Vuejs模板语法
一:vuejs介绍
Vue (读音 /vjuː/,类似于 view)
Vue是一个渐进式的框架,什么是渐进式的呢?
- 渐进式意味着你可以将Vue作为你应用的一部分嵌入其中,带来更丰富的交互体验。
- 或者如果你希望将更多的业务逻辑使用Vue实现,那么Vue的核心库以及其生态系统。
- 比如Core+Vue-router+Vuex,也可以满足你各种各样的需求。
Vue有很多特点和Web开发中常见的高级功能
- 解耦视图和数据
- 可复用的组件
- 前端路由技术
- 状态管理
- 虚拟DOM
二:修改webstorm为2个空格
三:插值操作
<div id="app">
<!-- mustach语法,不仅仅可以直接写变量,也可以写简单的表达式 -->
<h2>{{message}}</h2>
<h2>{{firstName + lastName}}</h2>
<h2>{{firstName + ' ' + lastName}}</h2>
<h2>{{firstName}} {{lastName}}</h2>
<h2>{{counter * 2}}</h2>
</div>
3.1 v-once
该指令后面不需要跟任何表达式(比如之前的v-for后面是由跟表达式的)
该指令表示元素和组件只渲染一次,不会随着数据的改变而改变。
<div id="app">
<h2>{{message}}</h2>
<h2 v-once>{{message}}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
message: 'Hello',
}
})
</script>
3.2 v-html
某些情况下,我们从服务器请求到的数据本身就是一个HTML代码,如果我们直接通过{{}}来输出,会将HTML代码也一起输出。 但是我们可能希望的是按照HTML格式进行解析,并且显示对应的内容。
如果我们希望解析出HTML展示
- 可以使用v-html指令
- 该指令后面往往会跟上一个string类型
- 会将string的html解析出来并且进行渲染
<div id="app">
<h2>{{url}}</h2>
<h2 v-html="url"></h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
url: '<a href="https://www.badiu.com">Baidu</a>'
}
})
</script>
3.3 v-pre
v-pre用于跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法。
比如下面的代码:
- 第一个h2元素中的内容会被编译解析出来对应的内容
- 第二个h2元素中会直接显示{{message}}
<div id="app">
<h2>{{message}}</h2>
<h2 v-pre>{{message}}</h2>
</div>
3.4 v-cloak
在某些情况下,我们浏览器可能会直接显然出未编译的Mustache标签。
cloak: 斗篷
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<h2 v-cloak>Hello {{message}}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
# 在vue解析之前,div中有一个属性v-cloak
# 在vue解析之后,div中没有一个属性v-cloak
const app = new Vue({
el: "#app",
data: {
message: 'Andy Low'
}
})
</script>
代码是由上而下执行的,当执行到div标签时,页面会直接显示{{message}},执行到js代码后才会将{{message}}替换为Andy Low,这样页面在显示时会出现一个闪动效果。
四:绑定属性(v-bind)
前面我们学习的指令主要作用是将值插入到我们模板的内容当中。
但是,除了内容需要动态来决定外,某些属性我们也希望动态来绑定。
- 比如动态绑定a元素的href属性
- 比如动态绑定img元素的src属性
这个时候,我们可以使用v-bind指令:
- 作用:动态绑定属性
- 预期:any (with argument) | Object (without argument)
- 参数:attrOrProp (optional)
v-bind用于绑定一个或多个属性值,或者向另一个组件传递props值
在开发中,有哪些属性需要动态进行绑定呢?
还是有很多的,比如图片的链接src、网站的链接href、动态绑定一些类、样式等等
<div id="app">
<img v-bind:src="imgUrl" alt=""> # imgUrl如同上面的message一样,是data中定义的变量
<a :href="aHref">Baidu</a> # v-bind可以省略(语法糖)
</div>
4.1 v-bind绑定class
v-bind可以绑定普通字符串,对象,数组
<div id="app">
<!-- {}表示是一个对象,里面写键值对 -->
<h2 :class="{active:isActive, line:isLine}">{{message}}</h2>
<button @click="btnClick">Button</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
message: 'Andy Low',
isActive: true,
isLine: true
},
methods: {
btnClick: function() {
this.isActive = !this.isActive
}
}
})
</script>
如果过于复杂,可以入在一个methods或者computed中:
<div id="app">
<!-- {}表示是一个对象,里面写键值对 -->
<h2 :class="getClasses()">{{message}}</h2>
<button @click="btnClick">Button</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
message: 'Andy Low',
isActive: true,
isLine: true
},
methods: {
btnClick: function() {
this.isActive = !this.isActive
},
getClasses: function() {
return {active:this.isActive, line:this.isLine}
}
}
})
</script>
v-bind的数组语法:
<div id="app">
<!-- [active, line]数组中的元素不加引号是变量,加引号是普通字符串 -->
<h2 :class="[active, line]" class="title">{{message}}</h2>
</div>
4.2 v-bind绑定style
在写CSS属性名的时候,比如font-size
- 我们可以使用驼峰式 (camelCase) fontSize
- 或短横线分隔 (kebab-case,记得用单引号括起来) ‘font-size’
绑定方式一:对象语法
:style="{color: currentColor, fontSize: fontSize + 'px'}"
绑定方式二:数组语法
<div v-bind:style="[baseStyles, overridingStyles]"></div>
如果过于复杂,可以放到methods或computed中:
<template>
..................................
<div :style="activeStyle"><slot name="item-text"></slot></div>
</div>
</template>
<script>
export default {
name: "TabBarItem",
props: {
path: String,
activeColor: {
type: String,
default: 'red',
}
},
data() {
return {
}
},
computed: {
isActive() {
return this.$route.path.indexOf(this.path) != -1
},
activeStyle() {
return this.isActive ? {color: this.activeColor} : {}
}
},
....................
}
</script>
五:计算属性
5.1 基础使用
我们知道,在模板中可以直接通过插值语法显示一些data中的数据。
但是在某些情况,我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示
- 比如我们有firstName和lastName两个变量,我们需要显示完整的名称。
- 但是如果多个地方都需要显示完整的名称,我们就需要写多个{{firstName}} {{lastName}}
<div id="app">
<h2>{{fullName}}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
firstName: 'Andy',
lastName: 'Low'
},
computed: {
fullName: function() {
return this.firstName + ' ' + this.lastName
}
}
})
</script>
计算属性较为复杂的操作:
<div id="app">
<h2>总价格:{{totalPrice}}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
books: [
{id: 110, name: 'Unix', price: 119},
{id: 113, name: 'Linux', price: 90},
{id: 115, name: 'Python', price: 50},
{id: 118, name: 'Java', price: 158}
]
},
computed: {
totalPrice: function() {
let result = 0
for (let i = 0; i < this.books.length; i++) {
result += this.books[i].price
}
return result
}
}
})
</script>
5.2 setter与getter
计算属性中的方法完整的写法如下:
computed: {
fullName: {
set: function() {
// 设置fullName值时会被调用
console.log('------');
},
get: function() {
return 'abc'
}
}
}
由于一般我们在计算属性中的方法不需要做设置值的操作,也就是方法中只有get方法,于是我们简写成了上面5.1节中的写法
5.3 计算属性的缓存
我们可能会考虑这样的一个问题:
- methods和computed看起来都可以实现我们的功能,
- 那么为什么还要多一个计算属性这个东西呢?
- 原因:计算属性会进行缓存,如果多次使用时,计算属性只会调用一次;而methods中的方法调用几次会执行几次
六: 事件监听
在前端开发中,我们需要经常和用户进行交互。
- 这个时候,我们就必须监听用户发生的时间,比如点击、拖拽、键盘事件等等
- 在Vue中如何监听事件呢?使用v-on指令
v-on介绍 - 作用:绑定事件监听器
- 缩写:@
- 预期:Function | Inline Statement | Object
- 参数:event
6.1 v-on参数
当通过methods中定义方法,以供@click调用时,需要注意参数问题:
- 情况一:如果该方法不需要额外参数,那么方法后的()可以不添加。但是注意:如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去
- 情况二:如果既要传入某个参数,又要传递event时,可以通过$event传入事件。
<div id="app">
<button @click="btnClick()">Button1</button>
<button @click="btnClick">Button2</button>
<!-- 如果btn2Click方法需要一个参数,但这里在监听时没有给参数,那么vue会默认将浏览器生成的event事件作为参数传递到函数中 -->
<button @click="btn2Click(123)">Button3</button>
<button @click="btn3Click(10, $event)">Button4</button>
</div>
6.2 v-on修饰符
在某些情况下,我们拿到event的目的可能是进行一些事件处理。
Vue提供了修饰符来帮助我们方便的处理一些事件:
- .stop - 调用 event.stopPropagation(),阻止冒泡
- .prevent - 调用 event.preventDefault(),阻止默认事件
- .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
- .native - 监听组件根元素的原生事件。
- .once - 只触发一次回调
<div id="app">
<div @click="divClick">
<button @click.stop="btnClick">Button</button> # .stop阻止冒泡
</div>
</div>
其它修饰符:
<button @click.prevent></button> # 阻止默认行为
<form action="" @submit.prevent></form> # 阻止默认行为,没有表达式
<button @click.stop.prevent></button> # 串联修饰符
<input type="text" @keyup.enter="onEnter"> # 键修饰符,键别名
<input type="text" @keyup.13="onEnter"> # 键修饰符,键代码
<button @click.once="doThis"></button> # 点击回调只会触发一次
七: 条件判断
v-if、v-else-if、v-else
- 这三个指令与JavaScript的条件语句if、else、else if类似。
- Vue的条件指令可以根据表达式的值在DOM中渲染或销毁元素或组件
v-if的原理:
- v-if后面的条件为false时,对应的元素以及其子元素不会渲染。也就是根本没有不会有对应的标签出现在DOM中。
<div id="app">
<h2 v-if="score>=90">优秀</h2>
<h2 v-else-if="score>=80">良好</h2>
<h2 v-else-if="score>=60">及格</h2>
<h2 v-else>不及格</h2>
</div>
7.1 切换小案例
<div id="app">
<span v-if="isUser">
<label for="username">username</label>
<input type="text" id="username" placeholder="username">
</span>
<span v-else>
<label for="email">email</label>
<input type="text" id="email" placeholder="email">
</span>
<button @click="isUser = !isUser">Switch</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
isUser: true
}
})
</script>
该案例很简单,点击按钮时input输入框进行切换。但是你会发现如果我们在有输入内容的情况下,切换了类型,会发现文字依然显示之前的输入的内容。按道理讲,我们应该切换到另外一个input元素中了。在另一个input元素中,我们并没有输入内容。为什么会出现这个问题呢?
这是因为Vue在进行DOM渲染时,出于性能考虑,会尽可能的复用已经存在的元素,而不是重新创建新的元素。在上面的案例中,Vue内部会发现原来的input元素不再使用,直接作为else中的input来使用了。
解决方案:如果我们不希望Vue出现类似重复利用的问题,可以给对应的input添加key,并且我们需要保证key的不同
<input type="text" id="username" placeholder="username" key="username">
<input type="text" id="email" placeholder="email" key="email">
7.2 v-show
v-show的用法和v-if非常相似,也用于决定一个元素是否渲染
v-if与v-show的区别:
- v-if当条件为false时,压根不会有对应的元素在DOM中。
- v-show当条件为false时,仅仅是将元素的display属性设置为none而已。
开发中如何选择呢?
- 当需要在显示与隐藏之间切片很频繁时,使用v-show
- 当只有一次切换时,通过使用v-if
八: 循环遍历
8.1 遍历数组
<ul>
<li v-for="item in movies">{{item}}</li>
<li>-------------------------------</li>
<li v-for="(item,index) in movies">{{index}} - {{item}}</li> # index为数组下标
</ul>
8.2 遍历对象
<ul>
<!-- 下面item获取到的是对象的value -->
<li v-for="item in info">{{item}}</li>
<!-- 下面的遍历获取到的是对象的value,key -->
<li v-for="(value,key) in info">{{key}} - {{value}}</li>
<!-- 下面的遍历获取到的是对象的value,key,index -->
<li v-for="(value,key,index) in info">{{key}} - {{value}} - {{index}}</li>
</ul>
8.3 key属性
官方推荐我们在使用v-for时,给对应的元素或组件添加上一个:key属性
一句话,key的作用主要是为了高效的更新虚拟DOM
8.4 检测数组更新
因为Vue是响应式的,所以当数据发生变化时,Vue会自动检测数据变化,视图会发生对应的更新。
Vue中包含了一组观察数组编译的方法,使用它们改变数组也会触发视图的更新。
// 1: push
this.letters.push('FF')
// 2: pop
this.letters.pop()
// 3: unshift 向数组的开头添加一个或更多元素,并返回新的长度
this.letters.unshift('why', 'zs')
// 4: shift 把数组的第一个元素从其中删除,并返回第一个元素的值
this.letters.shift()
// 5: splice 传递一个参数(index),将对应index以及后面的所有元素删除
this.letters.splice(2)
// 6: sort 排序
this.letters.sort()
// 7:reverse
this.letters.reverse()
并不是所有的操作都是响应式的:
btnClick() {
// this.letters[1] = 'kobe' # 该操作改变了数组,但页面不会立即渲染
# 下面的操作都是响应式
this.letters.splice(1,1,'kobe')
# set(要修改的对象,索引值,修改后的值)
Vue.set(this.letters, 1, 'kobe')
}
九: v-model
表单控件在实际开发中是非常常见的。特别是对于用户信息的提交,需要大量的表单。
Vue中使用v-model指令来实现表单元素和数据的双向绑定。
<input type="text" v-model="message">
<h2>{{message}}</h2>
当我们在输入框输入内容时
因为input中的v-model绑定了message,所以会实时将输入的内容传递给message,message发生改变。
当message发生改变时,因为上面我们使用Mustache语法,将message的值插入到DOM中,所以DOM会发生响应的改变。所以,通过v-model实现了双向的绑定。
当然,我们也可以将v-model用于textarea元素
9.1 v-model原理
v-model其实是一个语法糖,它的背后本质上是包含两个操作:
- v-bind绑定一个value属性
- v-on指令给当前元素绑定input事件
<div id="app">
<input type="text" :value="message" @input="valueChange">
<h2>{{message}}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
message: 'Hello'
},
methods: {
valueChange(event) {
this.message = event.target.value
}
}
})
</script>
9.2 v-model与radio
<div id="app">
<label for="male">
<input type="radio" id="male" name="sex" value="male" v-model="sex">Male
</label>
<label for="female">
<input type="radio" id="female" name="sex" value="female" v-model="sex">Female
</label>
<h2>你的选择是:{{sex}}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
sex: 'male' # 默认选择male
},
})
</script>
注意:radio类型中必须有name属性,否则不能互斥(两个都可以选择),如果使用了v-model进行双向绑定时,name属性可以不写,radio也是互斥的
9.3 v-model与checkbox
单个勾选框:
- v-model即为布尔值。
- 此时input的value并不影响v-model的值
<div id="app">
<label for="agree">
<input type="checkbox" id="agree" v-model="isAgree">同意协议
</label>
<h2>你选择的是:{{isAgree}}</h2>
<button :disabled="!isAgree">下一步</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
isAgree: false
},
})
</script>
多个复选框:
- 当是多个复选框时,因为可以选中多个,所以对应的data中属性是一个数组。
- 当选中某一个时,就会将input的value添加到数组中。
<div id="app">
<input type="checkbox" value="football" v-model="hobbies">Football
<input type="checkbox" value="basketball" v-model="hobbies">BasketBall
<input type="checkbox" value="tennis" v-model="hobbies">Tennis
<h2>你的爱好是:{{hobbies}}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
hobbies: []
},
})
</script>
9.4 v-model与select
单选:只能选中一个值。
- v-model绑定的是一个值。
- 当我们选中option中的一个时,会将它对应的value赋值到mySelect中
<div id="app">
<select name="fruit" id="" v-model="fruit">
<option value="Apple">Apple</option>
<option value="Pear">Pear</option>
<option value="Banana">Banana</option>
<option value="Orange">Orange</option>
</select>
<h2>your choice is: {{fruit}}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
fruit: 'Orange'
},
})
</script>
多选:可以选中多个值。
- v-model绑定的是一个数组。
- 当选中多个值时,就会将选中的option对应的value添加到数组mySelects中
<div id="app">
<select name="fruits" id="" v-model="fruits" multiple>
<option value="Apple">Apple</option>
<option value="Pear">Pear</option>
<option value="Banana">Banana</option>
<option value="Orange">Orange</option>
</select>
<h2>your choice is: {{fruits}}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
fruits: []
},
})
</script>
9.5 修饰符
lazy修饰符:
- 默认情况下,v-model默认是在input事件中同步输入框的数据的。
- 也就是说,一旦有数据发生改变对应的data中的数据就会自动发生改变。
lazy修饰符可以让数据在失去焦点或者回车时才会更新:
<input type="text" v-model.lazy="message">
<p>当前内容:{{message}}</p>
number修饰符:
- 默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理。
- 但是如果我们希望处理的是数字类型,那么最好直接将内容当做数字处理。
number修饰符可以让在输入框中输入的内容自动转成数字类型:
<input type="number" v-model.number="age">
<p>age: {{age}}, type: {{typeof age}}</p>
trim修饰符:
- 如果输入的内容首尾有很多空格,通常我们希望将其去除
- trim修饰符可以过滤内容左右两边的空格
<input type="text" v-model.trim="message">