美文网首页Vue.js开发技巧一起来看vue3Vue技术
【vue3.0】13.0 Composition API(一)—

【vue3.0】13.0 Composition API(一)—

作者: bobokaka | 来源:发表于2021-07-06 00:05 被阅读0次

    vue3的特点

    更多的API特性
    体积更小、速度更快
    解决遗留问题(比如对TS不友好、代码组件逻辑复用)

    createApp表示创建一个Vue应用,传入的参数表示这个应用最外层的组件应该如何展示。

      // createApp 表示创建一个 Vue 应用, 存储到 app 变量中
      // 传入的参数表示,这个应用最外层的组件,应该如何展示
      // MVVM 设计模式,M -> Model 数据, V -> View 视图, VM -> ViewModel 视图数据连接层
      const app = Vue.createApp({
        data() {
          return {
            message: 'hello world'
          }
        },
        template: "<div>{{message}}</div>"
      });
      // vm 代表的就是 Vue 应用的根组件
      const vm = app.mount('#root');
    

    VUE3.0 新特性 Composition API

    当一个组件越来越大的时候,会出现如下的代码结构:

    <script>
    
      const app = Vue.createApp({
        data(){
            return{
                name:'dell',
                age:23
            }
        },
        methods: {
          test() {
          },
          setName(){
              
          },
          setAge(){
              
          },
          a(){
              
          },
          b(){
              
          }
        },
        computed:{
            
        },
        directives:{},
        mixin:[],
        mounted() {
        },
        template:`
        <div>name:{{name}},age:{{age}}</div>`
      });
      const vm = app.mount('#root');
    </script>
    

    当一个组件变得越来越复杂的时候。会发现一个问题。当我们去看模板(template)中,name相关的逻辑的时候,会看到各个地方都涉及到这个变量的修改,维护性会很复杂。

    这就有了Composition API。
    Composition API涉及到需要了解一个重要的函数setup

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>lesson 34</title>
      <script src="https://unpkg.com/vue@next"></script>
    </head>
    <body>
      <div id="root"></div>
    </body>
    <script>
      // 对数据做校验的插件
      const app = Vue.createApp({
        template:`<div @click="handClick">name:{{name}},age:{{age}}</div>`
        ,
        // created 实例被完全初始化之前
        setup(props, context) {
            //props:外部组件传递进来的一些内容
            //context:上下文,代码中讲解
          return {
             //setup最后必须有一个return值
             //handleClick:可见 setup中使用的内容会暴露在外部,比如函数可以直接调用,参数可以直接赋值。
            name: 'dell',
            handleClick: () => {
              alert(123)
            }
          }
        }
      });
      const vm = app.mount('#root');
    </script>
    </html>
    

    进一步分析。

    <script>
      // 对数据做校验的插件
      const app = Vue.createApp({
        template:`<div @click="handClick">name:{{name}},age:{{age}}</div>`
        ,
        method:{
            test(){
                alert('test')
            }
        },
        // created 实例被完全初始化之前
        setup(props, context) {
            this.test();
            //props:外部组件传递进来的一些内容
            //context:上下文,代码中讲解
          return {
             //setup最后必须有一个return值
             //handleClick:可见 setup中使用的内容会暴露在外部,比如函数可以直接调用,参数可以直接赋值。
            name: 'dell',
            handleClick: () => {
              alert(123)
            }
          }
        }
      });
      const vm = app.mount('#root');
    </script>
    

    如上代码是执行报错的。有了setup就不需要用到this这样的语法了,method方法有更好的Composition API写法。
    setup没法调用外部的方法、函数、钩子函数等,比如methods、mounted。setup内部也没有this可以使用。

    <script>
      // 对数据做校验的插件
      const app = Vue.createApp({
        template:`<div @click="handClick">name:{{name}},age:{{age}}</div>`
        ,
        method:{
            test(){
                console.log(this.$options.setup())
            }
        },
        mounted(){this.test()},
        // created 实例被完全初始化之前
        setup(props, context) {
            this.test();
            //props:外部组件传递进来的一些内容
            //context:上下文,代码中讲解
          return {
             //setup最后必须有一个return值
             //handleClick:可见 setup中使用的内容会暴露在外部,比如函数可以直接调用,参数可以直接赋值。
            name: 'dell',
            handleClick: () => {
              alert(123)
            }
          }
        }
      });
      const vm = app.mount('#root');
    </script>
    

    ref, reactive 响应式的引用

    如下代码:

    <script>
      // ref, reactive 响应式的引用
      // 原理,通过 proxy 对数据进行封装,当数据变化时,触发模版等内容的更新
      // ref 处理基础类型的数据
      // reactive 处理非基础类型的数据
      const app = Vue.createApp({
        template: `
          <div>{{name}}</div>
        `,
        setup(props, context) {
          return { name:'dell' }
        }
      });
      const vm = app.mount('#root');
    </script>
    

    修改代码:

        <script>
            const app = Vue.createApp({
                template: `
          <div>{{name}}</div>
        `,
                setup(props, context) {
                    let name = 'dell';
                    setTimeout(() => {
                        name = 'lee'
                    }, 2000)
                    return {
                        name: 'dell'
                    }
                }
            });
            const vm = app.mount('#root');
        </script>
    

    发现及时name变了,模板也不会改变。
    Composition API中有办法将普通的变量改成响应式的变量。

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

    这时候需要ref,这是vue提供给我们的一个语法。

        <script>
            const app = Vue.createApp({
                template: `
          <div>{{name}}</div>
        `,
                setup(props, context) {
                    const { ref } = Vue;
                    // proxy , 'dell' 变成 proxy({value: 'dell'}) 这样的一个响应式引用
                    let name = ref('dell');
                    setTimeout(() => {
                        name.value = 'lee'
                    }, 2000)
                    return {
                        name: 'dell'
                    }
                }
            });
            const vm = app.mount('#root');
        </script>
    

    ref适合处理基础数据类型,像对象{}、数组[],就不方便处理。
    除此之外,可以有如下写法,通过reactive:

        <script>
            const app = Vue.createApp({
                template: `
          <div>{{nameObj.name}}</div>
        `,
                setup(props, context) {
                     const { reactive} = Vue;
                    // reactive 处理非基础类型的数据
                    //proxy , { name: 'dell'} 变成 proxy({ name: 'dell'}) 这样的一个响应式引用
                    let nameObj = reactive({name:'dell'});
                    setTimeout(() => {
                        nameObj.name = 'lee'
                    }, 2000)
                    return {
                        nameObj
                    }
                }
            });
            const vm = app.mount('#root');
        </script>
    

    由以上可见,setup中通过ref, reactive彻底转换了data的作用。

    readonly

    如果一个参数我们定义为只读状态,vue提供readonly函数。

    <script>
      const app = Vue.createApp({
        template: `
          <div>{{nameObj,name}}</div>
        `,
        setup(props, context) {
    
          const { reactive, readonly } = Vue;
          const nameObj = reactive({name: 'dell', age: 28});
        
          const copyNameObj =readonly(nameObj);
          setTimeout(() => {
            nameObj.name = 'lee'
            copyNameObj.name = 'laa'
          }, 2000)
           
          return { nameObj ,copyNameObj}
        }
      });
      const vm = app.mount('#root');
    </script>
    

    如上代码就会因为readonly报错。

    toRefs

    解构,如果只需要传递某一个对象中的一个属性,那么可以如下编写代码:

    <script>
      const app = Vue.createApp({
        template: `
          <div>{{name}}</div>
        `,
        setup(props, context) {
    
          const { reactive, toRefs } = Vue;
          const nameObj = reactive({name: 'dell', age: 28});
        
          setTimeout(() => {
            nameObj.name = 'lee'
          }, 2000)
          const {name} = toRefs(nameObj);
          return { nameObj ,copyNameObj}
        }
      });
      const vm = app.mount('#root');
    </script>
    

    同样可以实现动态更新值。
    toRefs的原理:

    toRefs proxy({ name: 'dell', age: 28}), {
    name: proxy({ value: 'dell'}),
    age: proxy({value: 28})
    }

    toRef

    <script>
      // toRef, context
      const app = Vue.createApp({
      
        template: `<div>{{age}}</div>`,
        setup(props, context) {
          const { reactive,toRef } = Vue;
          const data= reactive({name:'dell'});
          //意思是从data这个响应式对象中尝试取age这个响应式数据。
          //如果能取到就取到,如果不存在,则默认取到一个空的响应式数据
          const name = toRef(data,'age');
          setTimeout(()=>{
              name.value='lee'
          },2000)
          return { age }
        }
      });
     
      const vm = app.mount('#root');
    </script>
    

    context参数

    <script>
      // toRef, context
      const app = Vue.createApp({
        template: `<child  >parent</child>`,
      });
      
      app.component('child', {
        setup(props, context) {
          const { h } = Vue;//h函数
          //context中有3个值
          //attrs:指的是父组件传递过来的None-props属性
          //(就是当子组件不存在props声明时,父组件传递的自定义属性会在这个属性值中)
          //slots:父组件传递过来的插槽( 'parent')
          //emit:在setup中触发父组件的事件
          const { attrs, slots, emit } = context;
          
          return ()=>h('div',{},['123123']);
        
        }
      })
      const vm = app.mount('#root');
    </script>
    

    这个相当于把<div>123123</div>渲染到页面上。
    如果想把插槽内容parent渲染到页面上:

    <script>
      // toRef, context
      const app = Vue.createApp({
        template: `<child  >parent</child>`,
      });
      
      app.component('child', {
        setup(props, context) {
          const { h } = Vue;//h函数
          const { attrs, slots, emit } = context;
          return ()=>h('div',{},slots.default());
        }
      })
      const vm = app.mount('#root');
    </script>
    

    emit的使用:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>lesson 36</title>
      <script src="https://unpkg.com/vue@next"></script>
    </head>
    <body>
      <div id="root"></div>
    </body>
    <script>
      // toRef, context
      const app = Vue.createApp({
        methods: {
          handleChange() {
            alert('change');
          }
        },
        template: `<child @change="handleChange">parent</child>`,
      });
      
      app.component('child', {
        template: '<div @click="handleClick">123123</div>',
        setup(props, context) {
          const { h } = Vue;//h函数
          //context中有3个值
          //attrs:指的是父组件传递过来的None-props属性
          //(就是当子组件不存在props声明时,父组件传递的自定义属性会在这个属性值中)
          //slots:父组件传递过来的插槽( 'parent')
          //emit:在setup中触发父组件的事件
          const { attrs, slots, emit } = context;
          function handleClick() { emit('change'); }
          return { handleClick }
        }
      })
      const vm = app.mount('#root');
    </script>
    </html>
    
    

    相关文章

      网友评论

        本文标题:【vue3.0】13.0 Composition API(一)—

        本文链接:https://www.haomeiwen.com/subject/cudeultx.html