一、理解自定义指令
在 vue 中提供了一些对于页面和数据更为方便的输出,这些操作就叫做指令,以 v-xxx 表示,比如 html 页面中的属性 <div v-xxx ></div>。自定义指令很大程度提高了开发效率,提高了工程化水平,一定要认真学习。
二、vue2 有哪些内置指令
序号 | 指令 | 解释 |
1 | v-for | 基于源数据多次渲染元素或模板块。 |
2 | v-on | 绑定事件监听器。 |
3 | v-bind | 动态的绑定一个或多个attribute,或一个组件prop到表达式。 |
4 | v-model | 在表单控件或者组件上创建双向数据绑定。 |
5 | v-slot | 提供具名插槽或需要接收prop的插槽。 |
6 | v-pre | 跳过这个元素和它的子元素的编译过程。 |
7 | v-cloak | 这个指令保持在元素上直到关联实例结束编译。 |
8 | v-once | 只渲染元素或组件一次,随后的渲染会将组件/元素以及下面的子元素当成静态页面不再渲染。 |
9 | v-text | 更新元素的textContent |
10 | v-html | 更新元素的display属性 |
11 | v-if | 根据条件渲染元素 |
12 | v-else | 与v-if 或 v-else-if搭配使用 |
13 | v-else-if | 与 v-if 或 v-else 搭配使用,前一兄弟元素必须有 v-if 或 v-else-if。 |
三、vue2 指令修饰符
事件修饰符 | ||
序号 | 修饰符 | 解释 |
1 | .stop | 阻止事件冒泡,相当于调用 event.stopPropagation() |
2 | .prevent | 阻止默认事件的触发,相当于调用 event.preventDefault() |
3 | .capture | 使用事件捕获模式,从外部元素开始触发事件,然后再触发内部元素的事件 |
4 | .self | 只有当事件在绑定的元素本身触发时才触发事件,不会触发内部元素的事件 |
5 | .once | 指令只会触发一次,然后自动解绑。 |
6 | .passive | 指示监听器永远不会调用 event.preventDefault() ,可以提高性能。 |
7 | .native | 监听组件根元素的原生事件,而不是组件内部的子元素上的事件。 |
v-model修饰符 | ||
序号 | 修饰符 | 解释 |
1 | .trim | 自动去除输入内容的首尾空格 |
2 | .number | 将输入的 value 值转为数字类型 |
3 | .lazy | 将 input 事件改为 change 事件,减少输入事件的频率 |
按键修饰符 | ||
序号 | 修饰符 | 解释 |
1 | .enter | 监听键盘回车事件 |
其他修饰符 | ||
序号 | 修饰符 | 解释 |
1 | .camel | 用于将绑定的特性名字转回驼峰命名 <svg :view-box.camel="viewBox"></svg> 上面的代码等价于 <svg viewBox="..."></svg> |
2 | .sync | .sync 修饰符是一个特殊的修饰符,用于实现父子组件之间的双向数据绑定。 |
四、vue2自定义指令钩子
在 Vue 2 中,当你创建自定义指令时,你可以访问几个钩子函数,这些钩子函数允许你在不同的指令生命周期阶段执行代码。 | ||
序号 | 钩子 | 解释 |
1 | bind | 1、当指令第一次绑定到元素上时调用。此时,你可以执行一些初始化操作,比如设置初始值或添加事件监听器。 2、这个钩子函数接收三个参数: el (指令所绑定的元素)、binding (一个对象,包含指令的名称、值和其他属性)、vnode (Vue 编译生成的虚拟节点)。 |
2 | inserted | 1、当被绑定的元素插入到父节点中时调用。此时,元素已经存在于 DOM 中,你可以执行依赖于 DOM 的操作。 2、和 bind 钩子一样,它也接收 el 、binding 和 vnode 三个参数。 |
3 | update | 1、当指令的绑定值发生变化时调用,并且元素 DOM 也已经更新。 2、接收的参数和 bind 和 inserted 一样。 |
4 | componentUpdated | 1、当组件的 VNode 及其子 VNode 更新后调用,即组件的 DOM 已经更新。 2、这个钩子对于在更新之后的操作非常有用,比如基于新的 DOM 状态重新计算位置或大小。 |
5 | unbind | 1、当指令与元素解绑时调用,此时可以执行一些清理工作,比如移除事件监听器或清理计时器。 2、同样接收 el 、binding 、vnode 这些参数,但 vnode 参数在大多数情况下是 undefined。 |
五、Nuxt2使用自定义指令方法
5.1、全局自定义指令(方法一)
5.1.1、创建目录directives
创建文件directives/highlight.js
// eslint-disable-next-line import/no-extraneous-dependencies
import Vue from 'vue'
Vue.directive('highlight', {
// 当被绑定的元素插入到 DOM 中时
inserted (el, binding) {
// 获取指令的绑定值
const color = binding.value || 'yellow';
// 应用样式到元素
el.style.backgroundColor = color;
},
// 当绑定值更新时
update (el, binding) {
// 更新元素的背景颜色
el.style.backgroundColor = binding.value || 'yellow';
}
})
5.1.2、nuxt.config.js配置
nuxt.config.js文件中找到plugins
plugins: [
{
{ src: '../m-front-common/pc/directives/highlight', mode: 'client' },
}
]
5.1.3、页面使用
<template>
<div>
<p v-highlight="'red'">这段文字的背景色会被设置为红色。</p>
</div>
</template>
<script>
</script>
<style lang="less" scoped>
</style>
验证成功
5.2、全局自定义指令(方法二)
5.2.1、创建目录directives
5.2.2、创建文件directives/highlight.js
export default {
name: 'highlight',
install(Vue) {
Vue.directive('highlight', {
bind (el, binding) {
// 获取指令的绑定值
const color = binding.value || 'yellow';
// 应用样式到元素
el.style.backgroundColor = color;
},
// 当绑定值更新时
unbind (el, binding) {
// 更新元素的背景颜色
el.style.backgroundColor = binding.value || 'yellow';
}
})
}
}
5.2.3、创建文件directives/index.js
// eslint-disable-next-line import/no-extraneous-dependencies
import Vue from 'vue'
import highlight from './highlight'
Vue.use(highlight)
5.2.4、nuxt.config.js配置
nuxt.config.js文件中找到plugins
plugins: [
{
{ src: '../m-front-common/pc/directives/index'},
}
]
5.2.5、页面使用
<template>
<div>
<p v-highlight="'red'">这段文字的背景色会被设置为红色。</p>
</div>
</template>
<script>
</script>
<style lang="less" scoped>
</style>
5.3、局部自定义指令 / 页面自定义指令(方法三)
<template>
<div>
<div v-color="'red'">文字颜色</div>
</div>
</template>
<script>
export default {
directives: {
'color': {
bind: (el, binding) => {
el.style.color = binding.value || 'blue';
}
}
}
}
</script>
<style lang="less" scoped>
</style>
验证成功
六、Nuxt2使用自定义指令DEMO
6.1、v-focus
当输入表单时,可以使表单第一项自动获取焦点,减少一个操作步骤。
export default {
name: 'focus',
install(Vue) {
Vue.directive('focus', {
inserted (el) {
el.focus()
}
})
}
}
6.2、v-color
export default {
name: 'color',
install(Vue) {
Vue.directive('color', {
bind (el, binding) {
// 获取指令的绑定值
const color = binding.value || 'yellow';
// 应用样式到元素
el.style.color = color;
},
unbind (el, binding) {
el.style.color = binding.value || 'yellow';
}
})
}
}
6.3、v-copy
import { Message } from 'element-ui'
export default {
name: 'copy',
install(Vue) {
Vue.directive('copy', {
inserted(el) {
el.addEventListener('click', () => {
const textarea = document.createElement('textarea');
el.style.cursor = 'pointer';
textarea.value = el.innerText;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
Message.success("复制成功")
})
}
})
}
}
6.4、highlight
export default {
name: 'highlight',
install(Vue) {
Vue.directive('highlight', {
bind (el, binding) {
// 获取指令的绑定值
const color = binding.value || 'yellow';
// 应用样式到元素
el.style.backgroundColor = color;
},
// 当绑定值更新时
unbind (el, binding) {
// 更新元素的背景颜色
el.style.backgroundColor = binding.value || 'yellow';
}
})
}
}
6.5、lazyLoad
export default {
name: 'lazyLoad',
install(Vue) {
Vue.directive('lazyLoad', {
inserted (el) {
// 自动监听元素是否进入了设备的可视区域之内
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src
observer.unobserve(img)
}
})
})
observer.observe(el)
}
})
}
}
页面使用,验证成功
<img v-lazyLoad data-src="https://www.abc.com.cn/img/6376d08.png" style="height:50px;" />
6.6、dialogDrag
// Element-Dialog 弹窗可拖动
export default {
name: 'dialogDrag',
install(Vue) {
Vue.directive('dialogDrag', {
bind(el) {
const dialogHeaderEl = el.querySelector('.el-dialog__header');
const dragDom = el.querySelector('.el-dialog');
dialogHeaderEl.style.cursor = 'move';
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null);
dialogHeaderEl.onmousedown = e => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft;
const disY = e.clientY - dialogHeaderEl.offsetTop;
// 获取到的值带px 正则匹配替换
let styL;
let styT;
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (sty.left.includes('%')) {
styL = +document.body.clientWidth * (+sty.left.replace(/%/g, '') / 100);
styT = +document.body.clientHeight * (+sty.top.replace(/%/g, '') / 100);
} else {
styL = +sty.left.replace(/\px/g, '');
styT = +sty.top.replace(/\px/g, '');
}
// eslint-disable-next-line no-shadow
document.onmousemove = function(e) {
// 通过事件委托,计算移动的距离
const l = e.clientX - disX;
const t = e.clientY - disY;
// 移动当前元素
dragDom.style.left = `${l + styL}px`;
dragDom.style.top = `${t + styT}px`;
// 将此时的位置传出去
// binding.value({x:e.pageX,y:e.pageY})
};
document.onmouseup = function() {
document.onmousemove = null;
document.onmouseup = null;
};
};
}
})
}
}
七、推荐vue指令插件
7.1、vue-lazyload
npm install vue-lazyload