Vue3.0尝试

6,131 阅读6分钟

前言

    有关vue2的相关相关语法我相信大家都已经的语法我相信大家都已经会了,现在都已经2020年了vue作为前端这么热门的框架, 不去学一波对的自己是做前端的吗?哈哈哈哈🤣🤣🤣。
    一路就开始折腾,那是一路曲折啊,重不会到会也不知道自己经历了什么,到现在vue3.x马上又有开始了所以自己也是先试试水,玩了一波相关的语法。
     废话不多说直接上代码记录下(由于本人没有用到TS所以都是进行与ES6进行)

开始

  1. vue-cli3.0下安装 composition-api
    npm install @vue/composition-api --save
    # OR
    yarn add @vue/composition-api
    
    
  2. 在使用任何 @vue/composition-api 提供的能力前,必须先通过 Vue.use() 进行安装
    import Vue from 'vue'
    import VueCompositionApi from '@vue/composition-api'
    
    Vue.use(VueCompositionApi)
    
    安装完成后就可项目中使用相关composition-api来开发了

setup(入口函数)

    setup()函数是vue3中,专门为组件提供的新属性,感觉就跟是跟vue2.x中的data一样需要返回一个Object中包含了自己定义的function, computed, watch以及属性和生命周期。

  1. setup 函数会在 beforeCreate 之后、created 之前执行。

    setup(props, context) {
        const state = reactive({count: 0}) // 创建数据
        return state // 返回页面中使用
    }
    
  2. 接收props数据

    1. props中定义当前组件允许外界传递过来的参数名称:
      props: {
         name: String
      }  
      
    2. 通过setup函数的第一个形参,接收 props 数据:
      setup(props) {
          console.log(props.name)
      }
      
  3. context形参

    setup函数的第二个形参是一个上下文对象,就是vue2.x中的this,在vue 3.x中,它们的访问方式如下

     setup(props, context) {
        context.slots
        context.emit
        context.refs
    }
    

reactive与ref(响应式数据源)

  1. reactive()函数接收一个普通的对象,返回一个响应的数据对象。

    这等价于vue2.x中的Vue.observable()函数,vue3.x然后就是可以直接用reactive()函数直接创建响应的数据对象。

    1. 按需导入reactive相关函数

      import { reactive } from '@vue/composition-api'

    2. setup()的函数中调用reactive()函数,创建对应的响应式数据对象

      setup() {
          // 这个类似于vue2中的data()返回的响应式对象
          const state = reactive({ count: 0 }) 
          return state
      }
      
    3. template中访问响应式数据

      <template>
          <span>当前的count值为:{{count}}</span>
      </template>
      
  2. ref()函数用来根据给定值创建一个响应式的数据对象,ref()函数的调用返回值是一个对象,这个对象上只包含一个value属性。

    1. 导入相关ref相关函数

      import { ref } from '@vue/composition-api'

    2. 创建响应式对象

      setup() {
          const count = ref(0)
              return {
                  count,
                  name: ref('vue')
              }
      }
      
    3. template中访问响应式数据

      <template>
          <span>{{count}}--- {{name}}</span>
      </template>
      
  3. isRef的使用 ,isRef()函数主要用来判断某个值是否为ref()创建出来的对象;应用场景:当需要展开某个可能为ref()创建出来的值得时候,例如:

    import { isRef } from '@vue/composition-api'
    
    const fooData = isRef(foo) ? foo.value : foo
    
  4. toRefs的使用,toRefs()函数可以将reactive()创建出来的响应式对象,转为普通对象,只不过这个对象上的属性节点都是以ref()类型的像是数据, 最常见应用场景

    import { toRefs, reactive } from '@vue/composition-api'
    
    setup() {
        // 定义响应式数据对象
        const state = reactive({
          count: 0
        })
        
        // 定义页面上可用的事件处理函数
        const increment = () => {
          state.count++
        }
        
        // 在 setup 中返回一个对象供页面使用
        // 这个对象中可以包含响应式的数据,也可以包含事件处理函数
        return {
          // 将 state 上的每个属性,都转化为 ref 形式的响应式数据
          ...toRefs(state),
          // 自增的事件处理函数
          increment
        }
    }
    

    template中就直接可以使用count属性和相对应的increment方法了,如果没有使用roRefs直接返回state那么就得通过state.xx来访问数据

    <template>
      <div>
        <span>当前的count值为:{{count}}</span>
        <button @click="increment">add</button>
      </div>
    </template>
    

computed与watch(计算属性与监听)

  1. computed() 用来创建计算属性,computed() 函数的返回值是一个 ref 的实例。使用 computed 之前需要按需导入:

    import { computed } from '@vue/composition-api'
    
    1. 创建只读的计算属性,在调用computed()函数的时候,传入一个function函数,可以得到一个只读的计算属性。

      // 创建一个响应式数据
      const count = ref(1) 
      
      // 根据count的值创建一个响应式的计算属性, 它会根据ref自动计算并且返回一个新的ref
      const computedCount = computed(() => count.value + 1 ) 
      
      console.log(computedCount.value) // 打印 2
      
      computedCount.value++ //报错
      
      
    2. 创建可读可写的计算属性

      在调用computed()函数的时候传入一个包含getset的对象,就可以得到一个可读可写的计算属性了。

      // 创建一个响应式数据
      const count = ref(1) 
      
      // 根据count的值创建一个响应式的计算属性, 它会根据ref自动计算并且返回一个新的ref
      const computedCount = computed({
          get: () => count.value + 1,
          set: (val) => count.value = val - 1
      } ) 
      
      computedCount.count = 6
      
      console.log(count.value) // 打印 5
      
      

    2. watch() 函数用来监听数据的变化,跟vue2.x中的是一样的不过在这得像computed的使用方法一样导入相关api方法

    使用前导入 import { watch } from '@vue/composition-api'

    1. 基本用法

      const count = ref(0)
      
      // 定义watch只要count的值变化,就会触发watch的回调
      // watch 会在创建的时候自动调用一次
      
      watch(() => console.log(count.value))
      
      
      setTimeout(() => {
          count.value++
      }, 1000)
      
      
    2. 监听指定数据

      / 定义reactive数据源
      const state = reactive({ count: 0 })
      // 监视 state.count 这个数据节点的变化
      watch(() => state.count, (now, prev) => { 
          console.log(now, prev)
      })
      
      / 定义ref数据源
      const count = ref(0)
      // 监视count这个数据的变化
      watch(count, (now, prev) => { 
          console.log(now, prev)
      })
      
      
      

LifeCycle Hooks(生命周期)

在新版中的生命周期需要按需导入,并且只能写setup()函数中。

使用onBeforeMount, onMounted, updated相关生命周期,使用前导入相关api方法

import { onBeforeMount, onMounted, updated } from '@vue/composition-api'
setup () {
   onBeforeMount(() => {
     console.log('onBeforeMount!')
   })
   onMounted(() => {
     console.log('onMounted!')
   })
   updated(() => {
     console.log('updated!')
   }) 
}

相关每个生命周期方法都是传入一个function函数。

vue2.x与新版 Composition API之间的映射关系

  • beforeCreate -> setup
  • created -> setup
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

provide & inject(数据共享)

provide()inject()可以实现嵌套组件之间的数据传递。这个两个函数只能在setup()函数中使用。父级组件中使用provide()函数可以使数据向下传递,子组件中使用inject()接收上层传过来的数据。

实现代码:

根组件(父组件)parent.vue

<template>
  <div>
    <child-one></child-one>
    <child-two></child-two>
  </div>
</template>

<script>
  import { provide } from '@vue/composition-api'
  import ChildOne from '@/components/Child'
  import ChildTwo from '@/components/Child'
  export default {
    components: {
       ChildOne,
       ChildTwo
    },
    setup() {
    // provide('要共享的数据名称', 被共享的数据)
      provide('globalName', 'vue') 
    }
  }

</script>

子组件1 ChildOne.vue

<template>
  <div>
    <!--页面展示数据globalName -->
    {{globalName}} 
  </div>
</template>

<script>
  import { inject } from '@vue/composition-api'
  export default {
    name: 'ChildOne',
    setup() {
      const globalName = inject('globalName') 调用 inject 函数时,通过指定的数据名称,获取到父级共享的数据
      return {
        globalName
      }
    }
  }
</script>

子组件2 ChildTwo.vue

<template>
  <div>
    <!--页面展示数据globalName -->
    {{globalName}} 
  </div>
</template>

<script>
  import { inject } from '@vue/composition-api'
  export default {
    name: 'ChildTwo',
    setup() {
      const globalName = inject('globalName') 调用 inject 函数时,通过指定的数据名称,获取到父级共享的数据
      return {
        globalName
      }
    }
  }
</script>

provide函数被共享的数据可以使refreactive定义的响应式数据,用法类似

template refs(元素组件)

我们知道在vue2.x中获取页面元素的DOM可以通过ref写在页面元素上然后在js中通过$refs.x来拿取当前元素的DOM元素信息,操作DOM,在composition-api中我们通过提供的ref方法传入一个null并且定义与页面元素上ref相对应。

代码实现:

<template>
  <div>
    <h1 ref="h1Ref">Hello Word</h1>
  </div>
</template>

<script>
import { ref, onMounted } from '@vue/composition-api'

export default {
  setup() {
    // 创建一个 DOM 引用
    const h1Ref = ref(null)

    // 在 DOM 首次加载完毕之后,才能获取到元素的引用
    onMounted(() => {
      // 为 dom 元素设置字体颜色
      // h1Ref.value 是原生DOM对象
      console.log(h1Ref.value)
    })

    // 把创建的引用 return 出去
    return {
      h1Ref
    }
  }
}
</script>

结尾

    感觉composition-api都是以导入的形式使用,感觉没有直接vue2.x中直接使用的方便哈😂。虽然都是说按需引入,使用想用的方法。对比了与vue2.x的各种写法感觉突然转过来有很大不适应,写的各种数据方法都要在setup的入口函数中导出才能在页面上使用。虽然vue2.x定义的数据也需要通过data函数返回值然后在页面中使用,但是方法不用啊,什么计算属性监听也都是不用的啊。可能是自己适应了vue2.x的各种写法,感觉用起来各种爽。转变到vue3.x也就是现在的composition-api还需要点时间。

最后自己还是有个问题没有解决有大佬给我思路吗?就是子父组件的通信怎么写?之前版本是通过$emit进行,我发现这setup函数中写了父组件拿不到。

最后贴上composition-api官方文档

vue-composition-api-rfc.netlify.com