vue——计算属性和侦听器

vue

vue——计算属性和侦听器

一、计算属性(data中的相关数据)

  模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:

<body>

<div id="computed">

<div>

{{msg.split('').reverse().join('')}}

</div>

</div>

<script type="text/javascript" src="./vue.js"></script>

<script type="text/javascript">

var com = new Vue({

el: "#computed",

data:{

msg:"Hello World"

}

})

</script>

</body>

  在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message 的翻转字符串。显示效果如下:

  当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。

  所以,对于任何复杂逻辑,都应当使用计算属性。

<body>

<div id="computed">

<div>

<!--{{msg.split('').reverse().join('')}}-->

{{reverseStr}}

</div>

<button @click="clickHandler">修改</button>

</div>

<script type="text/javascript" src="./vue.js"></script>

<script type="text/javascript">

var com = new Vue({

el: "#computed",

data:{

msg:"Hello World"

},

methods:{

clickHandler(){

this.msg = 'Hello Luffy'

}

},

computed:{ // 计算属性: watch监听

// 默认只有getter方法

reverseStr(){

return this.msg.split('').reverse().join('');

}

}

})

</script>

</body>

  当我点击按钮的时候更改了当前的数据,同时h3和p标签中数据也随时改变。

(1)为什么会这样呢?

  因为Vue知道com.currentMsg依赖与com.msg,因此当com.msg发生改变时,所有依赖com.currentMsg的绑定也会更新。而且最妙的是我们已经以声明的方式创建了这种依赖关系。:计算属性的getter函数是没有副作用的,这使它更易于测试和理解。

(2)同样的上面操作,我们不用computed声明的计算属性方法,而仅仅通过methods中声明的方法也能完成上面的效果,那么为什么又要使用computed方法呢?

  因为计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要msg还没有发生变化,多次访问currentMsg计算属性会立刻返回之前计算的结果,而不比再次执行函数。同样的。每当触发重新渲染时,调用方法将总会执行函数。

(3)我们为什么需要缓存?

  假设我们有一个性能开销比较大的的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A 。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。

1、计算属性之computed

<body>

<div id="app">

<h4>{{alexDesc}}</h4>

<button @click="clickHandler">修改</button>

</div>

<script type="text/javascript" src="./vue.js"></script>

<script type="text/javascript">

new Vue({

el:'#app',

template:'',

data(){

return {

myName:'alex',

age:18

}

},

methods:{

clickHandler(){

this.myName='WUSIR';

this.age=28;

}

},

computed:{

alexDesc:function () {

var str = `${this.myName}它的年龄是${this.age}

岁了可以去大保健了`;

// 默认只有getter方法

return str;

}

}

})

</script>

</body>

(1)页面显示效果

(2)按钮点击后显示效果

   

(3)分析程序

  var str = `${this.myName}它的年龄是${this.age}   在实时监听data中声明的数据的变化。

  点击事件,对数据属性进行修改,由于计算属性的实时监听,就察觉了数据的修改。

  由于计算属性方法用模板插值关联,因此alexDesc函数的返回值就直接显示在模板中了。

2、计算属性的setter方法

  计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter 。

<body>

<div id="app">

<h4>{{alexDesc}}</h4>

<button @click="clickHandler">修改</button>

</div>

<script type="text/javascript" src="./vue.js"></script>

<script type="text/javascript">

new Vue({

el:'#app',

template:'',

data(){

return {

myName:'alex',

age:18

}

},

methods:{

clickHandler(){

console.log(this.alexDesc);

this.alexDesc = 'ALEX IS SB!!!';

}

},

computed:{

alexDesc:{

// setter

set:function (newValue) {

console.log(newValue);

this.myName = newValue;

},

// getter

get:function(){

var str = `${this.myName}它的年龄是${this.age}

岁了可以去大保健了`;

return str;

}

}

}

})

</script>

</body>

(1)计算属性setter固定编写套路

computed:{

alexDesc:{

// setter

set:function (newValue) {

console.log(newValue);

this.myName = newValue;

},

// getter

get:function(){

var str = `${this.myName}它的年龄是${this.age}

岁了可以去大保健了`;

return str;

}

}

}

(2)显示效果

(3)点击事件传值给计算属性setter方法

   

3、进一步理解setter用途

<body>

<div id="app">

<input type="text" v-model="alexDesc">

<h4>{{alexDesc}}</h4>

<!--<button @click="clickHandler">修改</button>-->

</div>

<script type="text/javascript" src="./vue.js"></script>

<script type="text/javascript">

new Vue({

el:'#app',

template:'',

data(){

return {

myName:'',

}

},

computed:{

alexDesc:{

// setter,给myName赋新值

set:function (newValue) {

this.myName = newValue;

},

// getter,实时监听myName属性的变化

get:function(){

return this.myName;

}

}

}

})

</script>

</body>

4、计算属性案例——音乐播放器

(1)构建音乐播放器页面

<body>

<div id="music">

<audio src="../static/那吾克热-水滴石穿.mp3" controls=""

autoplay=""></audio>

<ul>

<li v-for="(item, index) in musics">

<h3>{{item.id}}--歌曲为:{{item.name}}</h3>

<p>歌手:{{item.author}}</p>

</li>

</ul>

</div>

<script type="text/javascript" src="./vue.js"></script>

<script type="text/javascript">

var musicData = [{

id:1,

name:"那吾克热-水滴石穿",

author:"那吾克热",

songSrc:'../static/那吾克热-水滴石穿.mp3'

},

{

id:2,

name:"Inna-10 Minutes",

author:"Inna",

songSrc:'../static/10 Minutes.mp3'

},

{

id:3,

name:"Devotion-My_Prayer",

author:"Devotion",

songSrc:'../static/My_Prayer.mp3'

}

];

new Vue({

el:'#music',

data(){

return {

musics:musicData

}

},

template:''

});

</script>

</body>

  显示效果:

(2)计算属性监听切换播放歌曲

<body>

<div id="music">

<audio v-bind:src="currentSrc" controls=""

autoplay=""></audio>

<ul>

<li v-for="(item, index) in musics" @click="clickHandler(index)"> <!--给每个li绑定点击事件-->

<h3>{{item.id}}--歌曲为:{{item.name}}</h3>

<p>歌手:{{item.author}}</p>

</li>

</ul>

</div>

<script type="text/javascript" src="./vue.js"></script>

<script type="text/javascript">

var musicData = [{

id:1,

name:"那吾克热-水滴石穿",

author:"那吾克热",

songSrc:'../static/那吾克热-水滴石穿.mp3'

},

{

id:2,

name:"Inna-10 Minutes",

author:"Inna",

songSrc:'../static/10 Minutes.mp3'

},

{

id:3,

name:"Devotion-My_Prayer",

author:"Devotion",

songSrc:'../static/My_Prayer.mp3'

}

];

new Vue({

el:'#music',

data(){

return {

musics:musicData,

musicSrc:'../static/那吾克热-水滴石穿.mp3'

}

},

methods:{

clickHandler(index){ // 声明点击事件

// alert(index);

this.musicSrc = this.musics[index].songSrc; // 获取数组musics中对应index的歌曲资源

}

},

computed:{

currentSrc(){ // 实时监听musicSrc

return this.musicSrc;

}

},

template:''

});

</script>

</body>

(3)不再监听musicSrc,改为监听musics数组

<body>

<div id="music">

<audio v-bind:src="currentSrc" controls=""

autoplay=""></audio>

<ul>

<li v-for="(item, index) in musics" @click="clickHandler(index)"> <!--给每个li绑定点击事件-->

<h3>{{item.id}}--歌曲为:{{item.name}}</h3>

<p>歌手:{{item.author}}</p>

</li>

</ul>

</div>

<script type="text/javascript" src="./vue.js"></script>

<script type="text/javascript">

var musicData = [{

id:1,

name:"那吾克热-水滴石穿",

author:"那吾克热",

songSrc:'../static/那吾克热-水滴石穿.mp3'

},

{

id:2,

name:"Inna-10 Minutes",

author:"Inna",

songSrc:'../static/10 Minutes.mp3'

},

{

id:3,

name:"Devotion-My_Prayer",

author:"Devotion",

songSrc:'../static/My_Prayer.mp3'

}

];

new Vue({

el:'#music',

data(){

return {

musics:musicData,

currentIndex:0

// musicSrc:'../static/那吾克热-水滴石穿.mp3'

}

},

methods:{

clickHandler(index){ // 声明点击事件

// alert(index);

this.currentIndex = index; // 点击事件修改index

}

},

computed:{

currentSrc(){ // 实时监听了两个属性:musics、currentIndex

return this.musics[this.currentIndex].songSrc // 修改的index会导致获取的歌曲资源不同

}

},

template:''

});

</script>

</body>

(4)添加点选切换样式

<head>

<meta charset="UTF-8">

<title>Title</title>

<style type="text/css">

*{

padding: 0;

margin: 0;

}

ul{

list-style: none;

}

ul li{

margin: 30px 20px;

padding: 10px;

}

ul li.active{

background-color: #20FFFF;

}

</style>

</head>

<body>

<div id="music">

<audio v-bind:src="currentSrc" controls=""

autoplay=""></audio>

<ul>

<li v-for="(item, index) in musics" @click="clickHandler(index)"

:class="{active:currentIndex==index}"> <!--给当前歌曲li添加class=active-->

<h3>{{item.id}}--歌曲为:{{item.name}}</h3>

<p>歌手:{{item.author}}</p>

</li>

</ul>

</div>

<script type="text/javascript" src="./vue.js"></script>

<script type="text/javascript">

var musicData = [{

id:1,

name:"那吾克热-水滴石穿",

author:"那吾克热",

songSrc:'../static/那吾克热-水滴石穿.mp3'

},

{

id:2,

name:"Inna-10 Minutes",

author:"Inna",

songSrc:'../static/10 Minutes.mp3'

},

{

id:3,

name:"Devotion-My_Prayer",

author:"Devotion",

songSrc:'../static/My_Prayer.mp3'

}

];

new Vue({

el:'#music',

data(){

return {

musics:musicData,

currentIndex:0

// musicSrc:'../static/那吾克热-水滴石穿.mp3'

}

},

methods:{

clickHandler(index){ // 声明点击事件

// alert(index);

this.currentIndex = index; // 点击事件修改index

}

},

computed:{

currentSrc(){ // 实时监听了两个属性:musics、currentIndex

return this.musics[this.currentIndex].songSrc // 修改的index会导致获取的歌曲资源不同

}

},

template:''

});

</script>

</body>

  点击事件的时候修改currentIndex,自己的li标签监听currentIndex,修改为对应的标签,添加class=active,显示效果如下所示:

二、侦听器(watch)

  虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。因此Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

1、简单侦听器示例

<body>

<div id="app">

<input type="text" v-model="myName">

<h3>{{myName}}</h3>

</div>

<script type="text/javascript" src="./vue.js"></script>

<script type="text/javascript">

new Vue({

el:'#app',

template:'',

data(){

return {

myName:''

}

},

watch:{

// 检测单个属性 命令式的

myName:function (value) { // 通过watch来监听myName属性

console.log(value);

if (value === 'alex'){

console.log(value+"是sb");

}

}

}

})

</script>

</body>

  通过watch来监听myName属性的变化,当属性值为alex时,控制台打印alex是sb。

2、结合其他属性一起检测

<body>

<div id="app">

<input type="text" v-model="myName">

<h3>{{myName}}</h3>

</div>

<script type="text/javascript" src="./vue.js"></script>

<script type="text/javascript">

new Vue({

el:'#app',

template:'',

data(){

return {

myName:'',

firstName:'wuSir'

}

},

watch:{

// 检测单个属性 命令式的

myName:function (value) { // 通过watch来监听myName属性

console.log(value);

if (value === 'alex'){

console.log(value + " " + this.firstName +"是sb");

}

}

}

})

</script>

</body>

  显示效果:

3、数据随其它数据变动而变动监听

  添加按钮,并给按钮绑定事件:

<body>

<div id="app">

<input type="text" v-model="myName">

<h3>{{myName}}</h3>

<button @click="clickHandler">修改</button>

</div>

<script type="text/javascript" src="./vue.js"></script>

<script type="text/javascript">

new Vue({

el:'#app',

template:'',

data(){

return {

myName:'',

firstName:'wuSir'

}

},

methods:{

clickHandler(){

this.myName = '日天';

}

},

watch:{

// 检测单个属性 命令式的

myName:function (value) { // 通过watch来监听myName属性

console.log(value);

if (value === 'alex'){

console.log(value + " " + this.firstName +"是sb");

}

}

}

})

</script>

</body>

  点击按钮显示效果如下:

  可以看到控制台也输出“日天”,这个输出的语句是来自:console.log(value);

  如果将事件改为:this.myName = 'alex'; 则还会触发检测的if判断,显示效果如下所示:

 三、总结对比

  侦听器:侦听的是单个属性;计算属性:侦听多个属性; 

  Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。

posted @ 2018-09-11 00:21 休耕 阅读(...) 评论(...) 编辑 收藏

以上是 vue——计算属性和侦听器 的全部内容, 来源链接: utcz.com/z/376830.html

回到顶部