前言
个人认为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>
//data
textValue: '这是一段常规文字',
效果
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>
//data
listValue: [
{
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>
//data
textValue: '这是一段常规文字',
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,
//methods
changeNumberVal() {
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>
//methods
clickFun() {
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>
//methods
clickFun() {
console.log('常规点击')
},
第一个按钮会先触发函数,再跳往至百度页面。
第二个按钮只会触发函数,不会跳转页面。
阻止事件冒泡
<span @click="clickSpanFun"><el-button @click="clickFun">节点嵌套事件冒泡</el-button></span>
<span @click="clickSpanFun"><el-button @click.stop="clickFun">阻止事件冒泡</el-button></span>
//methods
clickFun() {
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>
//data
name1: '属性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.btn1
console.log(btn1, 'element组件按钮')
console.log(btn1.$attrs['name1'], JSON.parse(btn1.$attrs['name2']), btn1.$attrs['name3'], '按钮的属性')
},
checkBtn2() {
let btn2 = this.$refs.btn2
console.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组件我没有写,随便定义一个就行,这些代码可以直接复制测试
感觉有用就给个赞吧!!!