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')

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')
  }
}

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
    }
  }
}

reactive

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

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

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>

解决办法

    addSex () {
      // this.person.sex = '女'
      // 追加
      this.$set(this.person, 'sex', '女')
    },
    deleteName () {
      // delete this.person.name
      // 删除
      this.$delete(this.person, 'name')
    }

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

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

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
        }
      })

模拟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)

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
    }
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值