eslint
安装
npm install eslint -D
初始化
npx eslint --init
vueUse 的应用
安装
npm i @vueuse/core
vueuse 官方文档(opens new window)
获取滚动距离
import { useScroll } from "@vueuse/core";
const { y } = useScroll(window);
监听元素进入视口
import { useIntersectionObserver } from "@vueuse/core";
// el:要监听的元素
// isIntersecting:元素是否进入视口 布尔值
// stop:停止监听方法
const { stop } = useIntersectionObserver(el, ([{ isIntersecting }]) => {
console.log("元素进入视口", isIntersecting);
if (isIntersecting) {
el.src = binding.value;
//图片加载完毕后停止监听
stop();
}
});
获取鼠标相对位置
import { useMouseInElement } from "@vueuse/core";
//el:相对的元素 默认为相对屏幕
//elementX 元素相对的左边left值
//elementY 元素相对的顶部top值
//isOutside 鼠标是否在元素外 布尔值
const { elementX, elementY, isOutside } = useMouseInElement(el);
Vue中的css
组件作用域 CSS
当 <style>
标签带有 scoped``attribute
的时候,它的 CSS
只会影响当前组件的元素,和 Shadow DOM
中的样式封装类似.
子组件的根元素
使用 scoped
后,父组件的样式将不会渗透到子组件中。不过,子组件的根节点会同时被父组件的作用域样式和子组件的作用域样式影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。
深度选择器
处于scoped
样式中的选择器如果想要做更“深度”的选择,也即:影响到子组件,可以使用 :deep()
这个伪类:
<style scoped>
.a :deep(.b) {
/* ... */
}
</style>
插槽选择器
默认情况下,作用域样式不会影响到 <slot/>
渲染出来的内容,因为它们被认为是父组件所持有并传递进来的。使用 :slotted
伪类以明确地将插槽内容作为选择器的目标:
<style scoped>
:slotted(div) {
color: red;
}
</style>
全局选择器
如果想让其中一个样式规则应用到全局,比起另外创建一个 <style>
,可以使用 :global
伪类来实现 (看下面的代码):
<style scoped>
:global(.red) {
color: red;
}
</style>
CSS Modules
一个 <style module>
标签会被编译为 CSS Modules
并且将生成的 CSS class
作为 $style
对象暴露给组件:
<template>
<p :class="$style.red">This should be red</p>
</template>
<style module>
.red {
color: red;
}
</style>
自定义注入名称
你可以通过给 module attribute 一个值来自定义注入 class 对象的属性名:
<template>
<p :class="classes.red">red</p>
</template>
<style module="classes">
.red {
color: red;
}
</style>
与组合式 API 一同使用(useCssModule
)
可以通过 useCssModule
API 在 setup()
和 <script setup>
中访问注入的 class
。对于使用了自定义注入名称的 <style module>
块,useCssModule
接收一个匹配的 module attribute
值作为第一个参数:
<script setup>
import {useCssModule} from 'vue'
// 在 setup() 作用域中...
// 默认情况下, 返回 <style module> 的 class
useCssModule()
// 具名情况下, 返回 <style module="classes"> 的 class
useCssModule('classes')
</script>
<style module></style>
<style module="classes"></style>
CSS 中的 v-bind()
单文件组件的 <style>
标签支持使用 v-bind
CSS 函数将 CSS 的值链接到动态的组件状态:
<script setup>
import {ref} from 'vue';
const theme = ref('red');
const colors = ['blue', 'yellow', 'red', 'green'];
setInterval(() => {
theme.value = colors[Math.floor(Math.random() * 4)];
}, 1000);
</script>
<template>
<p>hello</p>
</template>
<style scoped>
/* Modify the code to bind the dynamic color */
p {
color: v-bind(theme);
}
</style>
这个语法同样也适用于 <script setup>
,且支持 JavaScript
表达式 (需要用引号包裹起来):
<script setup>
const theme = {
color: 'red'
}
</script>
<template>
<p>hello</p>
</template>
<style scoped>
p {
color: v-bind('theme.color');
}
</style>
实际的值会被编译成哈希化的 CSS 自定义属性,因此 CSS 本身仍然是静态的。自定义属性会通过内联样式的方式应用到组件的根元素上,并且在源值变更的时候响应式地更新。
自定义指令封装
v-once 指令
只渲染一次元素和组件,并且跳过以后的更新。
在随后的重新渲染,元素/组件及其所有子项将被当作静态内容并跳过渲染。这可以用来优化更新时的性能。
<script setup>
import {ref} from "vue";
const count = ref(0);
setInterval(() => {
count.value++;
}, 1000);
</script>
<template>
<span v-once>使它从不更新: {
{ count }}</span>
</template>
使用自定义指令实现图片懒加载
自定义指令一般位于 main.js 中进行配置
//获取app实例
import {createApp} from "vue";
const app = createApp(App);
app.directive("img-lazy", {
//mounted 自定义指令绑定元素挂载完毕时触发
mounted(el, binding) {
//el 组件实例 自定义指令绑定的那个元素 img
//binding: 等于号指令表达式后面的值
console.log("自定义指令", el, binding.value);
// 使用vueuse提供的useIntersectionObserver方法判断当前绑定自定义指令的元素是否进入视口
useIntersectionObserver(el, ([{isIntersecting}]) => {
//isIntersecting 元素是否进入视口 布尔值
console.log("元素进入视口", isIntersecting);
//img标签在绑定src属性时会立即发送图片请求
if (isIntersecting) el.src = binding.value;
});
},
});
封装图片懒加载插件
在上述操作中,图片懒加载代码放在 main.js
入口函数中,而入口函数只是负责页面初始化,不因该包含太多逻辑代码
可以通过插件的方法把懒加载指令封装为插件,main.js
入口函数只需要负责注册插件即可
项目 src 文件夹下新建directives
插件文件夹 在此文件夹中存放插件
编写懒加载插件
//引入vueuse中监听元素进入视口的方法
import {useIntersectionObserver} from "@vueuse/core";
//定义懒加载插件
export const lazyPlugin = {
//install函数 固定写法 参数为app实例
install(app) {
//懒加载指令逻辑
//自定义指令
app.directive("img-lazy", {
mounted(el, binding) {
//el 组件实例 自定义指令绑定的那个元素 img
//binding: 等于号指令表达式后面的值
const {stop} = useIntersectionObserver(el, ([{isIntersecting}]) => {
console.log("元素进入视口", isIntersecting);
if (isIntersecting) {
el.src = binding.value;
//图片加载完毕后停止监听
stop();
}
});
},
});
},
};
在 main.js 中注册插件
//引入懒加载指令并注册
import {lazyPlugin} from "@/directives";
app.use(lazyPlugin);
自定义指令的使用
<img v-img-lazy="item.picture" />
监听元素宽高变化
//监听元素宽高变化
//创建元素数组
const map = new WeakMap()
//创建观察者
const ob = new ResizeObserver((entries) => {
for (const entry of entries) {
const handle = map.get(entry.target)
const box = entry.borderBoxSize[0]
if (handle) handle({width: box.inlineSize, height: box.blockSize})
}
})
export const resizePlugin = {
install(app) {
app.directive('resize', {
mounted(el, binding) {
//监听元素尺寸变化
ob.observe(el)
map.set(el, binding.value)
},
unmounted(el) {
ob.unobserve(el)
}
})
}
}
使用
<template>
<div v-resize='sizeChange'>监听元素尺寸变化</div>
</template>
<script lang="ts" setup>
//元素宽高变化的处理函数
const sizeChange = (value) => {
console.log('元素宽高变化', value)
}
</script>
组件
<RouterLink />
组件默认激活类名配置
<RouterLink />
组件默认支持激活样式显示的类名,只需要给active-class
属性设置对应的类名即可
<RouterLink active-class="active" :to="`/category/${item.id}`"></RouterLink>
组件的全局注册(插件方式)
//把computed中的组件都进行全局注册
//通过插件的方式
import ImageView from "@/components/ImageView/index.vue";
import XtxSku from "@/components/XtxSku/index.vue";
export const componentsPlugin = {
install(app) {
//
暂无评论内容