vue自定义指令使用~以仿写v-show和实现v-copy为例讲解
highlight: a11y-dark theme: simplicity-green
vue自定义指令产生的背景
- 我们知道前端程序员,写的各种代码,最终是要作用于页面上的DOM元素的。比如用HTML固定好DOM的基础结构,用CSS设置DOM的样式,用JS去做一些DOM的交互。因为DOM元素相当于“物理层”,要呈现给用户看的。DOM相当于积木一样,我们去操作这个积木,最终“搭建”成各式各样的效果出来。 > 所以一切花里胡哨的前端框架都是,基于前端三件套HTML、CSS、JS封装出来的
- 所以jQuery中就通过
$
符,直接操作DOM就挺方便的,方便是方便了,但是直接操作DOM会引起页面的回流重绘,又会略为有点浪费浏览器的性能,容易出现页面卡顿的情况,造成用户体验不太好。 > 万事皆有利弊,直接操作DOM,有时候,也可能,会是一个简单方便快捷的选择。 - 所以vue和react就闪亮登场了,用数据驱动的思想,并不是直接操作DOM,通过虚拟DOM做一个缓冲,虚拟DOM会搜集谁需要操作DOM,操作了DOM的哪些东西,统一先记录好,最终全部一块操作DOM。有点像js文档碎片的感觉。这样的话,浏览器性能就会优化提升不少。所以,vue中并不提倡直接操作DOM,因为有虚拟DOM在呢,你还直接操作真实DOM干啥啊。用vue指令啊 > 虚拟DOM确实是个好东西,给大佬点赞。我们知道vue提供的内置指令很方便,能解决大多数的DOM操作问题,但是,并不能解决所有的问题。
- 所以某些情况下,vue内置指令不能满足我们的需求,咋办呢。当然Vue创始人也想到了这个问题,所以,就搞了vue自定义指令,封装了一套钩子函数和对应参数的规则、以供我们使用去,从而更方便解决相应问题 > vue自定义指令就是直接操作DOM了,某些场景下,vue自定义指令是一个很好的选择
vue自定义指令的分类
vue自定义指令有两种
- 1. 全局自定义指令(需要全局注册)
- 2. 组件自定义指令(需要组件内部注册)
以下案例一是后者,案例二是前者
自定义指令其实就是一个对象,对象身上有一些钩子函数,自定义指令对象身上的钩子函数和vue组件的生命周期钩子函数类似,后续会通过案例阐述
一般使用全局自定义指令会多一些,毕竟复用方便
vue自定义指令使用讲解
案例一 el-input初始获取焦点(组件自定义指令 )
这个案例其实官网的案例,这里我们修改一下,更加便于我们理解之。
假设我们需要这样一个效果:页面加载完毕以后,el-input输入框自动获取焦点,类似打开百度一下页面以后,输入框自动获取焦点一样。
```js
```
演示的话,直接复制粘贴代码即可
案例二 仿写v-show功能(全局自定义指令)
效果图如下
看了效果图,功能其实和v-show没啥区别,举这样一个例子是方便更加好理解vue自定义指令
第一步,新建utils文件夹中存放index.js文件,此文件用于书写全局自定义指令
js
// 引入vue并使用vue的directive方法去注册一个自定义指令
import Vue from 'vue'
Vue.directive('showshow', { // 指令的名字叫做showshow
// bind函数一般用来做初始化数据,也可以绑定事件什么的
bind(el, binding, vnode) {
console.log(el, binding.value, vnode);
// el参数是当前使用指令的元素,bind参数是指令绑定的数据,vnode是虚拟dom
const flag = binding.value // 找到组件中绑定的标识
if (flag == false) {
el.style.display = 'none'
} else {
el.style.display = 'inline-block'
}
},
// inserted函数是在元素插入dom节点调用
inserted(el, binding, vnode) { },
// update和componentUpdated都是更新使用,但是前者更加常用些,oldVnode参数只有在这两个钩子中才会有
componentUpdated(el, binding, vnode, oldVnode) { },
update(el, binding, vnode, oldVnode) {
const flag = binding.value
if (flag == false) {
el.style.display = 'none'
} else {
el.style.display = 'inline-block'
}
},
// unbind解绑时候使用,比如用来移除第一个bind函数中绑定的事件
unbind(el, binding, vnode) { }
});
第二步,在main.js中引入这个书写全局自定义指令的文件(表示使用之)
```js import Vue from 'vue' import App from './App.vue' import router from "@/router/index.js" //引入路由表 import store from './store/index' // 引入vuex // ...
// 引入就可以使用全局自定义指令啦 ^_^ import './views/utils/index.js'
let vvvue = new Vue({ render: h => h(App), router, store // 挂载上去 }).$mount('#app') ```
第三步,在组件中使用全局自定义指令
```js
```
有的道友说,蛤?这不是多此一举嘛?其实不是,因为还没遇到特定的场景。上述两个例子主要是学习自定义指令的思想。接下来我们举一个小例子,点击文字一键复制功能。
案例三 实现v-copy自定义指令
效果图
点击就复制成功了,然后在电脑的相应位置就可以执行 Ctrl V 就可以直接粘贴这个点击的文本了
第一步,写自定义指令代码
```js import Vue from 'vue' Vue.directive('copy', { // 指令的名字叫做v-copy // bind函数初始化 bind(el, binding, vnode) { }, // inserted函数是在元素插入dom节点调用 inserted(el, binding, vnode) { // el参数是当前使用指令的元素,bind参数是指令绑定的数据,vnode是虚拟dom // 将copyFn函数挂在el身上方便使用 el.copyFn = () => { console.log('点击的是哪个DOM', el); //创建选中范围 var range = document.createRange();
// 选择点击的这个dom
range.selectNode(el);
//移除剪切板中内容,不添加这个语句的话,在ie和Edge中复制不到
window.getSelection().removeAllRanges();
//将el中的文字内容复制到剪切板
window.getSelection().addRange(range);
// 开启复制粘贴功能
let flag = document.execCommand('copy');
// 需注意兼容性问题
flag ? alert('复制成功,可以粘贴啦') : alert('当前浏览器不支持一键复制功能,请手动复制粘贴')
}
el.addEventListener('click', el.copyFn)
},
// update和componentUpdated都是更新使用,但是前者更加常用些
// oldVnode参数只有在这两个钩子中才会有,更新以后才会有更新前和更新后的DOM
componentUpdated(el, binding, vnode, oldVnode) {
console.log('componentUpdated');
},
update(el, binding, vnode, oldVnode) {
console.log('update');
},
// unbind解绑时候使用,比如用来移除第一个bind函数中绑定的事件
unbind(el, binding, vnode) {
el.removeEventListener('click', el.copyFn)
}
});
/* * 为了快速上手自定义指令钩子,我们可以这样简单理解。 * * bind和inserted钩子 --> 类似created和mounted钩子 * componentUpdated和update钩子 --> 类似updated钩子 * unbind钩子类似 --> destroyed钩子 * * 具体顺序大家可以拷贝代码运行以后打印看一下,这样更加方便精准理解 * / ```
第二步,在.vue文件中使用
```js
```
补充案例中知识
- Range对象:https://developer.mozilla.org/zh-CN/docs/Web/API/Document/createRange
- Selection对象:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/getSelection
- execCommand方法:https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand
关于MDN说,execCommand方法将来可能被删除的这个问题,思否上有一个回答挺好的,也顺带贴上:https://segmentfault.com/q/1010000022841994?utm_source=tag-newest
总结
在什么时候需要用自定义指令?
当内置指令不够用的时候,当需要做一些特殊的效果的时候,当需要对普通DOM元素进行底层操作的时候
自定义指令就是贴近原生js书写方式,我们合理使用其钩子函数以及相应参数,可以实现更加灵活的效果功能。毕竟vue虽然提供了很多的内置指令,方便我们直接使用,上手快,但是也是限制了程序员的一些发散思维。各有利弊,所以需要权衡 ^_^
- 什么?后端要一次性返回我10万条数据!且看我这8种方案机智应对!
- 性能优化之通俗易懂学习requestAnimationFrame和使用场景举例
- 23个css动画效果,持续更新中...
- elementui源码学习之仿写一个el-message
- 项目优化之使用compression-webpack-plugin插件开启gzip压缩,以vue为例
- 巧妙使用Vue.extend继承组件实现el-table双击可编辑(不使用v-if和v-else)
- 通俗易懂讲解并手写一个vue数据双向绑定案例
- vue中使用docx-preview插件预览word文档(后端express)
- react组件通信方式之~图解父子组件通信和兄弟组件通信pubsub-js
- 解决react警告:findDOMNode is deprecated in StrictMode. findDOMNode was passed an...
- vue自定义指令使用~以仿写v-show和实现v-copy为例讲解
- el-table表头文字换行的三种方式
- elementUI时间日期选择器更改小图标的位置和icon
- 两种方式解决页面刷新vuex中数据丢失问题(详细讲解)
- vue组件的递归自调用~代码思路分析
- el-tree树组件的懒加载写法步骤