Vue Composition Api

Vue Composition Api

setup() 函数
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app"></div>
</body>
<script src="https://unpkg.com/vue@next"></script>
<script>
    const app = Vue.createApp({
        template: `<div @click="click">name: {{ name }}</div>`,
        methods: {
            test() {
                alert(this.name) // this.name 可以正常获取 setup 返回出来的值
                console.log(this.$options.setup()) // 也可以通过 $options 手动调用setup
            }
        },
        // created 实例化被完全初始化之前调用
        // props 传入值, context 上下文
        setup(props, context) {
        	// this.test() 报错,由于在初始化之前调用,methods还没初始化
        	console.log(this) // Window 
        	const click = () => {
                alert('click')
            }
            return {
                name: 'Test',
                click
            }
        }
    })
    const vm = app.mount('#app')
</script>

</html>
ref & reactive & toRefs & readonly & toRef
const app = Vue.createApp({
    template: `<div @click="click">{{ name }}</div>`,
    setup() {
        let name = 'test'; // name 不具备数据绑定
        const click = () => { // 更新 name 页面不改变
            name = '123'
        }
        return {
            name,
            click
        }
    }
})
// ref
const app = Vue.createApp({
    template: `<div @click="click">{{ name }}</div>`,// 模板渲染会自动获取value的值
    setup() {
        let { ref } = Vue // ref 主要用于原始数据的数据绑定
        let name = ref('test');  // 使用 ref 会将数据变成 proxy({ value: 'test' }) 
        const click = () => { 
            name.value = '123' // 需要通过 .value 的形式来改变内部对值
        }
        return {
            name,
            click
        }
    }
})
// reactive
const app = Vue.createApp({
    template: `<div @click="click">{{ obj.name }}</div>`,
    setup() {
        let { reactive } = Vue // reactive 主要用于引用数据的数据绑定
        const obj = reactive({ name: 'test' }) // 使用 reactive 会将数据变成 proxy({ name: 'test' })
        const click = () => {
            obj.name = '123' // 可以直接获取值
        }
        return {
            obj,
            click
        }
    }
})
// reactive 结构
const app = Vue.createApp({
    template: `<div @click="click">{{ name }}</div>`,
    setup() {
        let { reactive, toRefs } = Vue
        const obj = reactive({ name: 'test' })
        // let { name } = obj 直接结构会失去绑定
        let { name } = toRefs(obj) // 会把 reactive 封装成 { name: proxy({ value: 'test' }) }
        const click = () => {
            name.value = '123'
        }
        return {
            name,
            click
        }
    }
})
// readonly
const app = Vue.createApp({
    template: `<div @click="click">{{ copyObj.name }}</div>`,
    setup() {
        let { reactive, readonly } = Vue
        const obj = reactive({ name: 'test' })
        const copyObj = readonly(obj) // 只读复制
        const click = () => {
            copyObj.name = '123' // 警告无法修改
        }
        return {
            obj,
            copyObj,
            click
        }
    }
})
// toRef
const app = Vue.createApp({
    template: `<div >{{ test }}</div>`,
    setup() {
        let { reactive, toRefs } = Vue
        const obj = reactive({ name: 'test' })
        let { test } = toRefs(obj) // 使用 toRefs 获取对象内部没有的值
        console.log(test) // undefined 没有进行 proxy 封装
        let test1 = toRef(obj, 'test') // 使用 toRef 获取对象内部没有的值
        console.log(test1) // proxy{ value: undefined } 可以正常使用, 不推荐,可以直接在对象中定义 test: nudefined 即可
        return {
            test
        }
    }
})
props & context
const app = Vue.createApp({
      template: `<child test="test" p="p"><div>father</div></child>`   
    })
app.component('child',{
    mounted(){
        console.log('mounted:slots', this.$slots)
        console.log('mounted:emit', this.$emit)
    },
    props: {
        p: {
            type: String,
            default: ''
        }
    },
    setup(props, context) {
        console.log(props.p) // p 同原来的 props
        let { attrs, slots, emit } = context
        console.log(attrs) // proxy { test: "test" } none-props: 没有被 props 接收的属性
        console.log(slots) // slots 等价与原来的 this.$slots
        console.log(emit) // slots 等价与原来的 this.$emit
        // 执行 .default() 函数会返回一个对应的虚拟 DOM 列表
        let vm = slots.default()
        // 可以使用渲染函数进行渲染
        let { h } = Vue
        // 不使用 template, 使用渲染函数返回,需要以函数的形式
        // return h('div', {} ,vm) 报错
        // setup() should not return VNodes directly - return a render function instead. 
        return () => h('div', {} ,vm) // h(标签, 属性, 内容)
    }
})
const vm = app.mount('#app')
computed
const app = Vue.createApp({
    template: `<div @click="add">{{ count }}:{{ countComputed }}</div>`,
    setup(props, context) {
        let { ref, computed } = Vue
        let count = ref(0)
        let add = () => {
            count.value++
        }
        let countComputed = computed({ // ComputedRefImpl { value ... }
            get() {
                return count.value + 5
            },
            set(val) {
                count.value = val
            }
        })
        console.log(countComputed.value) // 5
        return {
            count,
            countComputed,
            add
        }
    }
})
watch & watchEffect
// watch
const app = Vue.createApp({
   	template: `
        <div>
        <input v-model="w"/>
        <div>{{ w1 }}</div>
        </div>
    `,
    setup(props, context) {
        let { ref, watch } = Vue
        let w = ref('')
        let w1 = ref('')
        // 惰性,需要数据改变才会触发
        // 可以获得改变前、后的值
        let stop = watch(w, (newW,oldW) => {
            w1.value = `${newW}${oldW}`
        },{
            // deep: true 监听对象内部值的变化
            // immediate: true 立即触回调
            // ...
        })
        // 通过调用 stop() 可以取消监听 watchEffect 同理
        return {
            w,w1
        }
    }
})
// 监听多个
const app = Vue.createApp({
    template: `
    <div>
    <input v-model="w"/>
    <input v-model="w2"/>
    <div>{{ w1 }}</div>
    </div>
    `,
    setup(props, context) {
        let { ref, watch } = Vue
        let w = ref('')
        let w1 = ref('')
        let w2 = ref('')
        watch([w, w2], ([nw, nw2],[ow,ow2]) => { // 可以使用数组进行监听,取到的值也为数组
            w1.value = `${nw}${nw2}`
        })
        return {
            w, w1, w2
        }
    }
})
// 监听对象内部的值
const app = Vue.createApp({
    template: `
    <div>
    <input v-model="obj.w"/>
    <div>{{ obj.w1 }}</div>
    </div>
    `,
    setup(props, context) {
        let { reactive, watch } = Vue
        let obj = reactive({ w: 'w', w1: '' })
        watch(() => obj.w,(n, o) => { // 监听对象内部的值需要使用函数
            obj.w1 = `${n}${o}`
        })
        return {
            obj
        }
    }
})
// watchEffect
const app = Vue.createApp({
    template: `
     <div>
        <div @click="b1 = !b1">{{b1}}</div>
        <div @click="obj.b2 = !obj.b2">{{obj.b2}}</div>
        <div v-show="show">show</div>
      </div>
    `,
    setup(props, context) {
        let { watchEffect, ref, reactive } = Vue
        let b1 = ref(false)
        let obj = reactive({
          b2: false
        })
        let show = ref(false)
        // 立即执行,没有惰性
        // 会自动感知依赖的值(ref, reactive),不需要像 watch 一样传递监听的值,没有过多参数,主要就一个回调函数
        // 不能获取旧数据
        watchEffect(() => {
            show.value = b1.value && obj.b2 // 可以方便的进行监听判断
        })
        return {
            b1, b2 , show
        }
    }
})
生命周期函数

setup() 介于 beforeCreate、created 直接 beforeCreate、created的方法体可以直接写在 setup() 内部

选项式 APIsetup() 对应方法
beforeCreate
created
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted
errorCapturedonErrorCaptured
renderTrackedonRenderTracked
renderTriggeredonRenderTriggered

使用方法

const app = Vue.createApp({
    template: `
    <div>
    <div @click="b1 = !b1">{{ b1 }}</div>
    </div>
    `,
    setup(props, context) {
        let { onRenderTracked, onRenderTriggered, ref } = Vue
        // 每次渲染后重新收集响应式依赖
        onRenderTracked(({ key, target, type }) => {
            console.log({ key, target, type })
            console.log('onRenderTracked')
        })
        // 每次触发页面重新渲染时自动执行
        onRenderTriggered(() => {
            console.log('onRenderTriggered')
        })
        let b1 = ref(false)
        return { 
            b1
        }
    }
})
provide & inject
const app = Vue.createApp({
    template: `
    <div>
    <child></child>
    </div>
    `,
    setup(props, context) {
        let { ref, provide, readonly } = Vue
        let name = ref('test')
        provide('name', readonly(name)) // 使用 readonly 反正组件内部直接通过 .value 修改值 提供 name
        provide('changeName', (value) => { // 提供 changeName(value)
            name.value = value
        })
    }
})
app.component('child', {
    template: `
<div @click="change">{{ name }}</div>
`,
    setup(props, context) {
        let { inject } = Vue
        let name = inject('name', '') // 接收 name
        let changeName = inject('changeName') // 接收 changeName
        let change = () => {
            // name.value = 'aaa' 警告 无法修改 readonly 值
            changeName('abc') // 通过获取修改方法进行修改
        }
        return { 
            name,
            change
        }
    }
})
DOM ref
const app = Vue.createApp({
    template: `
    <div>
    <!-- 设置 ref="test" -->
    <div ref="test">test</div>
    </div>
    `,
    setup(props, context) {
        let { ref, onMounted } = Vue
        let test = ref(null) // 配置对应的变量 ref="test"
        onMounted(() => {
            console.log(test.value) // 通过 .value 可以获取到 DOM
        }) 
        return {
            test // 返回出去
        }
    }
})
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值