Vue知识点唠嗑之Composition API

1. setup函数(所有的composition api函数使用的地方)

const app = Vue.createApp({
    template: `
        <div @click="handleClick">name:{{ name }}, age:{{ age }}</div>
    `,

    setup(props, context){
        return {
            name: 'dell',
            handleClick: () => {
                ... ...
            }
        }
    }
})

    setup函数是在created周期实例被完全初始化之前执行的,setup函数中不能用this,因为setup执行的时候,还没有this。有了实例之后,可以在其他地方通过this.$options.setup()来执行,setup中不能通过this来调用其setup外的实例方法,但是setup外部的实例方法(如methods中的方法)可以访问setup中的方法。 

在 setup 中你应该避免使用 this,因为它不会找到组件实例。setup 的调用发生在 data property、computed property 或 methods 被解析之前,所以它们无法在 setup 中被获取。

2. ref、reactive

通过proxy对数据进行封装,当数据变化时,触发模版等内容的更新。

ref用于处理基础类型的数据,将其变成响应式的。

const { ref, reactive } = Vue
const app = Vue.createApp({
    template: `
        <div @click="handleClick">name:{{ name }}</div>
    `,

    setup(props, context){
        let name = ref('dell')
        setTimeout(()=>{
            name.value = 'lee'
        },2000)
        return { name }
    }
})

 使用ref变成响应式数据之后,可以通过变量名.value的方式来赋值,在模版中直接使用变量名来使用。使用.value来赋值的原因主要是变量通过ref之后变为proxy({value:'data'})的方式,所以赋值需要使用value

用reactive处理非基础类型的数据。

在处理对象类型时,由{name: 'dell'}变为proxy({name:'dell'})

const { ref, reactive } = Vue
const app = Vue.createApp({
    template: `
        <div @click="handleClick">name:{{ name.name }}</div>
    `,

    setup(props, context){
        const name = reactive({name :' dell'})
        setTimeout(()=>{
            name.name = 'lee'
        },2000)
        return { name }
    }
})

在处理数组方面数据时,也用reactive。 

const { ref, reactive } = Vue
const app = Vue.createApp({
    template: `
        <div @click="handleClick">name:{{ name[0] }}</div>
    `,

    setup(props, context){
        const name = reactive([123])
        setTimeout(()=>{
            name[0]= 456
        },2000)
        return { name }
    }
})

在Vue3中,可以不用定义了data了,可以直接通过ref和reactive来定义响应式的数据。

3. readonly

const { ref, reactive } = Vue
const app = Vue.createApp({
    template: `
        <div @click="handleClick">name:{{ name.name }}</div>
    `,

    setup(props, context){
        const name = reactive({name :' dell'})
        const nameReadOnly = readonly(name);
        setTimeout(()=>{
            name.name = 'lee'
            nameReadOnly.name = 'lee' // 调用readonlyAPI修饰后的变量是无法修改的
        },2000)
        return { name }
    }
})

4. toRefs && toRef

const { ref, reactive } = Vue
const app = Vue.createApp({
    template: `
        <div @click="handleClick">name:{{ name.name }}</div>
    `,

    setup(props, context){
        const nameObj = reactive({name :' dell', age: 12})
        setTimeout(()=>{
            nameObj.name = 'lee'
        },2000)
        const { name, age } = nameObj //采用这种方式解构之后得到的name变量是没有响应式作用的
        return { name }
    }
})

想解决上面的问题,需要使用toRefs。

const { name, age } = toRefs(nameObj)

如果下述:

const nameObj = reactive({ name:'dell', age:12 }) 
const gender = toRefs(nameObj)

上述的nameObj中没有gender,此时通过解构得出的gender是undefined。如果在程序中出现这种情况,很容易引起程序崩溃,导致空指针异常。解决的办法就是toRef(没有s)

const nameObj = reactive({ name:'dell', age:12 }) 
const gender = toRef(nameObj,'gender')

这样之后,如果对象中没有gender也会赋空值给gender,同时gender还是有响应式特性的,而不是undefined。

5. setup函数的context参数

setup函数会自动传两个值,一个是props参数,还有一个是context参数。

context参数中有三个参数,一个是attrs,一个是slots还有一个是emit。

const { attrs, slots, emit } = context

其中attrs用来接收Non-Props属性,就是父组件通过属性传给子组件,同时子组件还没有props接收的。

const { ref, reactive } = Vue
const app = Vue.createApp({
    template: `
        <child app='app' />
    `
})

app.component('child', {
    template: `
        <div>child</div>
    `,
    setup(props, context){
        const { attrs, slots, emit } = context
        console.log(attrs.app) //此处的app在子组件没有通过props接收,存在attrs中
        return {  }
    }
})

slots这个参数就是用来接收父组件传给子组件的标签中的内容。

const { ref, reactive } = Vue
const app = Vue.createApp({
    template: `
        <child>parents</child>
    `
})

app.component('child', {
    setup(props, context){
        const { h } = Vue
        const { attrs, slots, emit } = context
        return () => h('div', {}, slots.default())
    }
})

在不用composition api的时候, 获得父组件传进来的slot使用的是this.$slots.

最后一个参数emit是用来向外出发事件使用的,在setup函数中,作用和this.$emit差不多。

const { ref, reactive } = Vue
const app = Vue.createApp({
    template: `
        <child @change="handleChange">parents</child>
    `
})

app.component('child', {
    template: `<div @click="handleClick">123123</div>`,
    setup(props, context){
        const { h } = Vue
        const { attrs, slots, emit } = context
        function handleClick() { emit('change'); }
        return { handleClick }
    }
})

6. computed计算属性

const app = Vue.createApp({
    template: `
        <div @click="handleClick">{{count}}--{{countAddFive}}</div>
    `,

    setup(props, context){
        const { ref, computed } = Vue
        const count = ref(0)
        const handleClick = () => { count.value += 1}
        let countAddFive = computed(() => {
            return count.value + 5
        })
        return { count, countAddFive, handleClick }
    }
})



// computed还有一种复杂写法:

let countAddFive = computed({
    get: () => {
        return count.value + 5
    }
    // 写set方法后,对countAddFive进行修改时会执行set方法
    set: (param) => {
        count.value = param - 5
    }
})

 7. watch与watchEffect

const app = Vue.createApp({
    template: `
        <div @click="handleClick">{{count}}--{{countAddFive}}</div>
    `,

    setup(props, context){
        const { ref, watch. toRefs } = Vue
        const nameObj = reactive({name: 'dell'})
        // 使用reactive响应式命令时,要用箭头函数来监听
        watch(()=>nameObj.name, (currentValue, prevValue) => {
            console.log(currentValue, prevValue)
        })
        // watchEffect 是立即执行,没有惰性,immdiate
        // watchEffect函数不需要传递很多参数,只要传递一个回调函数即可
        // watchEffect 自动感知代码依赖,即其函数中的代码涉及的变量发生改变的话,会立即执行回调函数。
        // watchEffect 不能获取改变前的值,只能获得改变后的新值
        watchEffect(() =>{
            console.log(nameObj.name)
        })
        const { name, englishName } = toRefs(nameObj)
        return { name, englishName }
    }
})

// watch 函数还支持监听两个数

watch([()=>nameObj.name,()=>nameObj.englishName],([curName, curEngName],[prevName, prevEngName]) => {
    console.log(curName, prevName, curEngName, prevEngName)
})
// 上述侦听两个数的,其实新值与旧值是一个解构的过程,如果采用下述写法:
watch([()=>nameObj.name,()=>nameObj.englishName],(currentValue,prevValue) => {
    console.log(currentValue, prevValue)
})
// 这时,currentValue和prevValue的值是数组,currentValue是旧值组成的一个数组,prevValue是新值组成的一个数组
// 由于watch是惰性的,所以在一个方法里,对watch监听的多个数据进行改变,watch的回调方法只会执行一次

// 将watch或者watchEffect函数停止侦听的方法可以使用显示调用函数返回值的方式
const stop = watchEffect(() => {
  /* ... */
})

// later
stop()

// watch函数还可以接收第三个参数,主要是
watch(
    [()=>nameObj.name,()=>nameObj.englishName],
    (currentValue,prevValue) => {
        console.log(currentValue, prevValue)
    },
    { imediate: true }
)

8. 生命周期函数的新写法

 可以通过在生命周期钩子函数前面加上“on”来访问组件的生命周期钩子。

选项式 APIHook inside setup触发时机
beforeCreateNot needed*
createdNot needed*
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted
errorCapturedonErrorCaptured
renderTrackedonRenderTracked触发响应式依赖的时候调用,每次渲染页面的时候都会收集一次响应式依赖,在beforeMount和mounted之间。
renderTriggeredonRenderTriggered每次重新渲染被触发的时候。第一次加载页面的时候不会触发,重新刷新页面的时候会触发,触发时机在beforeMount之前
activatedonActivated
deactivatedonDeactivated

在setup函数中,可以通过此方法来访问钩子函数。

export default {
  setup() {
    // 此处就是mounted生命周期函数
    onMounted(() => {
      console.log('Component is mounted!')
    })
  }
}

beforeCreate和created两个声明周期函数是没有composition api的,因为setup函数就是create阶段的函数。

9. provide、inject

const app = Vue.createApp({
    template: `
        <child />
    `,

    setup(props, context){
        const { provide } = Vue
        provide{'name', 'abc'}
        return {  }
    }
})

app.component('child', {
    setup() {
        const { inject } = Vue
        const name = inject('name') // inject('name', 'aaa') 取不到name就赋值’aaa‘
        return { name }
    },
    template: `<div>{{name}}</div>`
})

 子组件如果想修改父组件传过来的数据,根据单向数据流的思想,谁提供数据,谁修改数据。

const app = Vue.createApp({
    template: `
        <child />
    `,

    setup(props, context){
        const { provide, ref, readonly } = Vue
        const name = ref('abc')
        provide('name', readonly(name)) // 传给子组件数据时,可以通过readonly的方式向子组件传值,防止子组件不调用父组件的方法直接修改值
        provide('changeName', (value) => {
            name.value = value
        })
        return {  }
    }
})

app.component('child', {
    setup() {
        const { inject } = Vue
        const name = inject('name') // inject('name', 'aaa') 取不到name就赋值’aaa‘
        const changeName = inject('changeName')
        const handleClick = () => {
            changeName(name)
        }
        return { name, handleClick }
    },
    template: `<div @click="handleClick">{{name}}</div>`
})

10.DOM中的ref

const app = Vue.createApp({
    setup() {
        const { ref } = Vue
        const hello = ref(null)
        return { hello }
    },
    template: `<div ref="hello">hello</div>`
})

// hello.value 是节点的具体内容

在Vue2中,可以向DOM节点上增加ref属性,然后通过this.$refs来定位到相应的节点。在composition api中也可以实现定位DOM。

如上代码,定一个空ref,变量名与DOM节点中ref属性的值一致时,会进行自动绑定到DOM的节点中。

11.composition api 之VueX

import { toRefs } from 'vue';
import { useStore } from 'vuex';
export default {
    setup(){
        const store = useStore()
        const { name } = toRefs(store.state)
        const handleClick = () => {
            store.commit('changeName')
        }
    return { name, handleClick }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值