插值操作
v-text="data"
将数据以文本形式解析到当前节点,与Mustache语法类似v-html="data"
将数据以html标签的形式解析到当前节点v-once
与v-text类似, 但是数据只解析一次, 不会随着数据改变而改变v-pre
跳过当前节点与其子节点的解析过程,用于显示原本的Mustache语法v-cloak
某些情况下, 浏览器可能会直接显示出未编译的Mustache标签, 给用户一种乱码的感觉. 在节点中加上此语法后, 可以通过css限制带有此属性的节点隐藏, 当Mustache语法解析完成后, Vue会自动将这个属性去除, 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app" v-cloak>
<h2>{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
// 在vue解析之前, div中有一个属性v-cloak
// 在vue解析之后, div中没有一个属性v-cloak
setTimeout(function () {
const app = new Vue({
el: '#app',
data: {
message: '这是一个消息'
}
})
}, 5000)
</script>
</body>
</html>
绑定属性 v-bind
有时候, 除了节点内容需要动态绑定外, 我们希望某些属性也能动态绑定,如src, href等属性, 这时候则需要使用v-bind
- 语法: 如
v-bind:href="data"
,v-bind:src="data"
, 只需在普通属性加上v-bind:
前缀, 即可对属性进行动态绑定 - 语法糖
" : "
, 例如上面的写法可以简写成:href="data"
,:src="data"
v-bind动态绑定class
有对象语法和数组语法, 常用的是对象语法, 数据与视图分离,数据控制视图
对象语法: 对象中, 使用键值对形式, 键写class名称, 值为boolean值, 可动态绑定data内属性, 可以使用逗号分隔, 写多个键值对, 如:
<h2 :class="{'active': true, 'line': false}">Hello World</h2>
数组语法: 数组中写class类名即可,可与通过class属性合并,不会覆盖, 但不常用
<h2 class="aaa" :class="[‘active’, 'line']">Hello World</h2>
v-bind动态绑定style
同样,有对象语法和数组语法, 常用的仍是对象语法, 对象语法:
<span :style="{backgroundColor:backgroundColor(变量),color:'red'}">{{data}}</span>
数组语法
<h2 class="aaa" :class="[{color:'red'}]">Hello World</h2>
v-bind动态绑定disabled
语法:
<h2 class="aaa" :disabled="true(布尔值,等于true时则开启此属性)">Hello World</h2>
计算属性
Vue中的计算属性为:computed, 在页面需要显示一些通过Mustache语法难以处理时(如数组中的数字求和), 则需要使用计算属性; 直接在计算属性中定义一个函数, 将计算好的数据return, 在页面中即可如使用变量一样使用计算属性, 实例如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">数组总量:{{comp}}</div>
<script>
const app = new Vue({
el:"#app",
data:{
list:[20,50,100,150,200]
},
computed:{
comp(){
let number = 0;
for (let i=0;i<this.list.length;i++){
number+=this.list[i]
}
return number
}
}
})
</script>
</body>
</html>
计算属性中的getter和setter
实际上, 每个属性都包含一个gerter和setter属性, 我们可以在计算属性中提供一个getter方法, 当此计算属性被访问时, 这个getter方法将被执行, 最终可以取得getter方法返回的数据.
计算属性的缓存
如上使用计算属性完成的功能, 事实上, methods一样可以很好的完成, 而计算属性存在缓存, 区别于Methods, 同一个计算属性只会执行一次, 性能远远高于Methods. 所以, 在做复杂数据的展示时, 应该使用计算属性
事件监听
在前端中, 经常需要和用户交互, 需要感知用户点击, 拖拽, 键盘事件等, 我们需要用到监听事件v-on, 语法糖:@
v-on修饰符
- .stop 阻止事件向上冒泡
- .prevent 去除元素默认事件
- .keyCode | .keyAlias 使用@keyup做前缀, 监听键盘按下事件, 当监听到对应按键时触发, 如
@keyup.entry="change"
, 为敲下回车键时调用change函数 - .native 监听组件跟元素的原生事件
- .once 只触发一次回调
<!-- 点击时调用aa函数并阻止事件向上冒泡-->
<button @click.stop="aa()">btn</button>
<!-- 点击时调用aa函数并去除元素的默认事件-->
<button @click.prevent="aa()">btn</button>
<!-- 点击时调用aa函数并禁用此元素的点击事件, 此元素只触发一次此回调-->
<button @click.once="aa()">btn</button>
<!-- 输入回车时调用changes函数-->
<input type="text" @keyup.entry="changes()">
条件判断 if else
vue中提供v-if
, v-else-if
, v-else
属性, 作用与JavaScript的if else类似, 根据表达式的值(true或false)在DOM中渲染或销毁元素
- v-if 后面的条件为false时, 对应的元素及其子元素不会渲染, 也就是根本不会有对应的元素出现在DOM中
<div id="app">
<p v-if="score==100">挺牛的</p>
<p v-else-if="score>=90">秀儿</p>
<p v-else-if="score>=60">及格</p>
<p v-else>还要努力哦</p>
</div>
v-show
v-show的用法与v-if非常相似, 都用于决定一个元素是否显示, 不同的是
- v-if当条件为false时,压根不会有对应的元素在DOM中, 当条件再次为true时, 将重新在DOM中创建并渲染元素
- v-show当条件为false时,仅仅是将元素的display属性设置为none而已, 并不从DOM中删除元素, 当条件再次为true时, 也只是将display属性删除
因此, 当需要在显示与隐藏之间频繁切换时, 使用v-show, 只有一次切换时, 使用v-if
v-for
当有一组数据(如数组)需要进行渲染时, 可以使用v-for完成, 作用与JavaScript的for循环相似,如法如下
-
不需要使用到索引时
v-for="item(遍历得到的当前对象) in xx(要遍历的数组或对象)"
-
需用得到索引时
v-for="(item(遍历得到的当前对象),index(当前索引)) in xx(要遍历的数组或对象)"
-
注: 当使用索引直接改变数组中的某个值时(如:
strList[2]='祝你天天开心'
), Vue的双向数据绑定不会生效, 也就是不会重新渲染视图
key属性
Vue在进行DOM渲染时,出于性能考虑,默认会尽可能的复用已经存在的元素,而不是重新创建新的元素
如果给元素加上:key
属性, 则Vue会通过属性的值判断元素是否可以复用, 当两个元素的key相同时, vue会选择复用元素,并把差异值进行更正, 当两个元素的key不同时, vue则不会复用原来的元素, 而是将原元素删除, 并创建新的元素, 这个和虚拟DOM树和Diff算法有关
而官方推荐我们在使用v-for时, 给对应的元素加上:key
属性, 并且希望此属性的值可以代表自身并保证唯一(类似数据库中的主键), 当v-for循环对应的数组发生改变时(如添加或删除或修改一条数据时), Vue会先根据key保留未发生改变的数据, 从而只重新渲染被改变的数据, 而不是将v-for中的所有数据全部重新渲染. 当循环渲染的数据量大时, 用此可以极大节约性能
表单绑定 v-model
表单控件在实际开发中其实是非常常见的, 特别是对于用户信息的提交, 需要大量的表单; vue使用v-model
来实现表单元素和数据的双向绑定, 但它其实是一个语法糖, 其背后的本质包含两个操作:
- v-bind绑定一个value属性
- v-on给当前元素绑定input事件
单选框readio
直接绑定指定属性即可, 如:
<div id="app">
<input type="radio" v-model="a" value="男">男
<input type="radio" v-model="a" value="女">女
<h1>{{a}}</h1>
</div>
<script>
const app = new Vue({
el:"#app",
data:{
a:"男"
},
})
</script>
多选框checkbox
- 单个勾选框的情况中, v-model 绑定一个布尔值即可
- 多个勾选框的情况下, v-model 绑定一个数组, 并且可以给checkbox绑定一个value, 当勾选框被勾选时, value会被添加到数组中, 如下:
<div id="app">
<label>
<input type="checkbox" v-model="list" value="A">
</label>
<label>
<input type="checkbox" v-model="list" value="B">
</label>
<h1>{{list}}</h1>
</div>
<script>
const app = new Vue({
el:"#app",
data:{
list:[]
}
})
</script>
下拉选择框select
在select元素中使用v-model绑定属性, 将自动与option选择的值匹配
生命周期
声明周期函数, 也叫钩子函数, 在Vue运行到某种状态时触发, 钩子函数如el
, data
属性一样, 写在创建Vue实例时的参数对象中
<div id="app"></div>
<script>
const app = new Vue({
el:"#app",
mounted:()=>{
alert("声明周期函数mounted被执行")
}
})
</script>
如上代码, 我们写了一个钩子函数mounted, 当我们在浏览器运行时, 会发现 声明周期函数mounted被执行
这句话成功在浏览器弹窗了, 这就是钩子函数被执行产生的结果, 钩子函数具体有如下11个():
- beforeCreate : 创建Vue实例前的时候执行
- created : 创建Vue实例完成后执行
- beforeMount : Vue实例开始渲染前执行
- mounted : Vue实例渲染完成后执行, 常用于想后台请求数据
- beforeUpdate : Vue实例修改前执行
- updated : Vue实例修改完成后执行
- beforeDestroy : Vue开始消亡前执行
- destroyed : Vue实例消亡后执行
- activated :组件激活时调用。该钩子在服务器端渲染期间不被调用
- deactivated : 组件停用时调用。该钩子在服务器端渲染期间不被调用
- errorCaptured : 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播
管道过滤器filters
filter译为过滤器 ,语法: {{ 显示文本 | 过滤器 }}
它可以将即将需要展示的数据进行拦截, 然后可以进行修饰, 最后返回修饰过后的数据到页面,看以下示例
<div id="app">
<!-- 展示data中的text属性的值, 并将值传到change过滤器aaa中 -->
{{text | aaa }}
</div>
<script>
const app = new Vue({
el:"#app",
data:{
text:36.88
},
//创建一个过滤器, 名为aaa
filters:{
aaa(val){
//为值拼接上美元符与'元',然后再返回给视图渲染
let result = "$"+val+"元";
return result;
}
}
})
</script>
以上实例中声明了一个值为36.88的变量text
和一个名为 aaa的过滤器(写在filters中的函数都可作为过滤器), 接着在页面渲染text
, 并使用aaa过滤器, 最终页面显示的结果会是$36.88元
而不再是 36.88
同一个表达式中, 可以写多个过滤器, 如: {{text | aaa | bbb }}
则是先执行aaa函数, 得到返回值以后再传入bbb函数中执行
组件化
有时候,我们希望将一些东西复用,以组件的形式插拔,以减少代码冗余,vue中,提供了创建组件的方式exnend,示例如下:
const cpn = Vue.extend({
template:`
<h1>这是vue中的一个子组件</h1>
<a href="http://www.baidu.com">点击跳转</a>
`
})
创建通过vue创建组件后,需要将他注册到Vue中,使用Vue.component函数即可: Vue.component("cpn",cpn);
接下来,我们就可以在vue容器内使用这个cpn组件了,完整示例如下:
<div id="app">
<cpn-view></cpn-view>
</div>
<script>
//创建一个组件,名为cpn
const cpn = Vue.extend({
template:`
<div>
<h1>这是vue中的一个组件实例</h1>
<h1>documentAuthor 想了一整个当初</h1>
</div>
`
})
//将cpn组件注册到Vue全局
Vue.component("cpn-view",cpn);
const app = new Vue({
el:"#app"
})
</script>
这是一个简单的写法示例, 但实际上, 在通过Vue创建的组件, 你不仅可以使用template
属性指定html内容, 你还可以使用data
, methods
, computed
等属性为组件声明数据,函数,计算属性等, 然后通过v-bind,v-model.n-on
等语法去使用它, 这点与我们直接new出来的Vue实例很非常相似, 但不同的是, vue中的组件的data属性必须是个函数, 然后以函数返回值的形式声明数据, 否则会报错 , 采用这种方式, 组件每次被复用时data属性都会得到一个新创建的对象, 而不是与多个正在复用的组件共享同一个data, 避免组件被多处复用时组件内数据产生数据引用传递问题
上面这个示例, 组件是通过通过Vue.component
函数注册的, 通过这种方式注册到Vue中的组件, 称为全局组件, 全局组件可以使用在任何一个组件中, 与之对应的, 是局部组件:
<div id="app">
<cpnv></cpnv>
</div>
<template id="cpn">
<div>
<h1>这是vue中的一个组件实例</h1>
<h1>documentAuthor 想了一整个当初</h1>
</div>
</template>
<script>
//创建一个组件,名为cpn
const cpn = Vue.extend({
template: "#cpn"
})
const app = new Vue({
el:"#app",
components:{
cpnv:cpn
}
})
</script>
如上, 我们创建了一个cpn,并且在vue实例中的components
中注册了这个组件, 通过这样的方式注册, cpn就成为了app(根组件)的私有组件, 其他的组件就已经无法调用了, 查找顺序是先中局部组件找, 局部组件找不到时再到全局组件中找, 局部组件的优先级最高
- 组件的template属性, 不仅可以写直接写html标签, 还可以通过选择器引用文档树中的节点, 上面的实例我们采用的就是这种方式, template被赋值成了一个id为cpn的节点
子组件和父组件
在vue中, 组件与组件之间可以互相引用, 我们先看如下示例:
<div id="app">
<cpn1></cpn1>
</div>
<template id="cpn1">
<div>
<h1>已识乾坤大</h1>
<cpn2></cpn2>
</div>
</template>
<template id="cpn2">
<h1>尤怜草木青</h1>
</template>
<script>
const cpn2 = Vue.extend({
template:"#cpn2"
})
const cpn1 = Vue.extend({
template:"#cpn1",
components:{
cpn2:cpn2
}
});
const app = new Vue({
el:"#app",
components:{
cpn1:cpn1
}
})
</script>
在如上实例中, 我们创建了一个Vue实例和两个组件, 分别是cpm1
与cpn2
, 然后在实例中引用了cpn1组件, 同时, 在cpn1组件中引用了cpn2组件; 此时cpn1
是cpn2
的父组件; 而 cpn2
是 cpn1
的子组件; 这是一个概念化的东西, 父子组件是成对存在的