目录
一、指令
二、Vue中的常用内置指令
1)v-show
2)v-if
3)v-if,v-else
4)v-if-else-if
5)v-for
6)v-on
7)v-html(解析html标签)
8)v-cloak和v-text(即使遇到标签,也原样输出)
9)v-once
10)v-pre
三、自定义指令
四、ref索引
一、指令
Vue中什么是指令?
在表现形式上,就是带有’v-'前缀的属性。v-属性名=‘具体表达式’。当表达式对应的值发生变化后,将响应式的作用于Dom,从而影响视图层。更为具体的说,指令结合属性作为暗号,框架会根据按照对应的不同的值来进行Dom操作的绑定。因此,帮我们在实际开发中做了减法。
二、Vue中的常用内置指令
1)v-show
元素的显示或隐藏时,都用v-show。
原理:只要new Vue()扫描到v-show,就会先计算=右边的判断条件的值,如果=右边的判断条件值为true,则当前元素默认正常显示,如果=右边的判断条件值为false,则v-show自动被翻译为style="display:none",表示当前元素隐藏。
<body>
<div id="app">
<button @click='show=false'>隐藏</button>
<button @click='show=true'>显示</button>
<button @click='show=!show'>切换</button>
<h1 v-show='show'>Hello Vue!</h1>
</div>
<script>
new Vue({
el: '#app',
data: { show: true },
})
</script>
</body>
2)v-if
专门控制两个元素二选一显示,当要在两个元素之间选择一个时,就用v-if和v-else。
原理:当new Vue()扫描到v-if时,先计算=右边条件变量或表达式的值,如果v-if等号右边的条件为true,则new Vue()会保留v-if所在元素,删除v-else所在元素;如果v-if等号右边条件为false,则new Vue()会先删除v-if所在的元素,保留v-else所在的元素。根据条件来加载元素。
<body>
<div id="app">
<button @click='add=false'>删除</button>
<button @click='add=true'>添加</button>
<!-- v-if指令:根据条件来加载元素 -->
<h1 v-if='add'>灰太狼来了!</h1>
</div>
<script>
new Vue({
el: '#app',
data: { add: true }
})
</script>
</body>
小结:Vue中隐藏元素的方式有哪些?他们有什么区别?分别有什么用途?(面试题)
1)Vue中 v-show 和 v-if 都能实现元素的隐藏操作;差异:
v-show:利用css的display='none'实现隐藏
v-if:利用 DOM 元素的移除,实现隐藏
3)用途:
v-show:适合频繁切换显示的场景
v-if:移除/增加 DOM,消耗高,会降低页面的性能,适合一次性使用的场景
eg:之后我们的数据都来源于网络,假设发送请求需要1s,则 在请求完毕前,先隐藏一部分页面,请求完成后再显示。
3)v-if,v-else
也是用来控制元素的显示与消失,需要注意的是:当使用了v-if=‘true’的元素显示时,则使用v-else的元素不会显示;当使用了v-if=‘false’的元素不显示时,则使用了v-else的元素会显示。
通过一个模拟请求数据的案例,来说明:
<body>
<div id="app">
<button @click='getData'>请求数据....</button>
<!-- skills是null,则页面显示加载中 -->
<div v-if='skills==null'>加载中...</div>
<!-- 否则 不显示 -->
<div v-else>
<h1>请求数据已到达...显示中....</h1>
<div>{{skills}}</div>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
skills: null
},
methods: {
getData() {
//模拟请求数据 需要1s
console.log('请求数据....');
setTimeout(() => {
console.log('数据请求完毕..');
this.skills = 'html-css-js'
}, 1000);
}
},
})
</script>
</body>
4)v-if-else-if
多个元素选择一个显示隐藏时,都用v-else-if。
<body>
<div id="app">
<!-- 怒气值>=100 显示 揍灰太狼!! -->
<!-- 怒气值>=70 显示 骂灰太狼! -->
<!-- 怒气值>=30 显示 抓羊! -->
<!-- 否则 显示 给灰太狼做饭! -->
<div>红太狼的怒气值:{{score}}</div>
<button @click='score-=10'>-10</button>
<button @click='score+=10'>+10</button>
<p v-if='score>=100'>揍灰太狼!!</p>
<p v-else-if='score>=70'>骂灰太狼!</p>
<p v-else-if='score>=30'>抓羊!</p>
<p v-else>给灰太狼做饭</p>
</div>
<script>
new Vue({
el: '#app',
data: {
score: 50
}
})
</script>
</body>
原理:当new Vue()扫描到v-if时,先计算v-if后的条件,如果v-if条件为true,则保留v-if所在元素,删除其余v-else-if、v-else元素;如果v-if条件为false,则先删除v-if所在元素,然后,继续计算每个v-else-if后的条件;如果任意一个v-else-if的条件为true,则只保留着一个v-else-if所在元素,删除其余v-if、v-else-if和v-else元素;如果所有v-if和v-else-if的条件都不满足,则只保留v-else,删除其余v-if和v-else-if的元素。
5)v-for
专门在网页中根据一个数组或对象的成员,连续生成多个结构相同,内容不同的一组html元素的特殊指令,只要连续生成一组结构相同,但是内容不同的HTML元素时,都用v-for批量生成。
<body>
<div id="app">
<!--在 v-for中 of和in效果相同,随意写 -->
<button v-for='value of names'>{{value}}</button>
<button v-for='a in names'>{{a}}</button>
</div>
<script>
new Vue({
el: '#app',
data: { names: ['喜羊羊', '懒羊羊', '沸羊羊', '慢羊羊', '美羊羊'] }
})
</script>
</body>
原理:每当new Vue()扫描到v-for时,先遍历数组或对象中每个成员;每遍历一个成员,取出当前成员的属性名和属性值,将属性值交给of前的()中第一个变量,将属性名/下标交给of前的()中第二个变量;同时会自动创建当前v-for所在元素的一个新副本,数组或对象包含几个成员v-for就会反复创建几个HTML元素副本。
<要反复生成的元素 v-for="(元素值, 下标) of 数组">
<要反复生成的元素 v-for="(属性值, 属性名) of 对象">
注意:
- v-for只需一个元素当模板
- v-for统一了js中的for in和for of的功能
- vue中的v-for既可以遍历索引数组,又可以遍历对象
- 在 v-for 中,下标和属性名可以省略不写,但是如果需要序号或者属性名时,可以加上
of前的两个变量,虽然没有在new Vue()的data中的定义,但可以在v-for所在元素及其子元素范围内用于绑定语法和指令。
下面是一个通过v-for向页面中遍历数组的案例:
<body>
<div id="app">
<!--在 v-for中 of和in效果相同,随意写 -->
<button v-for='value of names'>{{value}}</button>
<button v-for='a in names'>{{a}}</button>
</div>
<script>
new Vue({
el: '#app',
data: { names: ['喜羊羊', '懒羊羊', '沸羊羊', '慢羊羊', '美羊羊'] }
})
</script>
</body>
v-for本身也存在一些问题, 即使只修改了数组或对象中一个成员的值,v-for默认也会删除所有元素副本,重新遍历和创建创建HTML元素副本,这样效率极低。
这是因为v-for生成的多个HTML元素副本,除了内容不同之外,元素本身没有任何差别,所以v-for每次只能删除所有HTML副本,再重建整个列表。
解决:只要使用v-for都必须同时绑定一个专门的属性: :key="不重复的值"。
拥有key值之后,v-for就可以通过key属性值来鉴别每个HTML元素副本不同,修改时只要修改某一个key的元素即可,不用重建整个列表。
v-for为什么必须加 :key(面试题):
a.为每个元素添加唯一标识;
b.避免重建整个列表;
c.提高修改的效率。
拓展1:
遍历数字的语法(在 in/of 后面直接写一个数字,可以直接遍历并使用它)。
<button v-for='n in 5'>鲁班{{n}}号</button>
拓展2:如何解决v-for中:key的静态报错问题?
出现的原因:由于我们使用的VScode能够快捷生成v-for的基本结构,其中会自带 :key这个属性,但是如果你不写值,VScode会自动解析代码,它会认为你的代码是错误的,从而产生静态报错,但是不会影响程序的执行。
解决方法:
1)如果不需要使用 :key 这个属性,直接删掉这个属性就可以了,但是需要每次都删掉它,比较麻烦;
2)“设置”- > 搜索 vetur.validation.template 把勾选去掉(之后VScode就不因为 :key 的问题误报了)
6)v-on
v-on是Vue1中常用的绑定事件的指令,只要在vue中要给元素绑定事件处理函数,都用v-on,在Vue2中,直接用@代替。
<元素 v-on:事件名="事件处理函数(实参值,...)"
//简写:
//所有v-on,都可简写@:
<元素 @事件名="事件处理函数(实参值,...)"
//如果事件处理函数不需要传实参值,则可以省略()
<元素 @事件名="事件处理函数"
//传参: vue中事件处理函数,可以传实参值:
<元素 @事件名="事件处理函数(实参值1, 实参值2,...)"
methods:{
事件处理函数(形参1, 形参2, ...){
}
}
在vue中获得事件对象e:
<元素 @事件名="事件处理函数" //一定不要加()
methods:{
事件处理函数(e){ } //e指代event
}
如果既想传实参值,又想获得事件对象,就要借助于vue中的一个关键字$event,专门在vue中提前获得事件对象。
<元素 @事件名="事件处理函数($event, 其它实参, ...)"
methods:{
事件处理函数(e, 形参,...){
e->event //结果是一样的
}
}
在事件触发时,$event关键字会提前获得事件对象event,再由vue框架代为转交给事件处理函数对应的形参变量;只要使用$event关键字获得事件对象,则参数顺序无所谓,只要形参和实参可以对应即可。
7)v-html(解析html标签)
要绑定的内容是一段包含HTML内容的代码片段时,都用用v-html。
innerHTML,会先将HTML片段交给浏览器解析,将解析后文本显示到页面。
<元素 v-html="变量或表达式"></元素>
还要注意:v-html不能将写死的部分字符串和变化的变量轻易拼接,必须使用js中的模板字符串才能拼接。
<body>
<div id="app">
<h3>这本书是: {{msg}}</h3>
<h3 v-html="`这本书是:${msg}`"></h3>
</div>
<script>
new Vue({
el: "#app",
data: { msg: `这本书是<a href="#"><<喜羊羊与灰太狼>></a>` }
})
</script>
</body>
8)v-cloak和v-text(即使遇到标签,也原样输出)
当网速慢时,new Vue()有可能延迟加载,用户就有可能短暂看到页面上的{{ }}语法。这个时候就可以用到v-cloak和v-text:
(1)v-cloak
在new Vue()加载之前,暂时隐藏部分元素的特殊指令,如果希望在new Vue()加载完之前,暂时隐藏部分元素,避免用户短暂看到{{ }},都可以用v-cloak。
1、在css中用属性选择器,选择所有带有v-cloak属性的元素,使用display:none,手工隐藏这些元素
2、用法:<要暂时隐藏的元素 v-cloak>
原理:在new Vue()加载完之前,v-cloak和css中的属性选择器[v-cloak]联合发挥作用,隐藏部分元素,当new Vue()加载完之后,会自动查找页面中所有v-cloak的元素,自动删除所有v-cloak属性。
(2)v-text
专门代替{{ }}绑定元素内容的特殊指令,只要不想让用户短暂看到{{ }},都可用v-text代替{{ }}。
用法:<要隐藏的元素 v-text="变量或表达式"></要隐藏的元素>
注意如果v-text的内容由需要部分写死的文本和变化的内容拼接而成,必须用模板字符串 。
小结:对比v-cloak和v-text:
- 只需在父元素上添加v-cloak,就可以批量隐藏元素,
- 使用v-text时如果需要隐藏的元素过多则需重复使用;所以推荐使用v-cloak。
9)v-once
不会自动更新页面;如果一个元素的内容,只会在首次加载时绑定一次,之后几乎不会改变时,都用v-once标记。
<元素 v-once>{{...}}</元素>
原理:凡是标有v-once的元素,new Vue()只在首次挂载时,动态更新元素的内容,但不会将v-once的元素加入到虚拟DOM树中,所以将来就算变量值发生变化,也无法通知到这个元素。
不会加入虚拟DOM树中,所以减少了虚拟DOM树中的元素的个数,虚拟DOM树遍历更快,效率更高。
举个栗子:
<body>
<div id="app">
<!-- data中的数据在变更时会自动更新DOM -- 默认设定 -->
<button @click='num++'>{{num}}</button>
<!-- 特殊设定: 显示完毕后 不要随着数据变化 -- 一次性 -->
<p v-once>{{num}}</p>
</div>
<script>
new Vue({
el: '#app',
data: { num: 1 },
})
</script>
</body>
效果如下:
v-once 的标签,数据不会发生变化。
10)v-pre
不希望被vue编译的{{ }}时,采用v-pre保护。原样输出,包括{{}}。
举个栗子:
<body>
<div id="app">
<div v-pre>{{msg}}</div>
</div>
<script>
new Vue({
el: '#app',
data: { msg: 'Hello!' }
})
</script>
</body>
效果如下:
三、自定义指令
如果希望在开始时就能对HTML元素执行一些初始化DOM操作(如自动获得焦点),但是vue中没有提供对应功能的指令。这时就可以自定义指令。
创建自定义指令
1、directives属性:用来存储自定义指令
2、在使用自定义指令是,用 ”v-“ 开头
3、在创建自定义指令时,不用写 v-
4、在创建自定义指令时,有两个固定的参数:
(1)el:指的是指令所在的元素(能够用来快速找到元素)
(2)binding:与此指令绑定的相关值(传的值)
指令的本质:代替DOM的选择器,可以快速查找到元素,然后自动触发。
<body>
<div id="app">
<!---使用自定义属性-->
<div v-green>喜羊羊</div>
<!--- 指令的值是 JS代码,一定要加 引号 !!!-->
<div v-color="'red'">喜羊羊</div>
<!--- 页面刷新后输入框获取焦点 -->
<input v-focus type="text" />
</div>
<script>
new Vue({
el: '#app',
//创建自定义属性
directives: {
// 传一个参数
green(el) { el.style.color = 'green' },
// 传两个参数
color(el,binding) {
console.log(binding.value) //red
el.style.color = binding.value
},
// 因为在输入框获取焦点的时候,要在页面元素挂在完成后,再触发,所以涉及一个元素生命周期的问题
focus(el){
bind(el){
console.log('bind:在元素创建时触发')
},
inserted(el){
console.log('inserted:在元素挂载完之后触发')
el.focus()
}
},
},
})
</script>
</body>
注意:自定义指令写在HTML中,而HTML只认识小写字母,所以不能使用驼峰命名法,如果包含多个单词,可以用”-“隔开。
原理:Vue.directive()是创建一个自定义指令对象,保存在Vue类型的内存中备用。new Vue()扫描时,发现v-开头的自定义指令,就去Vue内存中找同名的自定义指令,找到同名的自定义指令,就自动执行自定义指令对象中的inserted()函数,并将当前扫描到的带有自定义指令的元素对象传给inserted()的形参变量;在inserted()函数内,可对当前传入的带有自定义指令的DOM元素应用原生的DOM操作。
自定义属性传值
为了便于我们使用,可以使用一个同样的自定义指令,通过改变属性值,来快速操作DOM元素。
<body>
<div id="app">
<!---注意:传递的属性值必须是 字符串,也就是说,必须是双层引号--->
<div v-color="'pink'">美羊羊</div>
<div v-color="'red'">美羊羊</div>
<div v-color="'black'">美羊羊</div>
</div>
<script>
new Vue({
el: '#app',
directives: {
color(el, binding) {
// el指令所在元素
// binding:与此指令绑定的相关值
el.style.color = binding.value
},
},
})
</script>
</body>
四、ref索引
ref:索引,代替DOM查找器,快速找到指定的DOM元素。
ref:是将dom元素绑定到Vue身上的refs上,里面包含了这个元素所有的属性,后期我们也能通过这中方式进行组件间的传参。
ref与自定义指令的差异:
自定义指令是 自动 触发的;ref是 手动 触发的。
自定义指令的方法需要专门写在 directives 中;ref的方法是需要写在 methods 中即可。
案例:通过点击按钮,输入框获取焦点
<body>
<div id="app">
<button @click='doFocus'>点我试试</button>
<br>
<!-- ref属性可以绑定一个变量到 当前元素上(变量名不能一样) -->
<input type="text" ref="inp" />
<br>
<input type="text" ref="inp2" />
</div>
<script src="../vue.js"></script>
<script>
new Vue({
el: '#app',
methods: {
doFocus() {
// 查看结果中的ref属性
console.log("获得焦点", this)
// 利用ref绑定的变量,存储在$refs属性中
this.$refs.inp.focus()
}
},
})
</script>
</body>