Vue指令
什么是Vue的指令?
指令是Vue框架提供的一种特殊的HTML属性,它们帮助我们在HTML中直接操作和控制Vue实例的数据和行为。
指令通过在HTML元素上添加特定的属性来实现,以"v-"开头,后跟指令名称。指令可以绑定到HTML元素、组件、模板或Vue实例上,从而实现不同的功能。
Vue指令有什么用?
指令的作用有以下几个方面:
-
数据绑定:最常见的用途是将Vue实例的数据与HTML元素进行绑定。通过指令,我们可以实现双向绑定,即当数据发生变化时,HTML元素会自动更新;反之,当用户在HTML元素上进行输入或操作时,相关的数据也会自动更新。
-
条件渲染:指令可以根据条件来控制HTML元素的显示与隐藏。例如,使用v-if指令可以根据条件决定是否渲染某个元素,使用v-show指令可以根据条件决定元素是否显示。
-
列表渲染:通过指令,我们可以轻松地遍历数组或对象,生成重复的HTML元素。v-for指令可以循环遍历数据,并根据每个元素生成相应的HTML结构。
-
事件处理:指令可以监听并响应HTML元素上的事件。通过v-on指令,我们可以在Vue实例中定义方法,并将这些方法绑定到特定的事件上,从而实现交互和逻辑控制。
-
样式和类绑定:指令可以帮助我们根据数据动态地改变HTML元素的样式或类。通过v-bind指令,我们可以将Vue实例的数据绑定到HTML元素的属性上,例如style和class,从而实现样式和类的动态改变。
Vue指令有哪些?
指令 | 作用 |
---|---|
v-bind | 单向绑定解析表达式,可简写为 :xxx (v-bind:xxx),数据只能从data流向页面 |
v-model | 双向数据绑定,数据不仅能从data流向页面,还可以从页面流向data |
v-for | 遍历对象、数组、字符串等 |
v-on | 绑定事件监听,可简写为 @xxx (v-on:click="") |
v-if、v-else-if、v-else | 条件渲染(动态控制节点是否存在) |
v-show | 条件渲染(动态控制节点是否展示) |
v-text | 向其所在的节点中渲染文本; |
v-html | 向指定节点中渲染包含 html结构 的内容。 |
v-cloak(没有值) | 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。 |
v-once | v-once所在节点在初次动态渲染后,就视为静态内容了 |
v-pre | 跳过其所在节点的编译过程 |
总结,Vue会根据不同的指令,针对标签实现不同的功能
v-html
v-html
用来更新元素的 innerHTML,但是存在一定的安全性。
使用方式:
<div id="app">
<div v-html="message"></div>
</div>
<script>
new Vue({
el: "#app",
data: {
message: "<h1>Hello, world!</h1>"
}
})
</script>
实现效果
课堂练习
<!--使用vue中的v-html指令把h2标签的“皓学IT”,替换成“a标签链接到百度”-->
<div id="app">
<h2 v-html="message">皓学IT</h2>
</div>
实现效果
数据绑定
v-bind
指令用于绑定属性(单向数据绑定)
v-model
指令为(双向数据绑定)
使用方式:
<div id="root">
单向数据绑定:<input type="text" v-bind:value="name"><br>
双向数据绑定:<input type="text" v-model:value="name">
</div>
<script>
Vue.config.productionTip = false
new Vue({
el:'#root',
data:{
name:'JoJo'
}
})
</script>
实现效果:
总结:
Vue中有2种数据绑定的方式:
单向绑定(v-bind):数据只能从data流向页面 双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data 备注:
双向绑定一般都应用在表单类元素上(如:<input>、<select>、<textarea>等) v-model:value可以简写为v-model,因为v-model默认收集的就是value值。(重点,后续还有内容)
v-if
v-if
是条件渲染指令,它根据表达式的真假来删除和插入元素,它的基本语法如下:v-if="expression"
expression 是一个返回bool值的表达式,表达式可以是一个bool属性,也可以是一个返回bool的运算式。
提示:v-if指令是根据条件表达式的值来执行元素的插入或者删除行为。
<div id="app">
<p v-if="yes">Hello, vue.js!</p>
<p v-if="no">Hey, girl!</p>
<p v-if="age > 18">Welcome!</p>
<p v-if="name.indexOf('Henry') >= 0">Hello, {{ name }}!</p>
</div>
let vm = new Vue({
el: "#app",
data: {
yes: true,
no: false,
age: 16,
name: "Henry Lee"
}
});
##
因为 v-if
是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 <template>
元素当做不可见的包裹元素,并在上面使用 v-if
。最终的渲染结果将不包含 <template>
元素。
<div id="#app">
<template v-if="isLogin">
<a href="#" class="name">木子李</a>
<a href="#">注销</a>
</template>
</div>
v-else
v-else
指令可以为 v-if
添加一个 else
模块:
<div id="#app">
<template v-if="isLogin">
<a href="#" class="name">木子李</a>
<a href="#">注销</a>
</template>
<template v-else>
<a href="#" class="go-login">登录</a>
<a href="#" class="go-register">注册</a>
</template>
</div>
v-else-if
<div id="app">
<p v-if="grade >= 90 && score <= 100">优秀</p>
<p v-else-if="grade >= 70 && score < 90">良好</p>
<p v-else-if="grade >= 60 && score < 70">及格</p>
<p v-else-if="grade >= 0 && score < 60">不及格</p>
<p v-else>成绩有误!</p>
</div>
new Vue({
el: '#app',
grade: {
score: 98
}
})
用 key 管理可复用元素
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:
<template v-if="isTel">
<span>手机:</span>
<input type="tel" placeholder="请输入手机号">
</template>
<template v-else>
<span>邮箱:</span>
<input type="email" placeholder="请输入邮箱">
</template>
<button type="button" @click="isTel = !isTel">切换登陆方式</button>
let vm = new Vue({
el: "#app",
data: {
isTel: true
}
});
那么在上面的代码中切换 loginType
将不会清除用户已经输入的内容。因为两个模板使用了相同的元素,<input>
不会被替换掉——仅仅是替换了它的 placeholder
。
自己动手试一试,点击上方查看demo,在输入框中输入一些文本,然后按下切换按钮:
这样也不总是符合实际需求,所以 Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key
属性即可:
<input type="tel" placeholder="请输入手机号" key="tel-input">
<input type="email" placeholder="请输入邮箱" key="email-input">
v-show
另一个用于根据条件展示元素的选项是 v-show
指令。用法大致一样:
<h1 v-show="ok">Hello!</h1>
不同的是带有 v-show
的元素始终会被渲染并保留在 DOM 中。v-show
只是简单地切换元素的 CSS 属性 display
。
注意:
v-show
不支持<template>
元素,也不支持v-else
。
v-if VS v-show
# | v-if | v-show |
---|---|---|
渲染 | 条件成立,才会渲染元素 | 不管条件是否成立,都会渲染元素 |
切换开销 | 重新渲染元素,开销更大 | 控制display属性,开销更小 |
使用场景 | 不频繁切换 | 频繁切换 |
v-on
vue 事件处理通过 v-on
指令实现,其语法形式为:
// 完整形式 -> v-on:事件类型="事件处理" -> <div v-on:click="alert('Hello!')"></div>
// 缩写形式 -> @事件类型="事件处理" -> <div @click="alert('Hello!')"><div>
事件处理器
<div id="app">
<template>
<!-- 通过内联脚本处理事件 -->
<button type="button" @click="alert('Hello')">click me</button>
<!-- 通过监听函数处理事件 -->
<button type="button" @click="handleBtnClick">click me</button>
</template>
</div>
new Vue({
el: "#app",
data: {},
methods: {
handleBtnClick(event) {
// event object
console.log(event);
// this -> vue
console.log(this);
}
},
})
事件修饰符
在事件处理程序中调用 event.preventDefault()
或 event.stopPropagation()
是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题,Vue.js 为 v-on
提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
-
.stop
* -
.prevent
* -
.capture
-
.self
-
.once
-
.passive
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面/阻止表单默认行为 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
提示:使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用
@click.prevent.self
会阻止所有的点击,而@click.self.prevent
只会阻止对元素自身的点击。
v-for
v-for 迭代数组
循环使用 v-for
指令
v-for 指令需要以 item in items 形式的特殊语法, items 是源数据数组并且 item 是数组元素迭代的别名。
<div id="app">
<ol>
<li v-for="(hero, index) in heros" :key="index">
<h3>{{ hero.name }}</h3>
</li>
</ol>
</div>
var app = new Vue({
el: '#app',
data: {
heros: [
{name:"张良"},
{name:"露娜"},
{name:"妲己"},
{name:"甄姬"},
{name:"虞姬"}
]
}
})
提示:在控制台输入
app.heros.push({name:"亚瑟"})
你将会发现页面上将添加一个列表项。
v-for 迭代对象
<div id="app">
<div v-for="value in hero">
<p>{{ value }}</p>
</div>
</div>
var app = new Vue({
el: '#app',
data: {
hero: {
// 英雄名
name: "露娜",
// 定位
position: "战士/法师",
// 特长
specialSkil: "突进/收割",
// 技能
skill:"月光之舞、玄月斩、炙热剑芒、新月突击"
}
}
})
你也可以提供第二个参数(key)以及第三个参数(index),修改html部分代码,如下所示:
<div id="app">
<div v-for="(value, key, index) in hero">
<p>{{ index }}. {{ key }} -> {{ value }} </p>
</div>
</div>
v-for 迭代整数
<div id="app">
<h3 v-for="idx in 5">{{ idx }}</h3>
</div>
var vm = new Vue({
el: '#app'
})
// 结果:1 2 3 4 5
数组更新检测
1、变异方法
会改变原始数组的方法被称为变异方法。Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新。这些方法如下:push()
、pop()
、shift()
、unshift()
、splice()
、sort()
、reverse()
。
2、非变异方法
不会改变原始数组的方法被称为非变异方法。例如:filter()
, concat()
和 slice()
。这些不会改变原始数组,但 总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组以达到数据响应。
3、注意事项
由于 JavaScript 的限制,Vue 不能检测以下变动的数组:
-
通过下标修改数据时
-
修改数组的长度时
解决第一类问题:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue);
vm.$set(vm.items, indexOfItem, newValue);
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue);
解决第二类问题:
vm.items.splice(newLength)
对象更改检测注意事项
还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除
let vm = new Vue({
data: { a: 1 }
}
// => "vm.a" 现在是响应式的
vm.b = 2
// => "vm.b" 不是响应式的
对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。但是,可以向嵌套对象添加响应式属性。
// 1
this.$set(this.user, "tel", "17398888669");
// 2
Vue.set(this.user, "job", "前端工程师");
// 3
this.user = Object.assign(this.user, {
name: "木子李",
tel: "17398888669",
job: "前端工程师"
});
// 4
this.user = {
...this.user,
address: "四川省成都市高新区"
};
显示过滤/排序结果
有时,我们想要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据。在这种情况下,可以创建返回过滤或排序数组的计算属性。
例如:
<li v-for="n in evenNumbers"> {{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
// 计算属性
computed: {
// 筛选偶数
eventNumbers() {
return this.numbers.filters((num) => {
return num % 2 === 0;
});
}
}
在计算属性不适用的情况下 (例如,在嵌套 v-for
循环中) 你可以使用一个 method 方法:
<li v-for="n in even(numbers)">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
event() {
return this.numbers.filter((num) => {
return num % 2 === 0;
});
}
}
提示:
如果是使用计算属性实现过滤,在调用计算属性方法时,无需加圆括号,
如果是使用方法实现过滤,在调用方法时,必须加圆括号。