vue 模板语法
插值
文本
数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:
<span>Message: {{ msg }}</span>
Mustache 标签将会被替代为对应数据对象上 msg
属性的值。无论何时,绑定的数据对象上 msg
属性发生了改变,插值处的内容都会更新。即便数据内容为一段 html 代码,仍然以文本内容展示
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue template</title>
<!--这里因为方便,我直接使用cdn方式引入-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="div">
文本插值 {{html_str}}
</div>
</body>
<script>
//只要引入vue框架,就会全局有个vue对象,这个对象是应用的根对象
var app = new Vue({
// 设置要操作的元素
el: '#div',
// 要替换的额数据
data: {
html_str:'<h2>Vue<h2>'
}
});
//打印vue实例
console.log(app);
</script>
</html>
浏览器渲染结果:文本插值 <h2>Vue<h2>
打开浏览器的 REPL 环境 输入 app.html_str = '<s>vue</s>'
,结果如下
使用 JavaScript 表达式
迄今为止,在我们的模板中,我们一直都只绑定简单的属性键值。但实际上,对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持,但是不能使用 JS 语句;
(表达式是运算,有结果;语句就是代码,可以没有结果)
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue template</title>
<!--这里因为方便,我直接使用cdn方式引入-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="div" >
{{ un > 3 ? '大' : '小'}}
{{ fun() }}
</div>
</body>
<script>
var app = new Vue({
el:'#div',
data: {
un: 2,
fun: function () {
return 1 + 2;
}
}
})
</script>
</html>
运行结果
指令
指令 (Directives) 是带有 v-
前缀的特殊特性。指令特性的值预期是单个 JavaScript 表达式 (v-for
是例外情况)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM;参考 手册 、 API
<body>
<div id="div" >
<p v-if="seen">现在你看到我了</p>
</div>
</body>
<script>
var app = new Vue({
el:'#div',
data:{
seen:true
}
})
</script>
这里,v-if
指令将根据表达式 seen
的值的真假来插入/移除 <p>
元素。
例:
正常显示
改为false
不显示
v-text / v-html 文本
https://cn.vuejs.org/v2/api/#v-text
https://cn.vuejs.org/v2/api/#v-html
错误代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue template</title>
<!--这里因为方便,我直接使用cdn方式引入-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<!--HTML 属性不能用 {{}} 语法-->
<div id="div" {{class}}>
<p v-text="seen"></p>
<p v-html="str_html"></p>
</div>
</body>
<script>
var app = new Vue({
el:'#div',
data:{
seen:'<h1>Vue</h1>',
str_html:'<h1>Vue</h1>',
class:'dd',
}
})
</script>
</html>
运行结果
去掉TML 属性用 {{}}的正确代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue template</title>
<!--这里因为方便,我直接使用cdn方式引入-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<!--HTML 属性不能用 {{}} 语法-->
<div id="div" >
<p v-text="seen"></p>
<p v-html="str_html"></p>
</div>
</body>
<script>
var app = new Vue({
el:'#div',
data:{
seen:'<h1>Vue</h1>',
str_html:'<h1>Vue</h1>',
class:'dd',
}
})
</script>
</html>
注意:
- v-text
- v-text和差值表达式的区别
- v-text 标签的指令更新整个标签中的内容(替换整个标签包括标签自身)
- 插值表达式,可以更新标签中局部的内容
- v-html
- 可以渲染内容中的HTML标签
- 尽量避免使用,否则会带来危险(XSS攻击 跨站脚本攻击)
HTML 属性不能用 {{}}
语法
v-bind 属性绑定(单向数据绑定)
https://cn.vuejs.org/v2/api/#v-bind
可以绑定标签上的任何属性。
动态绑定图片的路径
<img id=“app” v-bind:src="src" />
<script>
var vm = new Vue({
el: '#app',
data: {
src: '1.jpg'
}
});
</script>
绑定a标签上的动态id
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue template</title>
<!--这里因为方便,我直接使用cdn方式引入-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<a id="app" v-bind:href="'del.php?id=' + id">删除</a>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
id: 11
}
});
</script>
</html>
绑定class
对象语法和数组语法,也可以两种混用
-
对象语法
如果isActive为true,则返回的结果为
<div id="app" class="active"></div>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue template</title> <!--这里因为方便,我直接使用cdn方式引入--> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <!--v-bind class 绑定--> <div id="app" v-bind:class="{active: isActive,dangerClass: isDanger}"> 啊哈哈 </div> </body> <script> var vm = new Vue({ el: '#app', data: { isActive: true, isDanger: false } }); </script> </html>
可以看到为true的属性存在,为false 不存在
-
数组语法
渲染的结果:
<div id="app" class="active text-danger"></div>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue template</title> <!--这里因为方便,我直接使用cdn方式引入--> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <!--v-bind class 绑定--> <div id="app" v-bind:class="[activeClass, dangerClass]"> 啊哈哈 </div> </body> <script> var vm = new Vue({ el: '#app', data: { activeClass: 'active', dangerClass: 'text-danger' } }); </script> </html>
- 两种混用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue template</title>
<!--这里因为方便,我直接使用cdn方式引入-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<!--v-bind class 绑定-->
<div id="app" v-bind:class="[activeClass, {dangerClass : isDanger }]">
啊哈哈
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
activeClass: 'active',
isDanger: true
}
});
</script>
</html>
绑定style
对象语法和数组语法
-
对象语法
渲染的结果:
<div id="app" style="color: red; font-size: 40px;">hei</div>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue template</title> <!--这里因为方便,我直接使用cdn方式引入--> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <!--v-bind style 绑定--> <div id="app" v-bind:style="{color: redColor, fontSize: font + 'px'}"> 啊哈哈 </div> </body> <script> var vm = new Vue({ el: '#app', data: { redColor: 'red', font: 40 } }); </script> </html>
-
数组语法
渲染结果:
<div id="app" style="color: red; font-size: 18px;">abc</div>
简化语法
<div id="app">
<img v-bind:src="imageSrc">
<!-- 缩写 -->
<img :src="imageSrc">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
imageSrc: '1.jpg',
}
});
</script>
v-model 双向数据绑定
https://cn.vuejs.org/v2/api/#v-model
单向数据绑定
<div id="div">
<input type="text" :value="input_val">
</div>
<script>
var app = new Vue({
el: '#div',
data: {
input_val: 'hello world '
}
})
</script>
浏览器渲染结果: <div id="div"><input type="text" value="hello world"></div>
通过浏览器 REPL 环境可以进行修改 app.input_val = 'Vue'
浏览器渲染结果: <div id="div"><input type="text" value="Vue"></div>
我们通过 vue 对象修改数据可以直接影响到 DOM 元素,但是,如果直接修改 DOM 元素,却不会影响到 vue 对象的数据;我们把这种现象称为 单向数据绑定 ;
双向数据绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue template</title>
<!--这里因为方便,我直接使用cdn方式引入-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="div">
<!--v-model双向数据绑定-->
<input type="text" v-model="input_val">
</div>
</body>
<script>
var app = new Vue({
el: '#div',
data: {
input_val: 'hello world '
}
})
</script>
</html>
通过 v-model 指令展示表单数据,此时就完成了 双向数据绑定 ;
不管 DOM 元素还是 vue 对象,数据的改变都会影响到另一个;
限制
但是不是所有的标签都支持双向绑定的,目前只有这几种
第四种是组件,先不管
多行文本 / 文本域
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue template</title>
<!--这里因为方便,我直接使用cdn方式引入-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="div">
<!--v-model双向数据绑定-->
<textarea v-model="inp_val"></textarea>
<div>{{ inp_val }}</div>
</div>
</body>
<script>
var app = new Vue({
el: '#div',
data: {
inp_val: ''
}
})
</script>
</html>
可以看到下面这个div的值会同步改变
绑定复选框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue template</title>
<!--这里因为方便,我直接使用cdn方式引入-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="div">
吃饭:<input type="checkbox" value="eat" v-model="checklist"><br>
睡觉:<input type="checkbox" value="sleep" v-model="checklist"><br>
打豆豆:<input type="checkbox" value="ddd" v-model="checklist"><br>
{{ checklist }}
</div>
</body>
<script>
var vm = new Vue({
el: '#div',
data: {
//如果是'',就会选中一个其他都选中,值只有true 或 false,类似全选和全不选
//checklist: ''
//如果是[],就会选中那个数组就会有那个inpu 的 value 值
checklist: []
}
});
</script>
</html>
绑定单选框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue template</title>
<!--这里因为方便,我直接使用cdn方式引入-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
男<input type="radio" name="sex" value="男" v-model="sex">
女<input type="radio" name="sex" value="女" v-model="sex">
<br>
{{sex}}
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
sex: ''
}
});
</script>
</html>
修饰符
.lazy
- 取代 input
监听 change
事件,鼠标离开之后vue的data对象的值才更新
.number
- 输入字符串转为有效的数字
.trim
- 输入首尾空格过滤
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue template</title>
<!--这里因为方便,我直接使用cdn方式引入-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="div">
<input type="text" v-model.lazy="input_val">
{{input_val}}
</div>
</body>
<script>
var app = new Vue({
el: '#div',
data: {
input_val: 'hello world '
}
})
</script>
</html>
并且三个修饰符,可以进行链式调用
v-on 绑定事件监听
https://cn.vuejs.org/v2/api/#v-on
https://cn.vuejs.org/v2/guide/events.html
基本使用
<div id="app">
<input type="button" value="按钮" v-on:click="cli">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
cli:function(){
alert('123');
}
}
});
</script>
上面的代码运行是没有问题的,但是,不建议这样做,因为 data 是专门提供数据的对象,事件触发需要执行的是一段代码,需要的是一个方法 (事件处理程序) ;
修改代码如下:
<div id="app">
<!-- 使用事件绑定的简写形式 -->
<input type="button" value="按钮" @click="cli">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {},
// 将事件处理程序写入methods对象
methods: {
cli: function () {
alert('123');
}
}
});
</script>
向事件处理器中传参
<div id="app">
<!-- 直接调用传参即可 -->
<input type="button" value="按钮" @click="cli(1,3)">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {},
methods: {
// 接受参数
cli: function (a,b) {
alert(a+b);
}
}
});
</script>
而此时,如果在处理器中需要使用事件对象,则无法获取,我们可以用特殊变量 $event
把它传入方法
<input type="button" value="按钮" @click="cli(1,3,$event)">
methods: {
// 接受参数
cli: function (a,b,ev) {
alert(a+b);
console.log(ev);
}
}
事件修饰符
https://cn.vuejs.org/v2/guide/events.html
在事件处理程序中调用 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>
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self
会阻止所有的点击,而 v-on:click.self.prevent
只会阻止对元素自身的点击。
原生 JS 代码,想要阻止浏览器的默认行为(a标签跳转、submit提交),我们要使用事件对象的 preventDefault()
方法
<div id="app">
<a href="http://www.qq.com" id="a">腾百万</a>
</div>
<script>
document.getElementById('a').onclick = (ev)=>{
// 组织浏览器的默认行为
ev.preventDefault();
}
</script>
使用修饰符 阻止浏览器的默认行为
<div id="app">
<a href="http://www.qq.com" @click.prevent="cli">腾百万</a>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {},
// 将事件处理程序写入methods对象
methods: {
cli: function () {
alert('123');
}
}
});
</script>
使用修饰符绑定一次性事件
<div id="app">
<a href="http://www.qq.com" @click.once="cli($event)">腾百万</a>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {},
// 将事件处理程序写入methods对象
methods: {
cli: function (ev) {
ev.preventDefault();
alert('123');
}
}
});
</script>
按键修饰符
绑定键盘抬起事件,但是只有enter
键能触发此事件
<div id="app">
<input type="text" @keyup.enter="keyup">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {},
methods: {
keyup:()=>{
console.log('111')
}
}
});
</script>
系统修饰符
按住 shift
后才能触发点击事件
<div id="app">
<input type="button" value="按钮" @click.shift="cli">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {},
methods: {
cli:()=>{
console.log('111')
}
}
});
</script>
鼠标修饰符
鼠标中键触发事件
<div id="app">
<input type="button" value="按钮" @click.middle="cli">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {},
methods: {
cli:()=>{
console.log('111')
}
}
});
</script>
为什么在 HTML 中监听事件?
你可能注意到这种事件监听的方式违背了关注点分离 (separation of concern) 这个长期以来的优良传统。但不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。实际上,使用
v-on
有几个好处:
- 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
- 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
- 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。
v-show 显示隐藏
https://cn.vuejs.org/v2/api/#v-show
根据表达式之真假值,切换元素的 display
CSS 属性。
<div id="app">
<p v-show="is_show">Vue</p>
</div>
<script>
var vm = new Vue({
el:'#app',
data:{
is_show:false
},
methods:{},
})
</script>
案例:点击按钮切换隐藏显示
<div id="app">
<input type="button" value="按钮" @click="isshow">
<p v-show="is_show">Vue</p>
</div>
<script>
var vm = new Vue({
el:'#app',
data:{
is_show:false
},
methods:{
isshow:function(){
this.is_show = !this.is_show;
}
},
})
</script>
v-if / v-else / v-else-if 条件判断
https://cn.vuejs.org/v2/api/#v-if
根据表达式的值来有条件地渲染元素
<div id="app">
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
type: 'F'
},
})
</script>
v-for 循环
https://cn.vuejs.org/v2/api/#v-for
<div id="app">
<ul>
<li v-for="(val,key) in arr">{{val}}---{{key}}</li>
</ul>
<ul>
<li v-for="(val,key) in obj">{{val}}---{{key}}</li>
</ul>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
arr: ['a', 'b', 'c'],
obj: { id: 1, name: '李四' }
},
})
</script>
v-cloak
https://cn.vuejs.org/v2/api/#v-cloak
和 CSS 规则如 [v-cloak] { display: none }
一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。
模拟
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue template</title>
<!--这里因为方便,我直接使用cdn方式引入-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{obj.id}}</p>
</div>
</body>
<script>
setTimeout(() => {
var vm = new Vue({
el: '#app',
data: {
arr: ['a', 'b', 'c'],
obj: { id: 1, name: '李四' }
},
})
}, 2000);
</script>
</html>
当我们的网络受阻时,或者页面加载完毕而没有初始化得到 vue 实例时,DOM中的 {{}}
则会展示出来;
如:
为了防止现象,我们可以使用 CSS 配合 v-cloak 实现获取 VUE 实例前的隐藏;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue template</title>
<!--这里因为方便,我直接使用cdn方式引入-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<p v-cloak>{{obj.id}}</p>
</div>
</body>
<script>
setTimeout(() => {
var vm = new Vue({
el: '#app',
data: {
arr: ['a', 'b', 'c'],
obj: { id: 1, name: '李四' }
},
})
}, 2000);
</script>
</html>
v-once
https://cn.vuejs.org/v2/api/#v-once
只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过
<div id="app">
<p v-once>{{msg}}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg:'kkk'
},
})
</script>
可以看看这个小案例