even

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

1、setup函数

vue3为了方便开发,实现数据,函数的统一管理,开放setup函数,setup函数的运行介于beforeCreated与created函数之间运行, 接收两个函数 props, context, 并且该方法返回一个object对象,导出的变量和函数就可以在template中进行使用

const app = Vue.createApp({
    template: `<div>
        <h1>this is test</h1>
        <button @click='clickEvent'>按钮</button>
    </div>`,
    setup(props, context) {
        const clickEvent = () => {
            console.log(props, context)
        }

        return {
            clickEvent
        }
    }
})

const vm = app.mount('#root')

注意: 因为setup是在created之前,即实例创建之前运行的,所以无法调用this这个对象,也没有办法调用methods里的方法, data里的变量

setup接收两个参数,props与context, props是外部传入到组件中的值 ,注意:不要对props进行解构,这样会失去响应,context中可以得到attrs, 这个attrs区别于props在于,attrs表示该组件未接收的参数,而props表示被接收的参数,emit表示发送机制,slot表示插槽对象

const {getCurrentInstance} = Vue

const myPlugin = (app) => {
    app.config.globalProperties.$say = () => {
        console.log('ok')
    }
}


const app = Vue.createApp({
    template: `<div>
        <h1>this is test</h1>
        <button @click='clickEvent'>change</button>
    </div>`,
    setup(props, {attrs, emit, slots}) {
        const { ctx } = getCurrentInstance()
        const clickEvent = () => {
            console.log(ctx)
            console.log(attrs, emit, slots)
        }

        return {
            clickEvent
        }
    }

})

const vm = app.mount('#root')

 注意:如果需要调用全局vue实例下的方法或值,如vue.config.globalProperties下的方法,需要用到getCurrentInstance来获取

 2、ref与reactive, readonly的使用

在setup函数中,因为得不到this所以没有办法实现data数据响应,为此实现了另外一套响应式方式, ref对String, Number, Boolean类型进行响应,而reactive是实现对object以及array实现响应

const {ref, reactive, readonly} = Vue
const app = Vue.createApp({
    template: `<div>
        <h1>this is test</h1>
        <span>name---{{nick}}</span>
        <button @click='changeName(), changeInfo(), changeJson()'>change</button>
    </div>`,
    setup(props, context) {
        const name = ref('bill')
        const changeName = () => {
            name.value = 'jeere'
        }

        const info = reactive({
            title: 'this is title',
            subTitle: 'this is subTitle'
        })

        const changeInfo = () => {
            info.title = 'this is changeTitle'
        }

        //如果用readonly来修饰ref或者reactive,那么数据相当于冻结,不可改变
        //如修饰ref  readonly(ref('bill'))
        //如修饰reactive  reaadonly(reactive({
        //     title: 'this is title',
        //     subTitle: 'this is subTitle'
        // })

        //也可以用来冻结普通对象
        const json = readonly({fav: 'computed'})

        const changeJson = () => {
            json.fav='game'
            console.log(json)
        }


        return {
            nick: name,
            changeName,
            info,
            changeInfo,
            changeJson
        }
    }
})

const vm = app.mount('#root')

在可以利用react的useState对ref进行二次封装

const useSimgle = (value) => {
    const val = Vue.ref(value);
    setVal = (newVal) => {
        val.value = newVal
    }
    return [val, setVal]
}

const app = Vue.createApp({
    template: `<div>
        <h1>this is test</h1>
        <span>title---{{title}}, name --- {{name}}</span>
        <button @click='clickEvent'>change</button>
    </div>`,
    setup(props, {attrs, emit, slots}) {
        const [title, setTitle] = useSimgle('this is test')
        const [name, setName] = useSimgle('bill')


        const clickEvent = () => {
            setTitle('this is ok');
            // setName('jeere')

        }

        return {
            title,
            name,
            clickEvent
        }
    }

})

const vm = app.mount('#root')

3、toRef与toRefs的使用

 如果对reactive后的数据进行解构出来使用,这时为了实现解构出来的数据的响应,就需要使用toRefs进行修饰,如果原本reactive里的数据没有,那么这时需要对原来没有的字段进行添加,就需要使用到toRef。

const {reactive, toRefs, toRef} = Vue
const app = Vue.createApp({
    template: `<div>
        <h1>this is test</h1>
        <span>name---{{name}}</span>
        <span>age---{{age}}</span>
        <button @click='changeName(), changeAge()'>change</button>
    </div>`,
    setup() {
        const info = reactive({
            name: 'bill'
        });

        const changeName = () => {
            info.name = 'jeere'
        }

        // 进行解构
        const {name} = toRefs(info); // 会对info对象进行递归遍历,把所有项的值都使用proxy进行代理监听

        // 因为原本age是没有值的,所以无需要赋值为undefined,所有无需要解构,返回的是一个ref对象
        const age = toRef(info, 'age') // 会对info中原本没有的值,进行赋值为undefined

        const changeAge = () => {

            info.age = 32
        }

        return {
            name,
            changeName,
            age,
            changeAge
        }
    }

})

const vm = app.mount('#root')

注意:通常来讲,toRefs用的相对会多,但是toRef用的相对会少些,因为,这样不便于数据的管理

 4、setup下的计算属性

 在setup函数下使用computed属性,那么就需要借助vue里的computed函数,这个函数接收两种参数,一种是函数,一种是一个object对象---可以使用get与set方法实现获取与设置

const useSimgle = (value) => {
    const val = Vue.ref(value);
    setVal = (newVal) => {
        val.value = newVal
    }
    return [val, setVal]
}

const { computed } = Vue
const app = Vue.createApp({
    template: `<div>
        <h1>this is test</h1>
        <span>当前数量---{{showCount}}</span>
        <button @click='clickEvent'>change</button>
    </div>`,
    setup(props, {attrs, emit, slots}) {
        const [count, setCount] = useSimgle(0)

        // const showCount = computed(() => {
        //     return count.value + '个'
        // })

        // const clickEvent = () => {
        //     setCount(count.value+1)
        // }
        

        const showCount = computed({
            get() {
                return count.value + '个'
            },
            set(val) {
                setCount(val)
            }
        })

        const clickEvent = () => {
            showCount.value = '123'
        }

        return {
            showCount,
            clickEvent
        }
    }

})

const vm = app.mount('#root')

注意:红色部份是使用传入函数的方式,而蓝色部份是使用传入Object对象的方式

5、setup下的watch以及watchEffect

watch监听非对象,非数组数据

const useSimgle = (value) => {
    const val = Vue.ref(value);
    setVal = (newVal) => {
        val.value = newVal
    }
    return [val, setVal]
}

const { watch, watchEffect } = Vue
const app = Vue.createApp({
    template: `<div>
        <div><span>name---{{name}}</span> | <span>age---{{age}}</span></div>
        <button @click='clickEvent'>change</button>
    </div>`,
    setup(props, {attrs, emit, slots}) {
        const [name, setName] = useSimgle('bill');
        const [age, setAge] = useSimgle(30);

         //单个数据的监听
        // watch(name, (curr, prev) => {
        //     console.log(curr, prev)
        // })

        // watch(age, (curr, prev) => {
        //     console.log(curr, prev)
        // })

        //多个数据的监听
        watch([name, age], (a, b) => {
            console.log(a, b)
        })

        const clickEvent = () => {
            setName('jeere');
            setAge(20);
        }

        return {
            name, age, clickEvent
        }
    }

})

const vm = app.mount('#root')

 监听reactive对象

const { watch, watchEffect, toRefs, reactive } = Vue
const app = Vue.createApp({
    template: `<div>
        <div><span>name---{{name}}</span> | <span>age---{{age}}</span></div>
        <button @click='clickEvent'>change</button>
    </div>`,
    setup(props, {attrs, emit, slots}) {
        const info = reactive({
            name: 'bill',
            age: 30
        })

        //监听单个变量
        // watch(() => info.name, (current, prev) => {
        //     console.log(current, prev)
        // })

        // watch(() => info.age, (current, prev) => {
        //     console.log(current, prev)
        // })

        //监听多个变量
        watch([() => info.name, () => info.age], (current, prev) => {
            console.log(current, prev)
        })

        const {name, age} = toRefs(info);

        const clickEvent = () => {
            info.name = 'jeere';
            info.age = 20;
        }

        return {
            name, age, clickEvent
        }
    }

watch可以配置配置项

const useSimgle = (value) => {
    const val = Vue.ref(value);
    setVal = (newVal) => {
        val.value = newVal
    }
    return [val, setVal]
}

const { watch, watchEffect, toRefs, reactive } = Vue
const app = Vue.createApp({
    template: `<div>
        <button @click='clickEvent'>change</button>
    </div>`,
    setup(props, {attrs, emit, slots}) {
        let info = reactive({
            name: 'bill',
            age: 30,
            props: {
                fav: ['computed']
            }
        })

        watch(info, (cur, prev) => {
            console.log(cur, prev)
        }, {
            immediate: true  //这个是配置是立即执行
        })

        const clickEvent = () => {
            info.props.fav[0] = 'sport'
        }

        return {
            clickEvent
        }
    }

})

const vm = app.mount('#root')

 watchEffect的使用

const { watch, watchEffect, toRefs, reactive } = Vue
const app = Vue.createApp({
    template: `<div>
        <button @click='clickEvent'>change</button>
    </div>`,
    setup(props, {attrs, emit, slots}) {
        let info = reactive({
            name: 'bill',
            age: 30,
            list: ['aaa']
        })

        watchEffect(() => {
            console.log(info.name)
            console.log(info.age)
        })

        const clickEvent = () => {
            info.name='jeere'
            info.age=20
        }

        return {
            clickEvent
        }
    }

})

const vm = app.mount('#root')

注意:watchEffect与watch的区别在于,watchEffect是setup后立即执行,里面接收一个函数参数以及后面的参数为配置项,该方法会感知所调用的变量,实现自动感知刷新

 6、setup函数下的生命钩子函数

以下是生命钩子函数的映射表

beforeCreate -> use setup()
created -> use setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeUnmount -> onBeforeUnmount
unmounted -> onUnmounted
errorCaptured -> onErrorCaptured
renderTracked -> onRenderTracked
renderTriggered -> onRenderTriggered
activated -> onActivated
deactivated -> onDeactivated

 

7、setup中使用provide与inject

在setup函数中使用provide(key, value)表示向子组件或孙组件提供值,子组件接收用const key = inject('key', default value)进行接收

如果provide向下传的是一个ref对象,那么子组件也可以修改对应的值 ,这时为了避免子组件修改,可以使用readonly进行修饰

const useSimgle = (value) => {
    const val = Vue.ref(value);
    setVal = (newVal) => {
        val.value = newVal
    }
    return [val, setVal]
}

const { provide, inject, onBeforeMount, readonly } = Vue


const Item = {
    template: `<div>{{title}} <button @click='clickEvent'>change</button></div>`,
    setup() {
        const title = inject('title', 'default')
        const setTitle = inject('setTitle')
        onBeforeMount(() => {
            console.log(title)
        })

        const clickEvent = () => {
            title.value = 'nono'
        }

        return {
            title,
            clickEvent
        }
    }
}


const app = Vue.createApp({
    template: `<div>
        <Item />
        
    </div>`,
    components: { Item },
    setup(props, {attrs, emit, slots}) {
        const [title, setTitle] = useSimgle('title');

        provide('title', readonly(title))
        provide('setTitle', setTitle)
        
    }

})

const vm = app.mount('#root')

 注意:使用以上方法需要注意一个原则就是vue是单向数据流

 

8、setup函数中使用dom的ref获取节点

在setup中需要获取dom节点也是使用ref但是方法有所不同,具体如下

const { ref } = Vue
const app = Vue.createApp({
    template: `<div>
        <h2 ref='title'>this is title</h2>
        <button @click='clickEvent'>click</button>
    </div>`,
    setup(props, {attrs, emit, slots}) {
        const title = ref(null);

        const clickEvent = () => {
            console.log(title)
        }

        return {
            title,
            clickEvent
        }
        
    }
})

const vm = app.mount('#root')

注意:首先定义一个ref并且赋值为null,然后并且把这个ref对象从setup中return出来,并且在dom上设置ref属性,名称与setup上一致,这样就可以获取这个节点了

 

9、setup与typescript相结合后,props的类型声明

<script lang="ts">
import { defineComponent, PropType, ref } from 'vue'

const PropsType = {
  msg: {
    type: String as PropType<string> // 作typescript的类型匹配
  },
  title: {
    type: Number as PropType<number>, // 可以是普通类型,也可以是一个接口类型的数据
    required: true
  }
} as const // 为了能够精准的匹配,后面需要跟一个as const

export default defineComponent({
  name: 'HelloWorld',
  props: PropsType,
  setup (props) {
    const name = ref<string>('bill')
    return {
      name
    }
  }
})
</script>

注意:经过上面配置后就可以在setup中使用props,并且有提示

 

10、在vue3中配置使用tsx语法

npm install @vue/babel-plugin-jsx -D

安装对应依赖后,需要对babel.config.js进行配置

{
  "plugins": ["@vue/babel-plugin-jsx"]
}

这样就可以愉快的进行tsx的编写了,可以把组件定义为tsx为后缀内容如下

import { defineComponent } from 'vue'

export default defineComponent({
  name: 'HelloWorld',
  setup () {
    return () => {
      return <div>this is test</div>
    }
  }
})

 注意:使用tsx进行组件的编写,配合的样式编写应为vue3-styled-components    npm i vue3-styled-components -D进行安装 ,相应的用法参考网上

posted on 2021-05-22 15:45  even_blogs  阅读(298)  评论(0编辑  收藏  举报