模板语法
选项中主要影响模板或DOM的选项有el和template,属性replace和template需要一起使用。 el:类型为字符串,DOM元素或函数。其作用是为实例提供挂载元素。一般来说我们会使用css选择符,或者原生的DOM元素。例如el:’#app’。在初始项中指定了el,实例将立即进入编译过程。
template:类型为字符串。默认会将template值替换挂载元素(即el值对应的元素),并合并挂载元素和模板根节点的属性(如果属性具有唯一性,类似id,则以模板根节点为准)。如果replace为false,模板template的值将插入挂载元素内。通过template插入模板的时候,挂载元素的内容都将被互联,除非使用slot进行分发。在使用template时,我们往往不会把所有的HTML字符串之间写在js里面,这样影响可读性也不利于维护所以经常用’#tpl’的方式赋值,并且在body内容添加为标签包含的HTML内容,这样就能将HTML从js中分离开来,示例如下:
<div id="app">
<p>123</p>
</div>
<script id="tpl" type="x-template">
<div class='tpl'>
<p>This is a tpl from script tag</p>
</div>
</script>
<script type="text/javascript">
var vm = new Vue({
el : '#app',
template : '#tpl'
});
</script>
最终输出HTML结构为:
<div class='tpl'>
<p>This is a tpl from script tag</p>
</div>
浏览器显示This is a tpl from script tag
数据
Vue.js实例中可以通过data属性定义数据,这些数据可以在实例对应的模板中进行绑定并使用。需要注意的是,如果传入data的是一个对象,Vue实例会代理起data对象里的所有属性,而不会对传入的对象进行深拷贝。另外,我们也可以引用Vue实例vm中的$data来获取声明的数据,例如:
var data = { a: 1 }
var vm = new Vue({
data: data
})
vm.$data === data // -> true
vm.a === data.a // -> true
// 设置属性也会影响到原始数据
vm.a = 2
data.a // -> 2
// 反之亦然
data.a = 3
vm.a // -> 3
然后在模板中使用{{a}}就会输出vm.a的值,并且修改vm.a的值,模板中的值会随之改变,我们也会称这个数据为响应式(responsive)数据。 需要注意的是,只有初始化时传入的对象才是响应式的,即在声明完实例后,再加上一句vm.$data.b = ‘2’,并在模板中使用{{b}},这时是不会输出字符串’2’的。例如:
<div id="app">
<p>{{a}}</p>
<p>{{b}}</p>
</div>
var vm = new Vue({
el : '#app',
data : {
a:1
}});
vm.$data.b = 2;
如果需要在实例化之后加入响应式变量,需要调用实例方法$set, 例如: vm.$set(‘b’, 2); 不过Vue.js并不推荐这么做,这样会抛出一个异常: 所以,我们应尽量在初始化的时候,把所有的变量都设定好,如果没有值,也可以用undefined或null占位。 另外,组件类型的实例可以通过props获取数据,同data一样,也需要在初始化时预设好。
示例:
<my-component title='myTitle' content='myContent'></my-component>
var myComponent = Vue.component('my-component', {
props : ['title', 'content'],
template : '<h1>{{title}}</h1><p>{{content}}</p>'
})
数据绑定语法
文本插值
1.文本插值 数据绑定最基础的形式就是文本插值,使用的是双大括号标签{{}},为“Mustache”语法(源自前端模板引擎Mustache.js),示例如下: <span>Hello {{ name }}</span> // -> Hello Vue Vue.js
实例vm中name属性的值将会替换Mustache标签中的name,并且修改数据对象中的name属性,DOM也会随之更新。在浏览器console中运行 vm.name = ‘Vue 1.0’, 输出结果为Hello Vue 1.0。 模板语法同时也支持单次插值,即首次赋值后再更改vm实例属性值不会引起DOM变化, 例如以下模板在运行vm.name = 'Vue 1.0’后,依旧会输出Hello Vue:
<span>Hello {{* name }} </span> // -> Hello Vue
Vue.js 2.0去除了{{*}}这种写采用v-once代替。以上模板需要改写为
<span v- once=”name”>{{name}}</span>。
指令语法
Vue.js提供指令(Directives)这一概念,可以理解为当表达式的值发生改变时,会有些特殊行为作用到绑定的DOM上。指令通常会直接书写在模板的HTML元素中,而为了有别于普通的属性Vue.js指令是带有前缀的v-的属性。写法上来说,指令的值限定为绑定表达式,所以上述提到的 JavaScript 表达式及过滤器规则在这里也适用。
① 参数
<img v-bind:src="avatar" />
指令v-bind可以在后面带一个参数,用冒号(:)隔开,src即为参数。此时img标签中的src会与vm实例中的avatar绑定,等同于: <img src="{{avatar}}" />
② 修饰符 修饰符(Modifiers)是以半角句号.开始的特殊后缀,用于表示指令应该以特殊方式绑定。 <button v-on:click.stop="doClick"></button>
v-on的作用是在对应的DOM元素上绑定事件监听器,doClick为函数名,而stop即为修饰符,作用是停止冒泡,相当于调用了e. stopPropagation()。
1.v-model的使用
我们可以使用v-model为可输入元素(input & textarea)创建双向数据绑定,它会根据元素类型自动选取正确的方法来更新元素。先演示单行文本框、多行文本框、单选框和复选框的绑定方法,代码如下:
<div id="app">
<h3>单行文本框</h3>
<input type="text" v-model="singleText" style="width: 240px;">
<p>{{ singleText }}</p >
<h3>多行文本框</h3>
<textarea v-model="multiText" style="width: 240px;"></textarea>
<pre>{{ multiText }}</pre>
<h3>单选框</h3>
<!--
由于点击被选中的单选项无法取消其被选中状态,所以实战中一般没有使用单个单选项的场景。
这里,设置v-model共用同一个变量(radioValue)可实现RadioGroup的效果
-->
<input id="ra" type="radio" value="杨玉环" v-model="radioValue">
<label for="ra">A.杨玉环</label>
<input id="rb" type="radio" value="赵飞燕" v-model="radioValue">
<label for="rb">B.赵飞燕</label>
<p>{{ radioValue }}</p >
<h3>单个复选框</h3>
<!-- 单个复选框被用于true和false的切换 -->
<input id="c" type="checkbox" v-model="toggleValue">
<label for="c">天生丽质</label>
<p>{{ toggleValue }}</p >
<h3>多个复选框</h3>
<!-- 多个复选框,v-model接收数组类型变量 -->
<input id="ca" type="checkbox" value="漂亮" v-model="checkedValues">
<label for="ca">A.回眸一笑百媚生</label>
<input id="cb" type="checkbox" value="瘦弱" v-model="checkedValues">
<label for="cb">B.体轻能为掌上舞</label>
<input id="cc" type="checkbox" value="得宠" v-model="checkedValues">
<label for="cc">C.三千宠爱在一身</label>
<p>{{ checkedValues.join(',') }}</p >
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.
js"></script>
<script type="text/javascript">
let vm = new Vue({
el: '#app',
data () {
return {
singleText: '',
multiText: '',
radioValue: '',
toggleValue: false,
checkedValues: []
}
}
})
</script>
效果:
此外,下拉选择框也可以使用v-model进行双向数据绑定,代码:
<body>
<div id="app">
<h3>单项下拉选择框</h3>
<select v-model="singleSelect">
<!-- 如果没有设置value, 则option节点的文本值会被当作value值 -->
<option value="汉代">汉代</option>
<option>唐代</option>
</select>
<p>{{ singleSelect }}</p >
<h3>多项下拉选择框</h3>
<select multiple v-model="multiSelect">
<!-- 按住ctrl键,可执行多选 -->
<option value=1>出身寒微</option>
<option value=2>饱受争议</option>
<option :value="3">结局悲凉</option>
</select>
<p>{{ multiSelect.join(',') }}</p >
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script type="text/javascript">
let vm = new Vue({
el: '#app',
data () {
return {
singleSelect: '唐代', // 根据value设置默认选择项
multiSelect: [1, 3]
}
}
})
</script>
</body>
效果L:
画圈的为绑定的部分
这里,笔者将select下拉选择框拎出来单独讲述,并不是因为它具有何种妙用,而是因为它的视图表现太差,而当下的规范尚不允许开发者自定义option的样式,所以在实战中一般都会使用其他元素来模拟下拉选择框,它存在的意义只是为我们定
义组件时提供一个参照物。
2 .v-model与修饰符
在使用v-model时,我们还可以为其后缀一些修饰符以丰富用户输入时的行为,Vue内置的修饰符如表。
下面来看一个简单示例,代码如下:
<input type=“text” v-model.trim.number=“text” @keyup=“handleKeyUp”>
为v-model绑定了trim和number修饰符,并在输入时打印出输入值及其类型(输入值原始类型为String),运行结果如图:
3. 条件渲染和列表渲染
程序中有三大结构:顺序结构、分支结构、循环机构。顺序结构不必多说,分支和循环结构则分别由条件判断语句和循环语句实现。同样地,Vue也为视图渲染提供了条件判断和循环的机制,简称为条件渲染和列表渲染。
3.1 指令v-if和v-show
v-if的使用方法并不复杂,只需要为元素挂上v-if指令即可,与之配套的还有v-else-if和v-else,不过它们只能与v-if配合使用。下面来看一个简单示例,代码如下:
<div id="app">
<h2 v-if="order === 0">站在前排的 v-if</h2>
<h2 v-else-if="order === 1">不上不下的 v-else-if</h2>
<h2 v-else>负责垫后的 v-else</h2>
<button @click="toggleTitle">切换标题</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.
js"></script>
<script type="text/javascript">
let vm = new Vue({
el: '#app',
data () {
return {
order: 0
}
},
methods: {
toggleTitle () {
this.order = ++this.order % 3
console.log('order的值为:', this.order)
}
}
})
</script>
在这个示例中,设置了多个h2元素,当order值被修改时,视图将渲染满足条件的元素,运行结果如图所示。
点击切换标题:
本例中的order只会在012三者之中切换
v-show
v-show也可以用于实现条件渲染,不过它只是简单地切换元素的CSS属性:display。当条件判定为假时,元素的display属性将被赋值为none;反之,元素的display属性将被恢复为原有值。 相对于v-if来说,v-show并不能算作真正的条件渲染,因为挂载它的多个元素之间并没有条件上下文关系,我们可以从下面的一段代码中体会一下:
<div id="app">
<h2 v-show="visible">v-show, visible = true</h2>
<h2 v-show="!visible">v-show, visible = false</h2>
<h2 v-if="visible">v-if, visible = true</h2>
<h2 v-else>v-if, visible = false</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.
js"></script>
<script type="text/javascript">
let vm = new Vue({
el: '#app',
data () {
return {
visible: false
}
}
})
</script>
从图中可以看到,v-show判定为假的元素的display属性被赋值为none,不过仍保留在DOM中,而v-if判定为假的元素则根本没有在DOM中出现。 最后,笔者罗列了以下几个注意点。
●v-if会在切换中将组件上的事件监听器和子组件销毁和重建。当组件被销毁时,它将无法被任何方式获取,因为它已不存在于DOM中。
●在创建父组件时,如果子组件的v-if被判定为假,Vue不会对子组件做任何事情,直到第一次判定为真时。这在使用Vue生命周期钩子函数时要尤为注意,如果生命周期已走过组件创建的阶段,却仍无法获取组件对象,想一想,是不是v-if在作怪。
●v-show有更高的初始渲染开销,而v-if有更高的切换开销,这与它们的实现机制有关,在使用时要多加考虑具体的应用场景。
●v-show不支持template元素,不过在Vue 2.0中,template的应用并不广泛,了解即可。
v-if和v-show的组件化实例
<template>
<div>
<button @click="isshow = !isshow" >显示/隐藏</button>
<div v-if="isshow">
{{msg}}
</div>
</div>
</template>
<script>
export default {
name: 'app',
data(){
return {
msg: 'test',
isshow: true,
num: 0
}
},
}
</script>
<style>
#app {
color: blue;
}
#box1{
width: 150px;
height: 150px;
background: #FFA722;
}
#box2{
width: 40px;
height: 40px;
background: coral;
}
</style>
按键显示或者隐藏以后test会显示或者隐藏
用v-show:将样式隐藏了,但是元素还在。
v-if和v-show
v-if是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-show就简单得多—不管初始条件是什么元素总是会被渲染,并且只是简单地基于CSS进行切换
4.1 指令v-for
v-for用于实现列表渲染,可以使用item in items或者item of items的语法,代码如下:
<!DOCTYPE html>
<html>
<head>
<title>Auto-fill Form Fields</title>
<style type="text/css">
body {
font: 1.2em arial, helvetica, sans-serif;
margin-top: 50px;
margin-left:500px;
color: aqua;
}
</style>
</head>
<body>
<div id="app">
<div style=" float: left; width: 160px;">
<h2>用户列表</h2>
<ul>
<!-- index作为第二个参数,用以标识下标 -->
<li v-for="(item, index) in users">{{ index }}. {{ item.name}}</li>
</ul>
</div>
<div style="margin-left: 170px;overflow: hidden"> <!-- BFC -->
<h2>用户列表</h2>
<ul>
<!-- uIndex作为第二个参数,用以标识下标 -->
<li v-for="(user, uIndex) of users">{{ uIndex }}. {{ user.city }} {{ user.age }}</li>
</ul>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script type="text/javascript">
let vm = new Vue({
el: '#app',
data () {
return {
users: [
{
name: 'Clark',
age: 27,
city: 'Chicago'
},
{
name: 'Jackson',
age: 28,
city: 'Sydney'
}
]
}
}
})
</script>
</body>
</html>
除了渲染数组之外,**v-for还可以渲染一个对象的键值对,**对上述示例中的HTML代码稍作修改,修改后的代码如下:
<div id="app">
<h2>用户列表</h2>
<ul>
<!-- index作为第二个参数,用以标识下标 -->
<li v-for="(user, index) in users">
用户{{ index + 1 }}
<ul>
<!-- key作为第二个参数,用以标识键名 -->
<li v-for="(value, key) of user">{{ key }}: {{ value }}</li>
</ul>
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script type="text/javascript">
let vm = new Vue({
el: '#app',
data () {
return {
users: [
{
name: 'Clark',
age: 27,
city: 'Chicago'
},
{
name: 'Jackson',
age: 28,
city: 'Sydney'
}
]
}
}
})
</script>
结果:
Vue会把数组当作被观察者加入响应式系统中,当调用一些方法修改数组时,对应的视图将会同步更新
与数据响应有关的数组方法 下面是一个用到了push()和reverse()方法的示例,代码如下:
<div id="app">
<h2>用户列表</h2>
<button @click="createUser">创建用户</button>
<button @click="reverse">倒序数组</button>
<ul>
<!-- index作为第二个参数,用以标识下标 -->
<li v-for="(user, index) in users">
用户{{ index + 1 }}
<ul>
<!-- key作为第二个参数,用以标识键名 -->
<li v-for="(value, key) of user">
<strong style="display: inline-block;width: 60px;">{{ key }}:</strong>
<span>{{ value }}</span>
</li>
</ul>
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script type="text/javascript">
let vm = new Vue({
el: '#app',
data () {
return {
users: []
}
},
methods: {
random (factor, base) { // 根据乘积因子和基数生成随机整数
return Math. floor(Math.random() * (factor || 1)) + (base || 0)
},
createUser () {
// 获取 name 大写首字母
let fLetter = '王张李吴何梁兰'[this.random(6.999)]
// 随机截取 name 字符串
let nameStr = '国靖新韩信鑫心欣辛梦梅眉舞湾宛菀莉利立历黎'
let bLetters = nameStr.substr(this.random(3.999), this.random(3.999, 1))
let user = {
name: fLetter + bLetters,
age: this.random(5.999, 25),
city: ['北京', '上海', '深圳', '杭州','大连'][this.random(4.999)]
}
console.log('--------------- 创建用户 ---------------\n', user)
this.users.push(user)
},
reverse () {
console.log('--------------- 倒序列表 ---------------')
console.log('Before:', this.users.map(user => user.name))
this.users.reverse()
console.log('After:', this.users.map(user => user.name))
}
}
})
</script>
注:<strong></strong>类似于<b></b>都是强调的,在网页中形成的字是粗体,<strong>在性质上和一样是属于行内联
结果:
点击倒序数组以后:
注意:关于姓之后的字的多少用 let bLetters = nameStr.substr(this.random(3.999), this.random(1.999, 1))来控制,第二个this.random中第一个数字的大小
查看控制台信息:
4.2 列表渲染中的key
在使用v-for时,最好为每个迭代元素提供一个值不重复的key。 当列表渲染被重新执行(数组内容发生改变)时,如果不使用key, Vue会为数组成员就近复用已存在的DOM节点,如图所示。
不使用key时的列表渲染
当使用key时,Vue会根据key的变化重新排列节点顺序,如图所示,并将移除key不存在的节点。
使用key时的列表渲染
实质上,key的存在是为DOM节点标注了一个身份信息,让Vue能够有迹可循追踪到数据对应的节点。在实战开发中,是否使用key都不会影响功能的实现,不过在Vue 2.2.0+的版本中,使用v-for时没有附加key的话,Vue会给出一个警告。
计算属性
Vue.js还提供了计算属性这种方法,避免在模板中加入过重的业务逻辑,保证模板的结构清晰和可维护性。 1.基础例子
var vm = new Vue({
el : '#app,
data: {
firstName : 'Gavin',
lastName: 'CLY'
}
computed : {
fullName : function() {
// this 指向vm实例
return this.firstName + ' ' + this.lastName
}
}
});
<p>{{ firstName }}</p> // Gavin
<p>{{ lastName }}</p> // CLY
<p>{{ fullName }}</p> // Gavin CLY 此时,你对vm.firstName和vm.lastName进行修改,始终会影响vm.fullName。