likes
comments
collection
share

插件及CompositionAPI中的Setup函数

作者站长头像
站长
· 阅读数 50

插件

插件要解决的问题

把通用性的功能封装起来

插件的定义和使用

1. 定义插件

const myPlugin = {
    install(app,options){
        // app参数是vue的实例
        // options是app.use的第二个参数"{msg:'Hell world'}"
    }
}

2. 使用插件

app.use(myPlugin,{msg: "Hell world"})

备注

写插件也就是写一个对象,这个对象中必须要有install方法 app.use的第二个参数"{msg:'Hell world'}" 这个方法接收2个参数,appoptionsapp就是vue最外层的实例,optionsapp.use的第二个参数"{msg:'Hell world'}"

敲代码

const myPlugin = {
    install(app, options) {
        // 扩展全局的变量
        app.provide('name', 'LeBron James');
        // 扩展指令
        app.directive('focus',{
            mounted(el){
                el.focus()
            }
        });
        // 扩展mixin
        app.mixin({
            mounted(){
                console.log('mixin');
            }
        });
        // vue底层上拓展方法sayHello
        app.config.globalProperties.$sayHello = 'hello world';
    }
    }
    const app = Vue.createApp({
    template: `
        <my-title />
    `
    })

    app.component('my-title', {
    inject: ['name'],
    mounted(){
        console.log(this.$sayHello);
    },
    template: `
        <div>
            {{name}}
            <input v-focus/>
            </div>
    `
    })
    app.use(myPlugin);

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

运行结果

插件及CompositionAPI中的Setup函数

备注

  • 由于参数app是app实例对象,因此我们就可以使用实例对象上的方法provide提供全局的数据,如果要使用这个数据就要使用inject
  • 为什么会打印2个mixin?因为混入到vue实例中的钩子函数mounted会在每个组件挂载到页面上都执行一次,包括根组件和子组件
app.mixin({
    mounted(){
        console.log('mixin');
    }
})
  • 主流的vue的拓展,包括VueRouter、Vuex都是通过插件plugin去扩展的

实现一个数据校验插件

1. 使用mixin实现

敲代码

const app = Vue.createApp({
    data(){
        return {
            name: 'LeBrow James',
            age: 28
        }
    },
    // 如果年龄不大于25就执行warn中的警告信息
    rules:{
        age:{
            validate: age => age > 25,
            warn: 'too young ,too simple!'
        },
        name:{
            validate: name => name.length >=4,
            warn: 'name too short!'
        }
    },
    template: `
        <div>
            name:{{name}} 

            age: {{age}}
        </div>
    `
})

app.mixin({
    created(){
        for(let key in this.$options.rules){
            const item = this.$options.rules[key]
            this.$watch(key,(value)=>{
                const result = item.validate(value)
                if(!result){
                    alert(item.warn)
                }
            })
        }
    }
})

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

过程

  • 在vue实例中定义一个rules,但是只是这样写vue是识别不不出来的,不会执行rules中的校验逻辑
  • 定义一个mixin,在mixin中定义一个created钩子函数,表示组件初始化完毕后自动执行的函数,在这个钩子函数中可以通过this.this.$options.rules获取到rule
  • 遍历对象rule
  • 使用this.$watch()对vue对象的实例或者说根组件的实例上的内容做监控(rule中的key,比如age),这样每次age发生改变就可以监听到
for(let key in this.$options.rules){
    const item = this.$options.rules[key]
    this.$watch(key,(value)=>{
        const result = item.validate(value)
        if(!result){
            alert(item.warn)
        }
    })
}
  • 代码中的value是监听的key更新了的新的值
  • 监听age的改变,当age发生变化的时候,回调函数会接收到最新的age的值,接下来判断最新的值是否符合校验规则,如果不符合就打印warn中提示信息

2. 将mixin改为pluguin插件的形式

上面把rules这样的校验规则通过mixin就很好的融入到vue的实例中,但是更加推荐使用插件Plugin的方式

敲代码

const app = Vue.createApp({
    data() {
        return {
            name: 'LeBrow James',
            age: 28
        }
    },
    // 如果年龄不大于25就执行warn中的警告信息
    rules: {
        age: {
            validate: age => age > 25,
            warn: 'too young ,too simple!'
        },
        name: {
            validate: name => name.length >= 4,
            warn: 'name too short!'
        }
    },
    template: `
        <div>
            name:{{name}} 

            age: {{age}}
        </div>
    `
})

const validatorPlugin = (app, options) => {
    app.mixin({
        created() {
            for (let key in this.$options.rules) {
                const item = this.$options.rules[key]
                this.$watch(key, (value) => {
                    const result = item.validate(value)
                    if (!result) {
                        alert(item.warn)
                    }
                })
            }
        }
    })
}

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

Plugin对mixin做了封装,写了validatorPlugin一眼就能看出写的是一个校验的插件,如果是用下面的mixin的方式,虽然也能实现同样的功能,但是代码读起来就不能一眼知道在干什么

app.mixin({
    created(){
        for(let key in this.$options.rules){
            const item = this.$options.rules[key]
            this.$watch(key,(value)=>{
                const result = item.validate(value)
                if(!result){
                    alert(item.warn)
                }
            })
        }
    }
})

所以Plugin的方式在可读性和可拓展性比单独的minxin更好

Setup函数

为什么要用Composition

当组件变得越来越复杂的的时候,vue示例中的内容也会越来越长,如vue实例中有data、methods、computed、directives、mixin、template、,当我们想看template想看某个变量相关的逻辑的时候,就要不停的往上翻去data、methods、computed、directives、mixin、等中查找和这个变量相关的逻辑,就是产生混乱和困难的感觉

这样传统的定义data、methods、computed、directives、mixin、template、的方式,就会显得可维护性有些问题

Vue3引入Composition API后就可以解决上面的问题,让代码更加容易的聚合到一起,具备更好的可维护性

插件及CompositionAPI中的Setup函数

Setup函数用法

Setup函数是在钩子函数created实例被完全初始化之前执行的函数

敲代码

const app = Vue.createApp({
    template: `
        <div @click="handleClick">
            {{name}} 
        </div>
    `,
    methods:{
        test(){
            console.log(this.$options.setup());
        }
    },
    mounted() {
        this.test()
    },
    setup(props, context) {
        return {
            name: 'LeBrow James',
            handleClick() {
                alert(123)
            }
        }

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

【备注】

  • setup函数中返回的变量或者函数等,都会暴露在外面,模板中可以直接使用
  • setup中没法使用this,因为Setup函数是在实例被完全初始化之前执行的函数,此时还没有vue实例因此也就没有this
  • setup函数中没法调vue实例上的methods,但是在外部的methods或者生命周期函数中可以调用setup方法,通过this.$options.setup(),如下图打印的this.$options

插件及CompositionAPI中的Setup函数

转载自:https://juejin.cn/post/7244840680384479289
评论
请登录