vue基础
一.第一个vue程序
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>第一个vue程序</title>
</head>
<body>
<div class="" id="app">
<span>{{msg}}</span>
<span>{{keywold}}</span>
<button v-on:click="add">点击</button>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<script>
var vm=new Vue({
el:"#app",
data:{//对象的格式
msg:"你好世界",
keywold:"我正在学习vue"
},
methods:{//对象的格式
add(){
console.log(this.msg);
}
}
});
</script>
</body>
</html>
vue的第一个程序虽然简单,但是包含了vue的诸多基础的知识点,下面我们正式学习vue的基础知识
二.挂载
<script>
var vm=new Vue({
el:"#app",//挂载
data:{
msg:"你好世界",
keywold:"我正在学习vue"
},
methods:{
add(){
console.log(this.msg);
}
}
});
</script>
在vue运行时会根据你挂载的是哪个DOM节点进行查找,该vue实例的数据将对该节点的区域起作用
三.插值表达式 {{}}
在vue中插值表达式的作用
- 对象:{{{ name:'jack'}}}
- 字符串:{{'hello world!'}}
- 布尔值:{{isTrue==-1}}
- 三元表达式:{{isTrue?'正确':'错误'}}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
</head>
<body>
<div class="" id="app">
<p>{{ msg }}</p>
<p>{{ {name: 'jack'} }}</p>
<p>{{ 'Hello World!' }}</p>
<p>{{ isTrue == -1 }}</p>
<p>{{ isTrue ? '真' : '假' }}</p>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<script>
var vm=new Vue({
el:"#app",
data:{
msg:"你好世界",
isTrue:true
},
methods:{
add(){
console.log(this.msg);
}
}
});
</script>
</body>
</html>
四.指令 v-
-
v-text
-
v-html
-
v-if
-
v-else-if
-
v-else
-
v-show
-
v-bind
-
v-on
-
v-model
-
v-for
1.v-text v-html
-
v-text:把内容当做纯文本解析出来,不会解析HTML代码
-
v-html:可以解析HTML代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
</head>
<body>
<div class="" id="app">
<p v-text="msg"></p>
<p v-html="msg"></p>
</div>
<script src="vue-2.4.0.js"></script>
<script>
var vm=new Vue({
el:"#app",
data:{
msg:"<h1>你好世界</h1>",
},
methods:{
add(){
console.log(this.msg);
}
}
});
</script>
</body>
</html>
2.v-if v-else-if v-else v-show
说明:
- v-if v-show的功能类似,都是判断语句,如果条件成立则进行节点渲染
- v-if 如果是假,则在 Element 中不会渲染
- v-show 如果是假,则该标签为 display: none
- 一般来说,
v-if
有更高的切换开销,而v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show
较好;如果在运行时条件很少改变,则使用v-if
较好。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
</head>
<body>
<div class="" id="app">
<p v-if="tag>=90">成绩优秀</p>
<p v-else-if="tag>=60">成绩合格</p>
<p v-else="tag<60">成绩不合格</p>
<p v-show="msg==11">你可以毕业了!</p>
</div>
<script src="vue-2.4.0.js"></script>
<script>
var vm=new Vue({
el:"#app",
data:{
tag:93,
msg:11
},
});
</script>
</body>
<!--结果-->
<!--成绩合格-->
<!--你可以毕业了-->
</html>
3.v-for v-bind v-model
说明:
v-for
是循环指令,如果有两个参数,v-for=(item,index) in arr
,item
表示数组的值,index
表示数组的索引v-bind
是属性绑定指令,给某个元素绑定属性,数据流向:vue-htmlv-model
双向数据绑定,v-model
只能给具有 value 属性的元素进行双向数据绑定,一般为表单元素,数据流向:vue-html-vue
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
</head>
<body>
<div class="" id="app">
<input v-model="msg" ></input>
<input v-bind:type="type" v-bind:value="msg"></input>
<p><span v-bind:style="style">你好呀,世界!</span></p>
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<th>编号</th>
<th>科目</th>
<th>成绩</th>
</tr>
<!--使用v-for时,一般要绑定一个key属性-->
<tr v-for="v in course" v-bind:key="v.id">
<th>{{v.id}}</th>
<th>{{v.cname}}</th>
<th>{{v.score}}</th>
</tr>
</table>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<script>
var vm=new Vue({
el:"#app",
data:{
course:[
{id:1,cname:"语文",score:70},
{id:2,cname:"数学",score:60},
{id:3,cname:"英语",score:58},
{id:4,cname:"生物",score:89},
{id:5,cname:"化学",score:94}
],
msg:"2018-2019学年成绩",
type:"button",
style:"color:red;"
}
});
</script>
</body>
</html>
4.v-on
说明:
- v-on,绑定的是事件,比如:v-on:click
- v-on:click - 全写,@click - 简写
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文字跑马灯</title>
<style type="text/css">
a{
display: inline-block;
padding: 4px;
border:1px solid #ccc;
cursor: pointer;
}
</style>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
</head>
<body>
<div class="box">
<div>
<a v-on:click.prevent="start">开始</a>
<a v-on:click.prevent="stop">结束</a>
</div>
<h2 v-html="msg"></h2>
</div>
<script>
var vm=new Vue({
el:(".box"),
data:{
msg:"我是幽灵小猫,你呢?",
timer:null
},
methods:{
start(){
this.timer=setInterval(()=>{
start=this.msg.substring(0,1);
end=this.msg.substring(1);
this.msg=end+start;
},300)
},
stop(){
clearInterval(this.timer);
}
}
});
</script>
</body>
</html>
-
substring( )
该方法用于提取字符串中介于两个指定下标之间的字符。
返回值是一个新的字符串,该字符串值包含 stringObject 的一个子字符串,其内容是从 start 处到 stop-1 处的所有字符,start 比 stop 大,那么该方法在提取子串之前会先交换这两个参数。
五.事件修饰符
- .stop: 阻止冒泡
- .prevent: 阻止默认事件
- .capture 添加事件侦听器时使用事件捕获模式
- .self 只当事件在该元素本身(比如不是子元素)触发时触发回调
- .once 事件只触发一次
六.自定义指令
-
自定义指令不详讲,这里举一个常用的例子
-
Vue.directive( dir_name , {} ) 定义全局自定义指令
-
directives{ dir_name : {} } 定义局部自定义指令
// 自定义全局指令 v-focus,为绑定的元素自动获取焦点:
Vue.directive('focus', {
inserted: function (el) { // inserted 表示被绑定元素插入父节点时调用
el.focus();
}
});
七.过滤器
-
过滤器的作用是将后台传过来的数据进行过滤
-
改变渲染结果,并返回过滤后的版本,不改变真正的data
-
过滤器可以用在两个地方: 插值表达式和 v-bind 表达式。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符指示
-
过滤器可以分为全局过滤器和私有过滤器,vue本身有内置的过滤器,但是也可以自定义过滤器
1.私有过滤器
- 私有局部过滤器,只能在 当前 VM 对象所控制的 View 区域进行使用
- 写在VM对象里面
- 关键字要加s
filters:{
filterName:function(str){
return ...;
}
//或者这样写
filerName(){
return...;
}
},
2.全局过滤器
- 写在VM对象之外
- 关键字不用加s
Vue.filter("filteName",function(str){
return ...;
})
3.过滤器的使用
//在差值表达式中
{{msg | filterName()}}
//在v-bind表达式中
<div v-bind:id="rowId | filterName()"></div>
八.vue的生命周期
从两个方面理解:内部变化,外部渲染
- 从vue实例创建,运行,到销毁期间总会伴随着各种各样的事件,这些事件统称为生命周期
- 生命周期钩子:生命周期事件的别名
创建期间的生命周期函数:
-
beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性
-
created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始编译模板
-
beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中
-
mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示
运行期间的生命周期函数:
- beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点
- updated:实例更新完毕之后调用此函数,此时 data 中的状态值和界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!
销毁期间的生命周期函数:
- beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。
- destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
九.vue组件
1.什么是组件:
组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可; 组件化和模块化的不同:
- 模块化: 是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一;
- 组件化: 是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用;
2.组件的内容包括三个方面:
-
组件的声明
-
定义模板
-
使用组件
3.组件的声明
全局组件
第一种方式
Vue.component('componentName',Vue.extend({
}))
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
</head>
<body>
<div id="app">
<!--使用组件-->
<com1></com1>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<script>
Vue.component('com1',Vue.extend({
//模板定义时一定要有一个根节点
template:"<h3>我是第一种定义组件的方式</h3>"
}))
var vm=new Vue({
el:"#app",
data:{
},
methods:{
}
});
</script>
</body>
</html>
第二种方式
省略Vue.extend( )方法
Vue.component('componentName',{
})
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
</head>
<body>
<div id="app">
<!--使用组件-->
<com2></com2>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<script>
//模板定义时一定要有一个根节点
Vue.component('com2',{
template:"<div><span>这是第二种定义组件的方式</span></div>"
})
var vm=new Vue({
el:"#app",
data:{
},
methods:{
}
});
</script>
</body>
</html>
第三种方式
将模板的定义独立出来
Vue.component('com3',{
template:"#temp1",
template:"#temp2"
})
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
</head>
<body>
<div id="app">
<!--使用组件-->
<com3></com3>
</div>
<!-- 在 被控制的 #app 外面,使用 template 元素,定义组件的HTML模板结构 -->
<template id="temp1">
<div>
<h3>你好呀世界</h3>
</div>
</template>
<template id="temp2">
<div>
<span>我是第三种定义组件的方法</span>
</div>
</template>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<script>
//模板定义时一定要有一个根节点
//注意如果组件中有多个模板,在调用时该组件时只显示最后一个
Vue.component('com3',{
template:"#temp1",
template:"#temp2"
})
var vm=new Vue({
el:"#app",
data:{
},
methods:{
}
});
</script>
</body>
</html>
私有组件
-
关键词components
-
私有组件只能在本身挂载的区域里使用
私有组件第一种写法
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
</head>
<body>
<div id="app">
<!--使用组件-->
<com1></com1>
<login></login>
</div>
<!-- 在 被控制的 #app 外面,使用 template 元素,定义组件的HTML模板结构 -->
<template id="temp1">
<div>
<h3>这是公共组件</h3>
</div>
</template>
<template id="temp2">
<div>
<span>这是私有组件</span>
</div>
</template>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<script>
//公共组件
Vue.component('com1',{
template:"#temp1",
})
var vm=new Vue({
el:"#app",
data:{
},
methods:{
},
components:{//实例内部私有组件
login:{
template:"#temp2"
}
}
});
</script>
</body>
</html>
私有组价的第二种写法
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<style>
</style>
</head>
<body>
<div id="app">
<login></login>
<account></account>
</div>
<template id="temp">
<h3>我是第一个私有组件</h3>
</template>
<template id="temp1">
<h3>我是第二个私有组件</h3>
</template>
<script>
var login={//注意写法
template:"#temp",
data:function(){
return{
msg:0
}
}
};
var account={//注意写法
template:"#temp1",
data:function(){
return{
msg:0
}
}
};
var vm=new Vue({
el:"#app",
data:{
tage:1
},
methods:{
showdata(){
alert(this.tage);
}
},
components:{//注意写法,有多个组件
login,
account
}
});
</script>
</body>
</html>
十.组件中的data与vue实例的data的区别
- 组件可以有自己的 data 数据
- 组件的 data 和 实例的 data 有点不一样,实例中的 data 可以为一个对象,但是组件中的 data 必须是一个方法
- 组件中的 data 除了必须为一个方法之外,这个方法内部,还必须返回一个对象才行
- 组件中 的data 数据,使用方式,和实例中的 data 使用方式完全一样
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
</head>
<body>
<div id="app">
<!--使用组件-->
<com1></com1>
</div>
<!-- 在 被控制的 #app 外面,使用 template 元素,定义组件的HTML模板结构 -->
<template id="temp1">
<div>
<h3>{{msg2}}</h3>
</div>
</template>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<script>
//公共组件
Vue.component('com1',{
template:"#temp1",
data:function(){
return{
msg2:"这是来自公共组件的data定义的数据"
}
}
})
var vm=new Vue({
el:"#app",
data:{
msg1:"这是实例中的data"
},
methods:{
}
});
</script>
</body>
</html>
十一.组件传值
- 组件分为私有组件,全局组件
- 父组件向子组件传值,通过v-bind
- 子组件向父组件传值,通过v-on
在学习组件传值之前必须要明白谁是父组件,谁是子组件
谁是私有的谁就是子组件
1.父组件向子组件传值
注意:一定要使用props
属性来定义父组件传递过来的数据
父组件向子组件传值的描述(面试最爱)
口头描述:
- 父组件通过子组件标签绑定一个属性,这个属性的值指向自己
data
的某个属性 - 子组件中定义一个
props
属性,props
的值是一个数组,存着父组件绑定的那个属性
书面描述:
- 父组件通过标签上面定义传值
:eg='data'
父组件中data(){data:'egdata'}
- 子组件通过
props
方法接受数据props:['eg']
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
</head>
<body>
<div id="app">
<com2 v-bind:pdata="msg"></com2>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<script>
var vm=new Vue({
el:"#app",
data:{
msg:"儿子,你要听话"
},
methods:{
},
components:{
com2:{
template:"<h3>{{this.msg2}}-----{{pdata}}</h3>",
data:function(){
return {
msg2:"我是儿子,我已收到来自爸爸的话"
}
},
props:["pdata"]
},
}
});
</script>
</body>
</html>
2.子组件向父组件传值
子组件内部通过this.$emit('方法名', 要传递的数据)
方式,来调用父组件中的方法,同时把数据传递给父组件使用
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
</head>
<body>
<div id="app">
<!--传值给父组件-->
<com2 @getdata='show'></com2>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<script>
var vm=new Vue({
el:"#app",
methods:{
show(val){
alert(val);
alert("儿子,你真不争气");
}
},
components:{
com2:{
template:"<h3 @click='showdata'>{{msg2}}</h3>",
data:function(){
return {
msg2:"我是儿子,点我看看我对爸爸说了什么"
}
},
methods:{
showdata(){
this.$emit('getdata','老爸,给点钱来花')//触发当前实例上的事件,并把值传出去
}
}
},
}
});
</script>
</body>
</html>
十二.路由
在学习路由之前,我们来看看一下案例在没有使用路由知识是怎么实现的?
实现登录/注册的模块的切换
方法一:
v-if v-else
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
</head>
<body>
<div id="app">
<a v-on:click="flag=true">登录</a>
<a v-on:click="flag=false">注册</a>
<div v-if="flag==true">
<h3>登录模块</h3>
</div>
<div v-else="flag==false">
<h3>注册模块</h3>
</div>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<script>
var vm=new Vue({
el:"#app",
data:{
flag:true
},
methods:{
}
});
</script>
</body>
</html>
方法二:
组件的is
属性
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
</head>
<body>
<div id="app">
<a @click.prevent="comName='login'">登录</a>
<a @click.prevent="comName='register'">注册</a>
<component :is="comName"></component>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<script>
Vue.component('login',{
template:"<h3>登录模板</h3>"
})
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
Vue.component('login',{
template:"<h3>登录模板</h3>"
})
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
var vm=new Vue({
el:"#app",
data:{
comName:"login"//当前component中的:is绑定的组件的名称
},
methods:{
}
});
</script>
</body>
</html>
下面正式来学习路由
- 路由是属于一个模块,在使用之前要引入,下面是cdn引入,也可以离线引入
- 注意在引入路由模块之前要先引入vue库文件,否则路由模块不起作用
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
1.路由基本模板
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<style>
/*.router-link-active{
color:red;
}*/
.mystyle{
color:red;
}
</style>
</head>
<body>
<div id="app">
<router-link to="/login/李四/20">登录</router-link>//可以设置参数
<router-link to="/register">注册</router-link>
<!--占位符,用来显示匹配到的组件-->
<router-view></router-view>
</div>
<script>
var login=Vue.extend({
template:"<h3>登录组件</h3>"
});
var register=Vue.extend({
template:"<h3>注册组件</h3>"
});
var router=new VueRouter({//注意实例的名字要与下面的属性值要一致
routes:[
{path:"/",component:login},//根目录的状态下,默认加载login组件
{path:"/login/:name/:age",component:login},
{path:"/register",component:register}
],
linkActiveClass:'mystyle'
});
var vm=new Vue({
el:"#app",
router:router,//使用router属性来使用路由规则,注意属性值可以自定义
});
</script>
</body>
</html>
2.路由的嵌套
<html>
<head>
<meta charset="utf-8">
<title>路由的嵌套</title>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
</head>
<body>
<div id="app">
<router-link to="/account">点击我看看路由是怎么样嵌套的吧</router-link>
<router-view></router-view>
</div>
<template id="temp">
<div>
<h1>下面是登录注册模块</h1>
<router-link to="/account/login">登录</router-link>
<router-link to="/account/reg">注册</router-link>
<router-view></router-view>
</div>
</template>
<script type="text/javascript">
var account={
template:"#temp"
}
var login={
template:"<h3>我是登录</h3>"
}
var reg={
template:"<h3>我是注册</h3>"
}
var router=new VueRouter({
routes:[
{
path:"/account",
component:account,
children:[
{path:"login",component:login},
{path:"reg",component:reg}
]
}
]
});
var vm=new Vue({
el:"#app",
router:router
})
</script>
</body>
</html>
十三.render渲染组件与传统组件使用的区别
- 传统组件的使用并不会覆盖原先挂载区域的其他的内容
- render渲染组件会覆盖原先挂载区域的其他的内容
传统组件的写法
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
</head>
<body>
<div id="app">
<h1>我是挂载区域的标签</h1>
<login></login>
</div>
<template id="temp">
<div>
<h1>登录</h1>
</div>
</template>
<script type="text/javascript">
var vm=new Vue({
el:"#app",
components:{
login:{
template:"#temp"
}
}
})
</script>
</body>
</html
render渲染组件
注意:使用render 渲染组件,组件的定义要写在vue实例外面
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
</head>
<body>
<div id="app">
<h1>我是挂载区域的标签</h1>
<login></login>
</div>
<template id="temp">
<div>
<h1>登录</h1>
</div>
</template>
<script type="text/javascript">
var login={//注意这种写法
template:"#temp"
}
var vm=new Vue({
el:"#app",
render:function(createElements){//createElements是一个方法,调用它可以把指定的模板渲染成html结构
return createElements(login)// return 的结果,会 替换页面中 el 指定的那个 容器
}
})
</script>
</body>
</html>
在使用render渲染组件,一般会这么简写:
9+render:c=>c(longin)
十四.监听属性 watch
- watch是属性监听器,一般用来监听属性的变化
- 当监听属性的值发生变化时,调用对应的方法
- 需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<style>
</style>
</head>
<body>
<div id="app">
<input type="text" v-model="tage"/>
<p><span>{{tage}}</span></p>
<button v-on:click="showdata">点击</button>
</div>
<script>
var vm=new Vue({
el:"#app",
data:{
tage:1
},
methods:{
showdata(){
console.log(this.tage);
}
},
watch:{
//格式
//监控的属性:属性变化执行的函数
tage:function(newVal,oldVal){
//获取监控属性的新旧值
// console.log(newVal);
// console.log(oldVal);
console.log(this.tage);
},
}
});
</script>
</body>
</html>
在写法上,监控一个属性还可以这么写,只是我们写成上面的那种形式语义更好
tage(){
//获取监控属性的新旧值
//console.log(newVal);
//console.log(oldVal);
console.log(this.tage);
}
十五.计算属性computed
1.什么情况下使用计算属性
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:
js<div id="example">
{{ message.split('').reverse().join('') }}
</div>
在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message
的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。
所以,对于任何复杂逻辑,你都应当使用计算属性 , 相关的逻辑放在计算属性中完成
2.计算属性的特点
computed
的依赖值 , 也就是监测的值有多个 , 当其中的依赖值发生变化时 , 就会自动执行相应的函数- 计算属性的结果会被缓存,只要相关依赖未改变,只会返回之前的结果 , 除非依赖的响应式属性变化才会重新计算并且返回新的结果
3.基础例子
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例,reversedMessage依赖于this.message
return this.message.split('').reverse().join('')
}
}
})
3.为什么第一次运行便自动执行了计算属性对应的函数
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基础</title>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<style>
</style>
</head>
<body>
<div id="app">
<input type="text" v-model="str"/>
<input type="text" v-model="msg"/>
<p><span>{{newStr}}</span></p>
<button v-on:click="showdata">点击</button>
</div>
<script>
var vm=new Vue({
el:"#app",
data:{
str:"hello",
msg:'world',
},
methods:{
showdata(){
console.log(this.newStr);
}
},
computed:{
newStr:function(){
return this.str+this.msg;
}
}
});
</script>
</body>
</html>
上面的代码第一次运行,计算属性newStr
的依赖值并没有发生改变,却触发了相应的函数,由<p><span>{{newStr}}</span></p>
显示了结果,这是为什么?原因是:
- 在
new Vue()
的时候,vue\src\core\instance\index.js
里面的_init()
初始化各个功能
function Vue (options) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options) //初始化各个功能
}
- 在
_init()
中有这样的一个执行顺序:其中initState()
是在beforeCreate
和created
之间
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm) //初始化
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
- 在initState()做了这些事情:
if (opts.props) initProps(vm, opts.props)//初始化Props
if (opts.methods) initMethods(vm, opts.methods)//初始化methods
if (opts.data) {
initData(vm)} else {
observe(vm._data = {}, true /* asRootData */)}//初始化data
if (opts.computed) initComputed(vm, opts.computed)//初始化computed
- 所以
Props
,methods
,data
和computed
的初始化都是在beforeCreated
和created
之间完成的。
十六.watch与computed的区别
共同点:
watch和computed都是以Vue的依赖追踪机制为基础的,它们都试图处理这样一件事情:当某一个数据(称它为依赖数据)发生变化的时候,所有依赖这个数据的“相关”数据“自动”发生变化,也就是自动调用相关的函数去实现数据的变动。
不同点:
1.watch监控属性依赖的值是单个,computed计算属性依赖的值是多个
2.watch没有缓存,computed提供缓存