模板数据绑定渲染
模板数据绑定渲染可生成动态的 HTML 页面,页面中使用嵌入 Vue.js 语法可动态生成:
{{xxx}}双大括号文本绑定v-xxx以v-开头用于标签属性绑定,称为 指令
双大括号语法
- 格式:
{{表达式}} - 作用:
- 使用在标签体中,用于获取数据
- 可以使用
JavaScript表达式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>1. 双大括号输出文本内容</h3>
<!-- 文本内容 -->
<p>普通文本:{{message}}</p>
<!-- JS表达式 -->
<p>JS表达式:{{number + 1}}</p>
</div>
<script>
new Vue({
data() {
return {
message: 'Hello World',
number: 1
}
},
}).$mount('#app');
</script>
</body>
</html>
一次性插值
通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>一次性插值</h3>
<!-- Hello World -->
<p v-once>这个值不会改变:{{message}}</p>
<!-- Hello Vue! -->
<p >这个值会改变:{{message}}</p>
</div>
<script>
var vm = new Vue({
data() {
return {
message: 'Hello World',
}
},
}).$mount('#app');
vm.message = 'Hello Vue!';
</script>
</body>
</html>
输出 HTML 指令
- 格式:
v-html='xxx' - 作用:如果是
HTML格式数据,双大括号会将数据解释为普通文本,为了输出真正的HTML,需要使用v-html指令;Vue为了防止 XSS 攻击,在此指令上做了安全处理,当发现输出内容有script标签时,则不渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>v-html指令</h3>
<p>双大括号:{{message}}</p>
<p>v-html指令:<span v-html="message"></span></p>
</div>
<script>
var vm = new Vue({
data() {
return {
message: '<span style="color:red">红色字体内容<script>alert("hello vue")<\/script></span>',
}
},
}).$mount('#app');
</script>
</body>
</html>
XSS 攻击主要是利用
JS脚本注入到网页中,读取 Cookie 值(Cookie 一般存储了登录身份信息),读取到了发送到黑客服务器,从而黑客可以使用你的账户做非法操作。XSS 攻击还可以在你进入到支付时,跳转到钓鱼网站。
元素绑定指令
- 完整格式:
v-bind:元素的属性名='xxx' - 缩写格式:
:元素的属性名='xxx' - 作用:将数据动态绑定到指定的元素上
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>v-bind指令</h3>
<a :href="url">百度</a>
</div>
<script>
var vm = new Vue({
data() {
return {
url: "http://www.baidu.com/",
}
},
}).$mount('#app');
</script>
</body>
</html>
事件绑定指令
- 完整格式:
v-on:事件名称="事件处理函数名" - 缩写格式:
@事件名称="事件处理函数名"(@后面没有冒号) - 作用:用于监听 DOM 事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>v-on指令</h3>
<p>number:{{number}}</p>
<button @click="handleAdd()">+1</button>
</div>
<script>
new Vue({
data() {
return {
number: 1
}
},
methods: {
handleAdd () {
this.number++;
}
},
}).$mount('#app');
</script>
</body>
</html>
计算属性和监听器
计算属性
computed 选项用于定义计算属性,计算属性类似于 methods 中定义的函数,它们之间的不同是:
- 计算属性会进行缓存,只在相关响应式依赖发生改变时它们才会重新求值
- 函数每次都会执行函数体进行计算
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>计算属性和 methods 方法</h3>
数学分数:<input type="text" v-model="mathScore"> <br>
英语分数:<input type="text" v-model="englishScore"> <br>
总分(方法-单向):<input type="text" v-model="sum1()"> <br>
总分(计算属性-单向):<input type="text" v-model="sum2">
</div>
<script>
new Vue({
data() {
return {
mathScore: 100,
englishScore: 100
}
},
methods: {
sum1 () {
return (this.mathScore - 0) + (this.englishScore - 0);
}
},
computed: {
sum2 () {
return (this.mathScore - 0) + (this.englishScore - 0);
}
}
}).$mount('#app');
</script>
</body>
</html>
computed 选项内的计算属性默认是 getter 函数,所以上面只支持单向绑定,当修改数学和英语的数据才会更新总分,而修改总分不会更新数学和英语分数。不过在需要的时候,也可以提供一个 setter 方法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>计算属性和 methods 方法</h3>
数学分数:<input type="text" v-model="mathScore"> <br>
英语分数:<input type="text" v-model="englishScore"> <br>
总分(方法-单向):<input type="text" v-model="sum1()"> <br>
总分(计算属性-单向):<input type="text" v-model="sum2"> <br>
总分(计算属性-双向):<input type="text" v-model="sum3">
</div>
<script>
new Vue({
data() {
return {
mathScore: 100,
englishScore: 100
}
},
methods: {
sum1 () {
return (this.mathScore - 0) + (this.englishScore - 0);
}
},
computed: {
sum2 () {
return (this.mathScore - 0) + (this.englishScore - 0);
},
sum3 : {
get: function () {
return (this.mathScore - 0) + (this.englishScore - 0);
},
set: function (newValue) {
this.mathScore = newValue / 2;
this.englishScore = newValue / 2;
}
}
}
}).$mount('#app');
</script>
</body>
</html>
监听器
当属性数据发生变化时,对应属性的回调函数会自动调用,并在函数内部进行计算。通过 watch 选项或者 vm 实例的 $watch() 来监听指定的属性:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>计算属性和 methods 方法</h3>
数学分数:<input type="text" v-model="mathScore"> <br>
英语分数:<input type="text" v-model="englishScore"> <br>
总分:{{totalScore}}
</div>
<script>
let app = new Vue({
data() {
return {
mathScore: 100,
englishScore: 100,
totalScore: 200
}
},
watch: {
// 监听 mathScore 的变化
mathScore: function (newValue, oldValue) {
this.totalScore = (newValue - 0) + (this. englishScore - 0);
}
}
}).$mount('#app');
// 通过实例对象创建监听
app.$watch('englishScore', function(newValue, oldValue) {
this.totalScore = (newValue - 0) + (this.mathScore - 0);
});
</script>
</body>
</html>
当对象中的某个属性发生改变之后,默认情况下是不会被监听到的。如果希望修改对象属性后也能够被监听到,就需要使用深度监听:
watch: { items : { deep: true, handler : function(newItems, oldItems) { } } }
class 与 style 绑定
- class 绑定的语法格式:
v-bind:class='表达式'或:class='表达式',其中的表达式有以下几种:- 字符串:
:class='activeClass' - 对象:
:class='{active:isActive, error:hasError}' - 数组:
:class=['active', 'error'](需要加上单引号,否则是获取data中的值)
- 字符串:
- style 绑定的语法格式:
:style={color:activeColor, fontSize: fontSize+'px'},active和fontSize为data中的属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
<style>
.active {
color: green;
}
.delete {
background-color: red;
}
.error {
font-size: 30px;
}
</style>
</head>
<body>
<div id="app">
<h3>class 绑定的案例</h3>
<p :class="activeClass">字符串表达式</p>
<p :class="{delete: isDelete, error: hasError}">对象表达式</p>
<p :class="['error', 'delete']">数组表达式</p>
<h3>style 绑定的案例</h3>
<p :style="{color: activeColor, fontSize: fontSize + 'px'}">style 绑定方式</p>
</div>
<script>
let app = new Vue({
data() {
return {
activeClass: 'active',
isDelete: true,
hasError: false,
activeColor: 'red',
fontSize: 20
}
},
}).$mount('#app');
</script>
</body>
</html>
条件渲染
条件渲染涉及到的指令如下:
v-if:是否渲染当前元素,另外还提供了v-else、v-else-if指令,实现不同条件的渲染v-show:与v-if类似,只是元素始终被渲染并保留在 DOM 中,只是简单切换元素的 CSS 属性display来显示或隐藏
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
<style>
.box {
background-color: red;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<div id="app">
<h3>v-if实现</h3>
<input type="checkbox" v-model="seen">是否显示
<div class="box" v-if="seen"></div>
<p v-else="seen">红色框被隐藏</p>
<hr>
<h3>v-show实现</h3>
<div class="box" v-show="seen"></div>
<hr>
</div>
<script>
let app = new Vue({
data() {
return {
seen: true
}
},
}).$mount('#app');
</script>
</body>
</html>
v-if和v-show比较
- 什么时候元素被渲染
v-if:如果初始条件为假,则什么也不做;每当条件为真时,都会重新渲染条件元素v-show: 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于CSS进行切换- 使用场景选择
v-if有更高的切换开销
v-show有更高的初始渲染开销因此,如果需要非常频繁地切换,则使用
v-show较好;如果在运行后条件很少改变,则使用v-if较好。
列表渲染
迭代数组
可以使用 v-for 来迭代数组,其语法如下:v-for="(alias, index) in array":
alias:数组元素迭代的别名index:数组索引值,从 0 开始(可以省略)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>v-for迭代数组</h3>
<div v-for="(employee) in employees" :key="employee.id">
{{employee.id}}. 姓名:{{employee.name}}, 年龄:{{employee.age}}
</div>
</div>
<script>
let app = new Vue({
data() {
return {
employees: [
{id: 1, name: '张三', age: 12},
{id: 2, name: '李四', age: 22},
{id: 3, name: '王五', age: 32}
]
}
},
}).$mount('#app');
</script>
</body>
</html>
注意:
- 使用
key特殊属性, 它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素,一般指定的key值是id值。- 可以使用
of替代in关于数组更新检测
- 使用以下方法操作数组,可以检测变动:
push、pop、shift、unshift、sort、reverse- 使用以下方法需要用新数组替换旧数组:
filter、concat、slice、map- 不能检测以下变动的数组:
vm.items[indexOfItem] = newValue,可以通过下面的方法解决:
Vue.set(example1.items, indexOfItem, newValue)splice方法
迭代对象
可以使用 v-for 来迭代对象,其语法如下:v-for="(value, key, index) in object":
value:每个对象的属性值key:每个对象的属性名(可以省略)index:索引值(可以省略)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>v-for迭代对象</h3>
<p v-for="(value, key, index) in person" :key="index">{{key}} - {{value}}</p>
</div>
<script>
let app = new Vue({
data() {
return {
person: {
id: 1,
name: 'John',
age: 12
}
}
},
}).$mount('#app');
</script>
</body>
</html>
注意:
- 在遍历对象时,是按
Object.keys()的结果遍历,但不能保证它的结果在不同的JavaScript引擎下是顺序一致的- 可以使用
of替代in
事件处理
事件处理方法
- 完整格式:
v-on:事件名='函数名'或v-on:事件名=函数名(参数..) - 缩写格式:
@事件名='函数名'或@事件名=函数名(参数..)(@后面没有冒号) event:函数中的默认行参,代表原生DOM事件;当调用的函数有多个参数传入的时候,需要使用原生的DOM事件,可以通过$event作为实参传入- 作用:用于监听
DOM事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>事件处理</h3>
<button @click="errorInfo">Error</button>
<button @click="warnInfo('Hello', $event)">Warn</button>
</div>
<script>
let app = new Vue({
methods: {
errorInfo (event) {
alert(event.target.innerHTML);
},
warnInfo(msg, event) {
alert(msg + event.target.innerHTML);
}
},
}).$mount('#app');
</script>
</body>
</html>
事件修饰符
.stop阻止单击事件继续传播event.stopPropagation().prevent阻止事件默认行为event.preventDefault().once点击事件将只会触发一次.passive每次事件产生,浏览器都会去查询一下是否有preventDefault阻止该次事件的默认动作。我们加上passive就是为了告诉浏览器不用查询了,我们没用preventDefault阻止默认动作。这里一般用在滚动监听
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>事件修饰符</h3>
<!-- 下面的代码会阻止 a 标签的默认行为 -->
<a href="http://www.baidu.com" @click.prevent="info">百度</a>
</div>
<script>
let app = new Vue({
methods: {
info () {
alert("百度");
}
},
}).$mount('#app');
</script>
</body>
</html>
按键修饰符
- 格式:
v-on:keyup.按键名或@keyup.案件名 - 常用按键名:
.enter、.tab、.delete、.esc、.space、.up、.down、.left、.right - 可以使用按键的按键码:
@keyup.13
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>按键修饰符</h3>
<input type="text" @keyup.enter="info">
</div>
<script>
let app = new Vue({
methods: {
info: function () {
alert("回车键");
},
},
}).$mount('#app');
</script>
</body>
</html>
表单数据双向绑定
双向绑定是指数据变的时候视图也相应改变;同时视图变的时候,数据也跟着改变。v-model 指令用于表单数据的双向绑定,主要针对以下类型:text(文本)、textarea(多行文本)、radio(单选按钮)、checkbox(复选框)、select(下拉框):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>text文本</h3>
<input type="text" v-model="textModel">
<p>text的当前文本:{{textModel}}</p>
<h3>多行文本</h3>
<textArea v-model="textAreaModel"></textArea>
<p>多行文本的当前内容:{{textAreaModel}}</p>
<h3>radio</h3>
<input type="radio" v-model="gender" value="male">:男
<input type="radio" v-model="gender" value="female">:女
<p>radio当前选择了:{{gender}}</p>
<h3>checkbox</h3>
<!-- 单个checkbox 可以绑定 boolean 对象 -->
<input type="checkbox" v-model="isAll"> 全选 <br>
<p>是否全选:{{isAll}}</p>
<!-- 多个的时候可以绑定数组 -->
<input type="checkbox" v-model="hab" value="football"> 足球
<input type="checkbox" v-model="hab" value="basketball"> 篮球
<p>checkbox选择了:{{hab}}</p>
<h3>select</h3>
<select v-model="person">
<option v-for="(person) in persons" :value="person">{{person.name}}</option>
</select>
<p>选择了:{{person}}</p>
</div>
<script>
let app = new Vue({
data() {
return {
textModel: "Hello world",
textAreaModel: "Hello Vue",
gender: 'male',
isAll: false,
hab:[],
persons : [
{id: '1', name: 'John'},
{id: '2', name: 'Jack'}
],
person: {}
}
},
}).$mount('#app');
</script>
</body>
</html>
常用表单控件修饰符
.lazy失去焦点同步一次.number格式化数字.trim去除首尾空格