• Vue3学习


    // vue2的写法
    new Vue({
      router,
      store,
      render: h => h(App),
    }).$mount('#app')
    
    // vue3的写法
    // 引入的不再是Vue构造函数, 而是一个工厂函数createApp
    import { createApp } from 'vue'
    import App from './App.vue'
    // createApp(App) 创建应用实例对象, 类似于Vue2中的new Vue({}), 但更轻
    createApp(App).mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Vue3组件中的模板结构可以没有根标签

    setup

    setup是所有 Composition API 表演的舞台。
    组件中用到的数据,方法等,均要配置在setup中。
    setup不能是一个async函数,因为返回值不再是return的对象,而是Promise,模板看不到return对象中的属性。
    setup执行的时机在beforeCreate之前。
    setup中的this是undefined。

    import {h} from 'vue'
    export default {
      name: 'App',
      // 此处只是测试一下setup, 暂不考虑响应式的问题
      setup () {
        // 数据
        let name = '张三'
        let age = 18
        // 方法
        function sayHello() {
          alert(`我叫${name},我${age}岁了,你好啊!`)
        }
    
        // 返回对象(常用)
        return {
          name,
          age,
          sayHello
        }
        // 返回函数(渲染函数)
        // return () => h('h1','ShangGuiGu')
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    ref响应式数据

    const xxx = ref(initialValue),创建一个包含响应式数据的引用对象。
    接收的数据可以是基本类型,也可以是对象类型。
    基本类型的数据,响应式依然是靠Object.defineProperty()的get和set完成的。
    对象类型的数据,依靠的是ES6中的Proxy

    import {ref} from 'vue'
    export default {
      name: 'App',
      setup () {
        // 数据(响应式要使用ref包装, 返回一个Ref对象)
        let name = ref('张三')
        let age = ref(18)
        // 方法(修改响应式数据的值)
        function changeData() {
          name.value = '李四'
          age.value = 20
        }
        // 返回对象(常用)
        return {
          name,
          age,
          changeData
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    reactive

    返回一个对象类型的响应式数据,基本类型的数据请使用ref。
    ref也可以包装对象/数组类型数据,内部会通过reactive转为代理对象。
    ref通过Object.defineProperty()的get和set来实现响应式。
    reactive通过Pxoxy实现响应式,使用Reflect操作源对象内部数据。

    // 接收一个对象或数组, 返回一个Proxy对象
    const 代理对象 = reactive(源对象)
    
    • 1
    • 2

    Vue3在处理对象类型响应式的时候,用的是ES6中的Proxy。

    Vue2的响应式原理

    对象类型:通过Object.defineProperty()对属性的读取,修改进行拦截。
    数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)
    存在问题:
    对象新增属性,删除属性界面不会更新。

    <template>
      <div>
        <h1>我是Vue2写的效果</h1>
        <h2>姓名:{{ person.name }}</h2>
        <h2>年龄:{{ person.age }}</h2>
        <h2>性别:{{ person.sex }}</h2>
        <button @click="addSex">添加sex属性</button>
        <button @click="deleteName">删除name属性</button>
      </div>
    </template>
    
    <script>
    export default {
      data () {
        return {
          person: {
            name: '张三',
            age: 18
          }
        }
      },
      methods:{
        addSex () {
          this.person.sex = '女'
        },
        deleteName () {
          delete this.person.name
        }
      }
    }
    </script>
    
    • 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

    解决办法

        addSex () {
          // this.person.sex = '女'
          // 追加
          this.$set(this.person, 'sex', '女')
        },
        deleteName () {
          // delete this.person.name
          // 删除
          this.$delete(this.person, 'name')
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    直接通过下标修改数组,界面不会自动更新。

        updateArray () {
          this.person.hobbies[0] = 'caish'
          // 可以通过以下两种方式之一进行修改
          // this.$set(this.person.hobbies, 0, 'caish')
          // this.person.hobbies.splice(0, 1, 'caish')
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Vue3的响应式原理

    Vue3
    通过Proxy(代理)拦截对象中任意属性的变化。
    通过Reflect(反射)对源对象的属性进行操作。
    模拟Vue2实现响应式

          let person = {
            name: '张三',
            age: 18
          }
          // 模拟Vue2对person实现响应式
          let p = {}
          Object.defineProperty(p, 'name', {
            configurable: true,
            get(){        // 读取时调用
              return person.name
            },
            set(value){   // 修改时调用
              console.log('有人修改了name属性, 我要去更新页面')
              person.name = value
            }
          })
          Object.defineProperty(p, 'age', {
            configurable: true,
            get(){
              return person.age
            },
            set(value){
              console.log('有人修改了age属性, 我要去更新页面')
              person.age = value
            }
          })
    
    • 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

    模拟Vue3实现响应式

    // 源数据
    let person = {
      name: '张三',
      age: 18
    }
    // 返回一个 Proxy 对象
    // 此后对p的任何修改都会作用到person身上
    const p = new Proxy(person, {})
      
    
    // 如果想要捕获修改, 在修改的时候做一些动作
    const p = new Proxy(person, {
      // 读取p某个属性时
      get (target, propName) {
        console.log(`有人读取了p身上的${propName}属性`)
        return target[propName]
      },
      // 修改或新增p某个属性时
      set (target, propName, value) {
        console.log(`有人修改了p身上的${propName}属性,我要去更新页面`)
        target[propName] = value
      },
      // 删除p某个属性时
      deleteProperty (target, propName) {
        console.log(`有人删除了p身上的${propName}属性,我要去更新页面`)
        return delete target[propName]
      }
    })
    
    // 对对象的操作还可以使用Reflect
    Reflect.get(target, propName)
    Reflect.set(target, propName, value)
    Reflect.deleteProperty(target, propName)
    
    • 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

    setup的参数

      props: {
        msg: {
          type: String,
          default: ''
        }
      },
      emits: ['hello'],
      setup (props, context) {
        console.log('-----setup-----', props)   // 组件外部传过来的值,且组件内进行了声明接收
        console.log('-----setup-----', context) // 上下文对象
        console.log('-----setup-----', context.attrs) // 组件外部传过来的值,且组件内没有声明接收(Vue2中的this.$attrs)
        console.log('-----setup-----', context.emit)  // 触发自定义事件的函数(Vue2中的this.$emit)
        console.log('-----setup-----', context.slots) // 收到的插槽内容(Vue2中的this.$slots) 
    
        function test () {
          context.emit('hello', 666)
        }
        return {
          test
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 相关阅读:
    【VisualStudio 】VisualStudio2022 项目模板
    PHP跨站点对接访问请求
    代码随想录算法训练营第23期day10 |232.用栈实现队列、225. 用队列实现栈
    Jetpack组件(二)不推荐使用的DataBinding
    Flink CDC详解
    stable-diffusion-webui sdxl模型代码分析
    交叉验证和网格验证的方法
    1.let和const关键字
    静电消除自动清洁离子风机
    ps2021版神经滤镜能用吗,ps2021没法用神经元滤镜
  • 原文地址:https://blog.csdn.net/qq_53318060/article/details/127681538