赞
踩
对象类型:通过Object.defineProperty()对属性的读取丶修改进行拦截(数据劫持)
数组类型:通过重写更新数组的一系列方法来实现拦截。
1.新增属性,或者删除属性,界面不会更新
2.直接通过下标修改数组,界面不会自动更新
我们来验证一下:
点击按钮的时候往对象里面添加年龄属性,这时候我们看到浏览器的控制台已经打印出了obj.sex为女。说明我们已经往obj对象上面添加了属性。但是页面上并没有发生改变。原因是vue监测不到。
- <template>
- <div>
- <div>
- <h1>姓名:{{obj.name}}</h1>
- <h1>年龄:{{obj.age}}</h1>
- <h1 v-if="obj.sex">性别:{{obj.sex}}</h1>
- </div>
- <div>
- <button @click="addSex">点击添加性别</button>
- </div>
- </div>
- </template>
-
- <script>
- export default {
- data(){
- return {
- obj:{
- name:'孙悟空',
- age:'99',
- }
- }
- },
- methods:{
- addSex(){
- console.log(this.obj.sex)
- this.obj.sex = '女'
- console.log(this.obj.sex)
- }
- }
- }
- </script>
-
- <style scoped>
-
- </style>
解决办法:利用$set
代码:
- <template>
- <div>
- <div>
- <h1>姓名:{{obj.name}}</h1>
- <h1>年龄:{{obj.age}}</h1>
- <h1 v-if="obj.sex">性别:{{obj.sex}}</h1>
- </div>
- <div>
- <button @click="addSex">点击添加性别</button>
- </div>
- </div>
- </template>
-
- <script>
- export default {
- data(){
- return {
- obj:{
- name:'孙悟空',
- age:'99',
- }
- }
- },
- methods:{
- addSex(){
- console.log(this.obj.sex)
- this.$set(this.obj,'sex','女')
- console.log(this.obj.sex)
- }
- }
- }
- </script>
-
- <style scoped>
-
- </style>
效果图:
再次添加一个按钮,点击删除obj下面的name属性。可以看到,页面上面依旧没有发生变化。
代码:
- <template>
- <div>
- <div>
- <h1>姓名:{{obj.name}}</h1>
- <h1>年龄:{{obj.age}}</h1>
- <h1 v-if="obj.sex">性别:{{obj.sex}}</h1>
- </div>
- <div>
- <button @click="addSex">点击添加性别</button>
- </div>
- <br>
- <div>
- <button @click="delAge">点击删除年龄</button>
- </div>
- </div>
- </template>
-
- <script>
- export default {
- data(){
- return {
- obj:{
- name:'孙悟空',
- age:'99',
- }
- }
- },
- methods:{
- addSex(){
- console.log(this.obj.sex)
- this.$set(this.obj,'sex','女')
- console.log(this.obj.sex)
- },
- delAge(){
- console.log(this.obj.age)
- delete this.obj.age
- console.log(this.obj.age)
- }
- }
- }
- </script>
-
- <style scoped>
-
- </style>
效果图:
解决办法:利用$delete
代码:
- <template>
- <div>
- <div>
- <h1>姓名:{{obj.name}}</h1>
- <h1 v-if="obj.age">年龄:{{obj.age}}</h1>
- <h1 v-if="obj.sex">性别:{{obj.sex}}</h1>
- </div>
- <div>
- <button @click="addSex">点击添加性别</button>
- </div>
- <br>
- <div>
- <button @click="delAge">点击删除年龄</button>
- </div>
- </div>
- </template>
-
- <script>
- export default {
- data(){
- return {
- obj:{
- name:'孙悟空',
- age:'99',
- }
- }
- },
- methods:{
- addSex(){
- console.log(this.obj.sex)
- this.$set(this.obj,'sex','女')
- console.log(this.obj.sex)
- },
- delAge(){
- console.log(this.obj.age)
- this.$delete(this.obj,'age')
- console.log(this.obj.age)
- }
- }
- }
- </script>
-
- <style scoped>
-
- </style>
效果图:
接下来说一下数组。如果要改变数组里面的值。利用索引是没有效果的。页面不会发生改变。
代码:
- <template>
- <div>
- <div>
- <h1>姓名:{{obj.name}}</h1>
- <h1 v-if="obj.age">年龄:{{obj.age}}</h1>
- <h1 v-if="obj.sex">性别:{{obj.sex}}</h1>
- <h1>爱好:{{obj.hobby}}</h1>
- </div>
- <div>
- <button @click="addSex">点击添加性别</button>
- </div>
- <br>
- <div>
- <button @click="delAge">点击删除年龄</button>
- </div>
- <br>
- <div>
- <button @click="updateHobby">点击修改爱好</button>
- </div>
- </div>
- </template>
-
- <script>
- export default {
- data(){
- return {
- obj:{
- name:'孙悟空',
- age:'99',
- hobby:['抽烟','烫头'],
- }
- }
- },
- methods:{
- addSex(){
- console.log(this.obj.sex)
- this.$set(this.obj,'sex','女')
- console.log(this.obj.sex)
- },
- delAge(){
- console.log(this.obj.age)
- this.$delete(this.obj,'age')
- console.log(this.obj.age)
- },
- updateHobby(){
- console.log(this.obj.hobby);
- this.obj.hobby[0] = '打妖怪'
- console.log(this.obj.hobby);
- }
- }
- }
- </script>
-
- <style scoped>
-
- </style>
效果图:
解决办法有两种:
1.$set()
2.splice()
代码:
- <template>
- <div>
- <div>
- <h1>姓名:{{obj.name}}</h1>
- <h1 v-if="obj.age">年龄:{{obj.age}}</h1>
- <h1 v-if="obj.sex">性别:{{obj.sex}}</h1>
- <h1>爱好:{{obj.hobby}}</h1>
- </div>
- <div>
- <button @click="addSex">点击添加性别</button>
- </div>
- <br>
- <div>
- <button @click="delAge">点击删除年龄</button>
- </div>
- <br>
- <div>
- <button @click="updateHobby">点击修改爱好</button>
- </div>
- </div>
- </template>
-
- <script>
- export default {
- data(){
- return {
- obj:{
- name:'孙悟空',
- age:'99',
- hobby:['抽烟','烫头'],
- }
- }
- },
- methods:{
- addSex(){
- console.log(this.obj.sex)
- this.$set(this.obj,'sex','女')
- console.log(this.obj.sex)
- },
- delAge(){
- console.log(this.obj.age)
- this.$delete(this.obj,'age')
- console.log(this.obj.age)
- },
- updateHobby(){
- console.log(this.obj.hobby);
- // this.obj.hobby[0] = '打妖怪'
- // this.$set(this.obj.hobby,0,'打妖怪')
- this.obj.hobby.splice(0,1,'打妖怪')
- console.log(this.obj.hobby);
- }
- }
- }
- </script>
-
- <style scoped>
-
- </style>
效果图:
以上就是vue2响应式原理,以及一些问题的解决方案。
安装最新版本脚手架:
npm install -g @vue/cil
这里简单介绍一下setup.
1.它是vue3.0中的一个新配置,值为一个函数
2.组件里面用到的数据,方法,都配置在setup中。(就是data和methods)
3.setup函数有两种返回值。若返回一个对象则对象中的属性,方法,在模板中都可以直接使用。还有一种,返回一个渲染函数,则可以自定义渲染内容。
代码:
- <template>
- <div class="hello">
-
- </div>
- </template>
-
- <script>
- import {h} from 'vue'
- export default {
- name: 'HelloWorld',
- setup() {
-
- return ()=> h('h1','我是vue3')
-
- },
- props: {
- msg: String
- }
- }
- </script>
-
- <!-- Add "scoped" attribute to limit CSS to this component only -->
- <style scoped>
-
- </style>
效果图:
4.使用setup的时候,有以下几点需要注意:
一样是添加两个按钮,分别是添加性别和删除年龄以及修改爱好。在vue3中直接obj.sex和delete obj.age以及数组的索引就可以对obj这个对象进行添加,修改以及删除,并且更新到页面上。这都得益于reactive。
代码:
- <template>
- <div class="hello">
- <div>
- <h1>姓名:{{obj.name}}</h1>
- <h1 v-if="obj.age">年龄:{{obj.age}}</h1>
- <h1 v-if="obj.sex">性别:{{obj.sex}}</h1>
- </div>
- <div>
- <button @click="addSex">点击添加性别</button>
- </div>
- <br>
- <div>
- <button @click="delAge">点击删除年龄</button>
- </div>
- </div>
- </template>
-
- <script>
- import {reactive} from 'vue'
- export default {
- name: 'HelloWorld',
- setup() {
- let obj = reactive({
- name:'孙悟空',
- age:99,
- })
-
- function addSex() {
- obj.sex = '男'
- console.log('我添加了sex');
- console.log(obj.sex)
- }
-
- function delAge() {
- delete obj.age
- console.log('我删除了年龄');
- console.log(obj.age)
- }
-
- return {
- obj,
- addSex,
- delAge
- }
- },
- props: {
- msg: String
- }
- }
- </script>
-
- <!-- Add "scoped" attribute to limit CSS to this component only -->
- <style scoped>
-
- </style>
效果图:
实现原理:
先来讲下Proxy的基本用法:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
-
- </body>
- <script>
- //源数据
- let obj = {
- name:'孙悟空',
- age:100
- }
-
- // 模拟vue3中的响应式
- //Proxy第一个参数是源数据。第二个参数是配置
- const p = new Proxy(obj,{
- // 读取
- get(target,propName){
- console.log(`读取了p的${propName}属性`)
- return target[propName]
- },
- // 修改,新增
- set(target,propName,value){
- console.log(`修改了p的${propName}属性,准备更新界面`)
- return target[propName] = value
- },
- //删除
- deleteProperty(target,propName){
- console.log(`删除了p的${propName}属性,准备更新界面`)
- return delete target[propName]
- }
- })
- </script>
- </html>
在讲一下Reflect(反射的意思),首先定义一个对象obj,obj下面有a,两个属性。一般我们要读取a属性,会用obj.a来实现。其实还有另外一种方式。就是Reflect。Reflect.get(obj,'a')
vue3实现响应式原理就是利用了Reflect
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
-
- </body>
- <script>
- //源数据
- let obj = {
- name:'孙悟空',
- age:100
- }
-
- // 模拟vue3中的响应式
- //Proxy第一个参数是源数据。第二个参数是配置
- const p = new Proxy(obj,{
- // 读取
- get(target,propName){
- console.log(`读取了p的${propName}属性`)
- return Reflect.get(target,propName)
- },
- // 修改,新增
- set(target,propName,value){
- console.log(`修改了p的${propName}属性,准备更新界面`)
- return Reflect.set(target,propName,value)
- },
- //删除
- deleteProperty(target,propName){
- console.log(`删除了p的${propName}属性,准备更新界面`)
- return Reflect.deleteProperty(target,propName)
- }
- })
- </script>
- </html>
总结一下,vue2实现原理主要依靠Object.defineProperty。而vue3则是引用了Proxy来做代理。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。