前言
个人认为vue的指令,对比react来说,给开发者节省了很大的学习成本。比如在react中,你想渲染一个列表,需要用Array.map的方法return<div>,而在vue中,一个简单的v-for就解决了问题。
在学习成本和入手体验上,vue的作者确实后来者居上,能让人更快的使用vue开发。不过也是老生常谈的问题,各有特点,不做过多比较。
vue中的指令是用在标签上或者组件上,是ui层和数据层的交互介质。这个官方没有这么说,是我自己说的,比如你使用v-if,通过data去控制ui,使用v-model实现ui和data的双向交互。
我这里并不是指令的具体教程,只是一些demo的测试效果。
示例
这里我将指令分为三块
简单指令:学习简单,使用简单
复杂指令:可以在组件上使用,或者有修饰符等
自定义指令:自定义一些指令去实现某些业务功能
简单指令
v-text
用来回显常规字符串的
<h6>v-text使用</h6><p>使用v-text----<span v-text="textValue"></span></p><p>使用模板语法----<span>{{ textValue }}</span></p>//datatextValue: '这是一段常规文字',
效果
v-html
用来回显html的节点
<h6>v-html使用</h6>
<div v-html="htmlTemplate"></div>//data
htmlTemplate: `<div><input/><button>按钮</button></div>`
效果
v-show
用来控制元素的样式回显
<h6>v-show使用</h6>
<el-checkbox v-model="checkedValue">开关</el-checkbox>
<p v-show="checkedValue">开启</p>
<p v-show="!checkedValue">关闭</p>//data
checkedValue: true,
效果
v-if & v-else-if & v-else
用来控制元素的渲染
<h6>v-if && else-if && else的使用</h6>
<p>数字:{{ numValue }}</p>
<el-button @click="addNum">增加</el-button>
<el-button @click="deleteNum">减少</el-button>
<p v-if="numValue > 0">大于0</p>
<p v-else-if="numValue === 0">等于0</p>
<p v-else>小于0</p>//data
numValue: 0,//methods
addNum() {this.numValue++
},
deleteNum() {this.numValue--
},
v-for
渲染数组类型
<h6>v-for使用</h6><ul><li v-for="(item, index) in listValue" :key="item.value">{{ item.label }}</li></ul>//datalistValue: [{label: '文字1',value: 'one'},{label: '文字2',value: 'two'},{label: '文字3',value: 'three'}],
v-pre
跳过对js等变量的编译,渲染原始html
<h6>v-pre使用</h6><p v-pre>我是不需要编译的<span>{{ textValue }}</span></p>//datatextValue: '这是一段常规文字',
v-cloak
渲染完成之前的一种替代(网速慢优化策略)
<h6>v-cloak使用</h6><p v-cloak>{{ textValue }}</p>
v-once
元素只会渲染一次,更新不会重新渲染
<h6>v-once使用</h6><el-button @click="changeNumberVal">修改值</el-button><p v-once>不变的:{{ numberVal }}</p><p>变化的的:{{ numberVal }}</p>//data
numberVal: 100,//methodschangeNumberVal() {this.numberVal++},
复杂指令
v-on
用来处理事件的
简写和动态事件
<h6>v-on使用(简写为@)</h6>
<el-button v-on:click="clickFun">常规点击</el-button>
<el-button @click="clickFun">简写常规点击</el-button>
<el-button v-on:[eventName]="clickFun">动态事件</el-button>
<el-button @[eventName]="clickFun">动态事件简写</el-button>
<el-button @click.once="clickFun">只生效一次</el-button>//methodsclickFun() {console.log('常规点击')},
依次点击按钮,最后一个按钮点击只触发依次
阻止默认事件
<a href="http://www.baidu.com" @click="clickFun"><el-button>无限制跳转</el-button></a>
<a href="http://www.baidu.com" @click.prevent="clickFun"><el-button>阻止默认事件</el-button></a>//methodsclickFun() {console.log('常规点击')},
第一个按钮会先触发函数,再跳往至百度页面。
第二个按钮只会触发函数,不会跳转页面。
阻止事件冒泡
<span @click="clickSpanFun"><el-button @click="clickFun">节点嵌套事件冒泡</el-button></span>
<span @click="clickSpanFun"><el-button @click.stop="clickFun">阻止事件冒泡</el-button></span>//methodsclickFun() {console.log('常规点击')},clickSpanFun() {console.log('点击span标签')},
点击按钮1
点击按钮2
其他事件和点击组件的修饰符
<input v-model="inputValue" @keyup.enter="inputEventFun" type="text">
<el-input v-model="inputValue" @keyup.native.enter="inputEventFun"></el-input>
<Child @click.native="componentClick"></Child>
v-bind
动态渲染值
<h6>v-bind使用</h6>
<p v-bind:class="className">动态class</p>
<p :style="styleName">动态样式加简写</p>
<el-button :name1="name1" :name2="name2" name3="属性3" ref="btn1" @click="checkBtn1">查看element按钮组件的自定义属性</el-button>
<button :name1="name1" :name2="name2" name3="属性3" ref="btn2" @click="checkBtn2">查看原生dom的自定义属性</button>//dataname1: '属性1',name2: JSON.stringify({value: '属性3'}),
依次点击两个按钮
v-model
输入框类型数据视图双向绑定
<h6>v-model使用</h6>
<p>常规v-model<el-input v-model="InputVal"></el-input></p>
<p>lazy修饰符<input v-model.lazy="InputLazyVal" @input="inputLazyFun" /></p>
<p>number修饰符<el-input v-model.number="InputNumberVal"></el-input></p>
<p>trim修饰符<el-input v-model.trim="InputTrimVal"></el-input></p>
v-slot
插槽,这里不说了,看插槽相关的文档吧
自定义指令
语法
全局注册和局部注册
局部注册
局部注册就是在当前组件里面写
<template><div><h6>固定颜色指令</h6><p v-color>固定红色的指令效果</p></div>
</template><script>export default{data(){return{
}
},directives: {color: {// 指令的定义inserted: function (el) {el.style.color = 'red'}}},
}</script>
全局注册
创建一个js文件并在main.js中引入
import Vue from 'vue'Vue.directive('setColor',{//初始化钩子inserted:function(el,val,vnode){console.log(el,val,vnode,'???自定义函数')el.style.color = val.value || '#000'},//更新钩子update:function(el,val,vnode){console.log(el,val,vnode,'???自定义函数')el.style.color = val.value || '#000'},
})
引入后,任意组件内都可以使用
<h6>自定义颜色</h6>选择一个颜色吧:<el-color-picker v-model="colorValue"></el-color-picker><p v-setColor="colorValue">我是一段可选择颜色的字段</p>//data
colorValue:'#000'
定义一个可拖拽的指令
vue组件
<h6>可拖拽指令</h6>
<div class="dragBox"><div class="dragContent" v-draggable></div>
</div><style lang="less">.dragBox {position: relative;width: 800px;height: 200px;border: 1px solid #000;.dragContent {position: absolute;width: 50px;height: 50px;background: red;cursor: move;left: 10px;top: 10px;}
}
</style>
定义指令
Vue.directive('draggable',{inserted: function (el) {el.onmousedown = function (e) {var disx = e.pageX - el.offsetLeft;var disy = e.pageY - el.offsetTop;document.onmousemove = function (e) {el.style.left = e.pageX - disx + 'px';el.style.top = e.pageY - disy + 'px';}document.onmouseup = function () {document.onmousemove = document.onmouseup = null;}}},
})
自定义指令在实际的项目中还是很重要的,可以实现很多的业务场景。
比如我个人就用指令完成过水印效果,拖拽,按钮权限的控制等,学会自定义指令,也是多少需要复习一下很多人抛弃已久的dom基础知识。
全部代码
vue组件
<template><div class="box"><el-tabs v-model="activeName"><el-tab-pane label="简单指令(不需要修饰符)" name="first"><div class="content1"><h6>v-text使用</h6><p>使用v-text----<span v-text="textValue"></span></p><p>使用模板语法----<span>{{ textValue }}</span></p></div><div class="content1"><h6>v-html使用</h6><div v-html="htmlTemplate"></div></div><div class="content1"><h6>v-show使用</h6><el-checkbox v-model="checkedValue">开关</el-checkbox><p v-show="checkedValue">开启</p><p v-show="!checkedValue">关闭</p></div><div class="content1"><h6>v-if && else-if && else的使用</h6><p>数字:{{ numValue }}</p><el-button @click="addNum">增加</el-button><el-button @click="deleteNum">减少</el-button><p v-if="numValue > 0">大于0</p><p v-else-if="numValue === 0">等于0</p><p v-else>小于0</p></div><div class="content1"><h6>v-for使用</h6><ul><li v-for="(item, index) in listValue" :key="item.value">{{ item.label }}</li></ul></div><div class="content1"><h6>v-pre使用</h6><p v-pre>我是不需要编译的<span>{{ textValue }}</span></p></div><div class="content1"><h6>v-cloak使用</h6><p v-cloak>{{ textValue }}</p></div><div class="content1"><h6>v-once使用</h6><el-button @click="changeNumberVal">修改值</el-button><p v-once>不变的:{{ numberVal }}</p><p>变化的的:{{ numberVal }}</p></div></el-tab-pane><el-tab-pane label="复杂指令" name="second"><div class="content2"><h6>v-on使用(简写为@)</h6><el-button v-on:click="clickFun">常规点击</el-button><el-button @click="clickFun">简写常规点击</el-button><el-button v-on:[eventName]="clickFun">动态事件</el-button><el-button @[eventName]="clickFun">动态事件简写</el-button><el-button @click.once="clickFun">只生效一次</el-button><br><a href="http://www.baidu.com" @click="clickFun"><el-button>无限制跳转</el-button></a><a href="http://www.baidu.com" @click.prevent="clickFun"><el-button>阻止默认事件</el-button></a><br><p @click="clickPFun"><span @click="clickSpanFun"><el-button @click="clickFun">节点嵌套事件冒泡</el-button></span><span @click="clickSpanFun"><el-button @click.stop="clickFun">阻止事件冒泡</el-button></span></p><br><input v-model="inputValue" @keyup.enter="inputEventFun" type="text"><el-input v-model="inputValue" @keyup.native.enter="inputEventFun"></el-input><Child @click.native="componentClick"></Child><br><button v-on="{ mousedown: mousedownFun, mouseup: mouseUpFun }">对象语法</button></div><div class="content2"><h6>v-bind使用</h6><p v-bind:class="className">动态class</p><p :style="styleName">动态样式加简写</p><el-button :name1="name1" :name2="name2" name3="属性3" ref="btn1"@click="checkBtn1">查看element按钮组件的自定义属性</el-button><button :name1="name1" :name2="name2" name3="属性3" ref="btn2" @click="checkBtn2">查看原生dom的自定义属性</button></div><div class="content2"><h6>v-model使用</h6><p>常规v-model<el-input v-model="InputVal"></el-input></p><p>lazy修饰符<input v-model.lazy="InputLazyVal" @input="inputLazyFun" /></p><p>number修饰符<el-input v-model.number="InputNumberVal"></el-input></p><p>trim修饰符<el-input v-model.trim="InputTrimVal"></el-input></p></div><div class="content2"><h6>v-slot使用</h6>具体参考插槽吧,这里不做演示了</div></el-tab-pane><el-tab-pane label="自定义指令" name="third"><h6>固定颜色指令</h6><p v-color>固定红色的指令效果</p><hr><h6>自定义颜色</h6>选择一个颜色吧:<el-color-picker v-model="colorValue"></el-color-picker><p v-setColor="colorValue">我是一段可选择颜色的字段</p><hr><h6>可拖拽指令</h6><div class="dragBox"><div class="dragContent" v-draggable></div></div></el-tab-pane></el-tabs></div>
</template>
<script>
import Child from './child.vue'
export default {name: 'instructions',data() {return {activeName: 'first',textValue: '这是一段常规文字',htmlTemplate: `<div><input/><button>按钮</button></div>`,checkedValue: true,numValue: 0,numberVal: 100,inputValue: '输入框的值',listValue: [{label: '文字1',value: 'one'},{label: '文字2',value: 'two'},{label: '文字3',value: 'three'}],eventName: 'click',className: 'classP',styleName: {color: 'green'},name1: '属性1',name2: JSON.stringify({value: '属性3'}),InputVal: '常规输入框的值',InputLazyVal: 'lazy输入框的值',InputNumberVal: 1,InputTrimVal: '去空输入框的值',colorValue: '#000',}},directives: {color: {// 指令的定义inserted: function (el) {el.style.color = 'red'}}},components: {Child},methods: {addNum() {this.numValue++},deleteNum() {this.numValue--},changeNumberVal() {this.numberVal++},clickFun() {console.log('常规点击')},clickPFun() {console.log('点击p标签')},clickSpanFun() {console.log('点击span标签')},inputEventFun() {console.log(this.inputValue, '输入框的值')},componentClick(e) {console.log(e, '点击了组件')},mousedownFun() {console.log('鼠标按下')},mouseUpFun() {console.log('鼠标抬起')},checkBtn1() {let btn1 = this.$refs.btn1console.log(btn1, 'element组件按钮')console.log(btn1.$attrs['name1'], JSON.parse(btn1.$attrs['name2']), btn1.$attrs['name3'], '按钮的属性')},checkBtn2() {let btn2 = this.$refs.btn2console.log(btn2, 'btn的节点')console.log(btn2.getAttribute('name1'), JSON.parse(btn2.getAttribute('name2')), btn2.getAttribute('name3'), '按钮的属性')},inputLazyFun() {console.log(this.InputLazyVal, 'lazy值')},},
}
</script>
<style lang="less" scoped>
.box {padding: 14px;.content1 {float: left;width: 30%;height: 200px;margin: 10px;padding: 8px;box-shadow: 1px 1px 1px 1px #837e7e;h6 {font-size: 14px;font-weight: 600;}}.content2 {float: left;width: 40%;height: 350px;margin: 10px;padding: 8px;box-shadow: 1px 1px 1px 1px #837e7e;h6 {font-size: 14px;font-weight: 600;}}}[v-cloak] {display: none;
}.classP {color: red;
}.dragBox {position: relative;width: 800px;height: 200px;border: 1px solid #000;.dragContent {position: absolute;width: 50px;height: 50px;background: red;cursor: move;left: 10px;top: 10px;}
}
</style>
自定义指令文件
import Vue from 'vue'
import _ from 'lodash'
Vue.directive('setColor',{inserted:function(el,val,vnode){console.log(el,val,vnode,'???自定义函数')el.style.color = val.value || '#000'},update:function(el,val,vnode){console.log(el,val,vnode,'???自定义函数')el.style.color = val.value || '#000'},
})Vue.directive('draggable',{inserted: function (el) {el.onmousedown = function (e) {var disx = e.pageX - el.offsetLeft;var disy = e.pageY - el.offsetTop;document.onmousemove = function (e) {el.style.left = e.pageX - disx + 'px';el.style.top = e.pageY - disy + 'px';}document.onmouseup = function () {document.onmousemove = document.onmouseup = null;}}},
})
那个child组件我没有写,随便定义一个就行,这些代码可以直接复制测试
感觉有用就给个赞吧!!!