Vue学习笔记②

简介: Vue学习笔记②

计算属性

计算属性将被混入到 Vue 实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。

此处fullname调用了四次,但是1只执行了一次。get的作用:当fullName被读取的时候时,get就会被调用,且返回值就作为fullName的值。

计算属性的结果会被缓存,除非依赖的响应式 property 变化才会重新计算。注意,如果某个依赖 (比如非响应式 property) 在该实例范畴之外,则计算属性是不会被更新的。

get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<divid="root"style="margin: 121px 366px;">
        姓氏<inputtype="text"v-model="firstname"><br/>
<inputtype="text"v-model="nextname"><br/>
        姓名:<span>{{fullname}}</span><br/>
        姓名:<span>{{fullname}}</span><br/>
        姓名:<span>{{fullname}}</span><br/>
        姓名:<span>{{fullname}}</span><br/>
</div>
<script>
        Vue.config.productionTip= false
const vm = new Vue({
el:'#root',
data:{
firstname:'张',
nextname:'三'
        },
computed:{
fullname:{
get(){
console.log(1)
returnthis.firstname + this.nextname
                }
            }
        }
        })
</script>

  • 定义:要用的属性不存在,要通过已有属性计算得来。
  • 原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
  • 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
  • 备注:
    计算属性最终会出现在vm上,直接读取使用即可。
    如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
  • 简写

    PLAINTEXT
1
2
3
4
5
computed:{
    fullname(){
    return this.firstname + this.nextname
    }
}

监视 属性

  1. 当被监视的属性变化时, 回调函数自动调用, 进行相关操作
  2. 监视的属性必须存在,才能进行监视!!
  3. 监视的两种写法:
  • new Vue时传入watch配置
  • 通过vm.$watch监视,传两个参数,一个属性,一个方法('isHot',{handler(){}})

写法一:

JS

1
2
3
4
5
6
7
8
watch:{
isHot:{
immediate:true, //初始化时让handler调用一下
handler(newvalue,oldvalue){
console.log("isHot被更改了",newvalue,oldvalue) 
        }
    }
}

写法二:

JS

1
2
3
4
5
6
7
8
vm.$watch('isHot',
    {
immediate:true,
handler(newvalue){
console.log("isHot被更改啦",newvalue);
        }
    }
)

深度监视

  1. Vue中的watch默认不监测对象内部值的改变(一层)。
  2. 配置deep:true可以监测对象内部值改变(多层)。

备注:

(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!

(2).使用watch时根据数据的具体结构,决定是否采用深度监视。

(3).deep默认为false为了提高开发效率,

JS

1
2
3
4
5
6
7
8
9
vm.$watch('number',
    {
immediate:true,
handler(newvalue){
console.log("number被更改啦",newvalue);
        },
deep:true
    }
)

简写

简写的话,不能够添加deep,immediate属性。

简写一:

JS

1
2
isHot(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue,this)

简写二:

JS

1
2
3
vm.$watch('isHot',function(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue,this)
		})

计算属性和监测属性对比

如下代码证明watch能执行异步操作,但是computed不行,setTimeout必须是箭头函数,this指向所定义的作用域内的Vue实例对象,setTimeout下的回调函数不是Vue实例对象调用的,而是V8浏览器的js引擎调用的,所以不使用箭头函数的话,this指向window。

JS

1
2
3
4
5
6
7
8
9
10
11
watch:{
firstName(val){
setTimeout(()=>{
console.log(this)
this.fullName = val + '-' + this.lastName
		},1000);
	},
lastName(val){
this.fullName = this.firstName + '-' + val
	}
}

computed和watch之间的区别:

  1. computed能完成的功能,watch都可以完成。
  2. watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。

两个重要的小原则:

  1. 所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
  2. 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数这些都是异异步的),最好写成箭头函数,这样this的指向才是vm 或 组件实例对象。

绑定class样式

写法:class=”xxx” xxx可以是字符串、对象、数组。

字符串写法适用于:类名不确定,要动态获取。

对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。

数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。

HTML

1
2
3
4
5
6
7
8
<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 ,比如mood确定但是mood的值是normal,happy,sad不确定-->
<divclass="basic":class="mood" @click="changeMood">{{name}}</div><br/><br/>
<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
<divclass="basic":class="classArr">{{name}}</div><br/><br/>
<!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
<divclass="basic":class="classObj">{{name}}</div><br/><br/>

绑定style样式

:style=”{fontSize: xxx}”其中xxx是动态值。

:style=”[a,b]”其中a、b是样式对象。

PLAINTEXT

1
2
3
4
5
6
7
8
9
data:{
   showin:{
        backgroundColor:'orange',
        fontSize: '50px',
        margin:'auto',
        textAlign:'center'
}
},

条件渲染

HTML

1
2
3
4
5
6
7
8
9
10
<divid="root">
<h2>hello,{{n}}</h2>
<button @click="n++">anniu</button>
<divv-if="n===1">a</div>
<divv-else-if="n===2">b</div>
<divv-else-if="n===3"> c</div>
<!-- <div v-show="n===1">a</div>
  <div v-show="n===2">b</div>
  <div v-show="n===3">c</div> -->
</div>

v-if

写法:

(1).v-if=”表达式”

(2).v-else-if=”表达式”

(3).v-else,else后面无需跟条件。

适用于:切换频率较低的场景。

特点:不展示的DOM元素直接被移除

注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”。

v-show

写法:v-show=”表达式”

适用于:切换频率较高的场景。

特点:不展示的DOM元素不会被移除,vue内部添加style="display :none",仅仅是使用样式隐藏掉

3.备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。

列表渲染

1.用于展示列表数据

2.语法:v-for=”(item, index) in xxx” :key=”yyy”

遍历数组:p是数组中的每个数据,index是当前索引(用的最多的一种)。

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<divid="root">
<ul>
<liv-for="(p,index) in persons":key="p.id">
            {{p.name}}-{{p.age}}
</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
persons:[
            {id:'01',name:'张三',age:'18'},{
id:'02',name:'李四',age:'20'
            },{
id:'03',name:'王五',age:'18'
            }
        ]
     }
 })
</script>

遍历对象:value是值,k是属性

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<ul>
<liv-for="(value,k) of car":key="k">
			{{k}}-{{value}}
</li>
</ul>
<scripttype="text/javascript">
	Vue.config.productionTip = false
new Vue({
el:'#root',
data:{
car:{
name:'奥迪A8',
price:'70万',
color:'黑色'
			},
str:'hello'
		}
	})
</script>

Key的作用和原理

  • 虚拟DOM中key的作用:
    变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
    随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
  • 对比规则:

(1).旧虚拟DOM中找到了与新虚拟DOM相同的key

①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!

②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。

(2).旧虚拟DOM中未找到与新虚拟DOM相同的key,创建新的真实DOM,随后渲染到到页面。

  • 用index作为key可能会引发的问题:
    破坏顺序操作:
    会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低,逆序操作重新生成张三李四王五。

如果结构中还包含输入类的DOM:

会产生错误DOM更新 ==> 界面有问题。

开发中如何选择key?:

1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。

2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,

使用index作为key是没有问题的。

列表过滤

watch监测属性实现

  1. 创建persons属性,创建一个filterper数组为了避免更改原来的数据。
  2. 添加watch属性,返回this.filterper的值,因为空字符串也是包含在字符串中,使用immediate:true让数据能够全部显示。

  3. this.filterper= this.persons.filter((p)=>{return p.name.indexOf(val)!== -1}) ,即是用arr.filter()的回调判断arr.indexOf()的返回值如果为-1就不存在。

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<divid="root">
<ul>
<inputtype="text"v-model="keywords">
<liv-for="(p,index) in filterper":key="p.id">
                {{p.name}}-{{p.age}}
</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
persons:[
            {id:'001',name:'马冬梅',age:19,sex:'女'},
						{id:'002',name:'周冬雨',age:20,sex:'女'},
						{id:'003',name:'周杰伦',age:21,sex:'男'},
						{id:'004',name:'温兆伦',age:22,sex:'男'}
            ],
keywords:'',
filterper:[]
         },
watch:{
keywords:{
immediate:true,
handler(val){
this.filterper= this.persons.filter((p)=>{
return p.name.indexOf(val)!== -1
                   })
                }
             }
         }
     })
</script>

computed计算属性实现

  1. 第一个return是计算属性的返回值,第二个return是filter回调函数的返回值。

JS

1
2
3
4
5
6
7
computed:{
filPerons(){
returnthis.persons.filter((p)=>{
return p.name.indexOf(this.keyWord) !== -1
		})
	}
}

列表排序

JS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    computed:{
filterpers(){
const arr=  this.persons.filter((p)=>{
return p.name.indexOf(this.keywords) !== -1
		})
if(this.sorttype){
                         arr.sort((a,b)=>{
returnthis.sorttype=== 1 ?  a.age -b.age :b.age -a.age
                        })
                    }
return arr
	}
}

Vue监听数据原理

对象

JS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 核心数据响应式方法
functiondefineReactive(obj,key,val){
// val可能还是个对象,需要递归一下
    objserve(val)
Object.defineProperty(obj,key,{
get(){
return val
        },
set(newVal){
if(newVal !== val){
                val = newVal
// 如果改变的是个对象,还需要调用一下
                objserve(newVal)
console.log('set', newVal);
// 在这里已经监听到了数据的变化,后续可以做一些更新视图的操作
            }
        }
    })
}
// 如果一个对象有多个属性,循环调用defineReactive,传入每一个值去进行监听
functionobjserve(obj){
// 判断obj类型
if(Object.prototype.toString.call(obj)!=="[object Object]"){
return
    }
Object.keys(obj).forEach(key =>defineReactive(obj,key,obj[key]))
}
// 如果给对象增加新的属性,是监听不到变化的,那么需要用set方法传入新对象,调用defineReactive手动监听一下
functionset(obj,key,val){
    defineReactive(obj,key,val)
}
const obj = {foo:'foo',baz:{a:1}};
objserve(obj)
obj.foo = '2222'
obj.baz.a = '3333'
obj.baz = {a:10} 
obj.baz.a = 100
set(obj,"dong",'dong')
obj.dong = "dong1"

数组

变更方法

Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

你可以打开控制台,然后对前面例子的 items 数组尝试调用变更方法。比如 example1.items.push({ message: 'Baz' })

Vue.set()

Vue.set( target, propertyName/index, value )

  • 参数
  • {Object | Array} target
  • {string | number} propertyName/index
  • {any} value
  • 返回值:设置的值。
  • 用法
    向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty = 'hi')

注意对象不能是 Vue 实例,或者 Vue 实例的根数据对象。

只能在data的对象中添加Vue.set(),而不能在data上直接添加,也就是不能在vm和vm._data上添加。

JS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const vm = new Vue({
el:'#root',
data:{
school:{
name:'尚硅谷',
address:'北京',
			},
student:{
name:'tom',
age:{
rAge:40,
sAge:29,
				},
friends:[
					{name:'jerry',age:35},
					{name:'tony',age:36}
				]
			}
		},
methods: {
addSex(){
// Vue.set(this.student,'sex','男')
this.$set(this.student,'sex','男')
			}
		}
	})

总结

Vue监视数据的原理:

\1. vue会监视data中所有层次的数据。

\2. 如何监测对象中的数据?

通过setter实现监视,且要在new Vue时就传入要监测的数据。

(1).对象中后追加的属性,Vue默认不做响应式处理

(2).如需给后添加的属性做响应式,请使用如下API:

Vue.set(target,propertyName/index,value) 或

vm.$set(target,propertyName/index,value)

\3. 如何监测数组中的数据?

通过包裹数组更新元素的方法实现,本质就是做了两件事:

(1).调用原生对应的方法对数组进行更新。

(2).重新解析模板,进而更新页面。

4.在Vue修改数组中的某个元素一定要用如下方法:

1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()

2.Vue.set() 或 vm.$set()

特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
methods: {
	addSex(){
		// Vue.set(this.student,'sex','男')
		this.$set(this.student,'sex','男')
	},
	addFriend(){
		this.student.friends.unshift({name:'jack',age:70})
目录
相关文章
|
23天前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
24天前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
26天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
31 1
vue学习第一章
|
26天前
|
JavaScript 前端开发 索引
vue学习第三章
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中的v-bind指令,包括基本使用、动态绑定class及style等,希望能为你的前端学习之路提供帮助。持续关注,更多精彩内容即将呈现!🎉🎉🎉
24 1
vue学习第三章
|
26天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
35 1
vue学习第四章
|
23天前
|
JavaScript 前端开发 开发者
Vue是如何劫持响应式对象的
Vue是如何劫持响应式对象的
21 1
|
23天前
|
JavaScript 前端开发 API
介绍一下Vue中的响应式原理
介绍一下Vue中的响应式原理
27 1
|
26天前
|
JavaScript 前端开发
vue学习第五章
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,正向全栈进发。如果你从我的文章中受益,欢迎关注,我将持续分享更多优质内容。你的支持是我最大的动力!🎉🎉🎉
26 1
|
23天前
|
JavaScript 前端开发 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
23天前
|
存储 JavaScript 前端开发
介绍一下Vue的核心功能
介绍一下Vue的核心功能