vue3.0的新特性的使用与总结

1、实例化的方式

// Vue2.0
new Vue({
 el: "#app",
 router,
 store,
 render: h => h(App)
})

  

// Vue3.x
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <!-- <script src="../../packages/vue/dist/vue.global.js"></script>
   -->
   <script src="../vue-next/packages/vue/dist/vue.global.js"></script>
</head>

<body>
  <div id="app"></div>
  <script>
    const {
      createApp,
      reactive,
      computed,
    } = Vue
    const MyComponent = {
      template: `
                <button @click="click">
                {{ state.message }}
                </button>
            `,
      setup() {
        const state = reactive({
          message: 'Hello Vue 3!!'
        })
        function click() {
          state.message = state.message.split('').reverse().join('')
        }
        return {
          state,
          click
        }
      }
    }
    createApp(MyComponent).mount('#app')

  </script>
</body>

</html>

 

2、Composition API

这个是变化最大的地方

在Vue2.x中是在data中写数据,在methods中写方法,通过this调用

在Vue3.x中,所有的逻辑代码都是在setup方法中实现,包括data,watch,computed,methods,hooks,不再有this

Vue3.x中的setup方法在组件生命周期内只执行一次,不会重复执行

(1)、reactive其实就是Vue3.0中的响应式

如以下所写

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <!-- <script src="../../packages/vue/dist/vue.global.js"></script>
   -->
   <script src="../vue-next/packages/vue/dist/vue.global.js"></script>
</head>

<body>
  <div id="app"></div>
  <script>
    const {
      createApp,
      reactive,
      computed,
    } = Vue
    const MyComponent = {
      template: `
                <button @click="click">
                {{ state.message }}
                </button>
            `,
      setup() {
        //  -------reactive响应式-----------
        const state = reactive({
          message: 'Hello Vue 3!!'
        })
        function click() {
          state.message = state.message.split('').reverse().join('')
        }
        return {
          state,
          click
        }
      }
    }
    createApp(MyComponent).mount('#app')

  </script>
</body>

</html>

在上面那段的click里面添加

console.log('state',state)
在控制台则会打印如下:

 

(2) ref和toRefs

   其中,ref可以用来初始化一个数,并给这个数初始值,如果你学过React,你就会发现,它其实和useState有些类似

   用toRefs展开保证了state中的数据不失去响应式

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <!-- <script src="../../packages/vue/dist/vue.global.js"></script>
   -->
  <script src="../../vue-next/packages/vue/dist/vue.global.js"></script>
</head>

<body>
  <div id="app"></div>
  <script>
    const {
      createApp,
      reactive,
      computed,
      ref,
      toRefs
    } = Vue
    const MyComponent = {
      template: `
                <div><button @click="addCount">点击增加, 数量{{count}}
               <span>{{count}}</span>
                </button></div>
                <div><button @click="addNum">点击减少</button>
                <span>{{num}}</span></div>

            `,
        setup() {
        // reactive响应式
        const state = reactive({
          count: 0
        })
        // ref的使用
        const num = ref(0)
        function addCount() {
          state.count++
        }
        function addNum() {
          num.value++
        }
        return {
          ...toRefs(state),
          num,
          addNum,
          addCount
        }
      }
    }
    createApp(MyComponent).mount('#app')

  </script>
</body>

</html>

(3)、computed

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <!-- <script src="../../packages/vue/dist/vue.global.js"></script>
   -->
  <script src="../../vue-next/packages/vue/dist/vue.global.js"></script>
</head>

<body>
  <div id="app"></div>
  <script>
    const {
      createApp,
      reactive,
      computed,
      ref,
      toRefs,
    } = Vue
    const MyComponent = {
      template: `
                <div><button @click="addCount">点击增加, 数量{{count}}
               <span>{{count}}</span>
                </button></div>
                <div><button @click="addNum">点击减少</button>
                <span>{{num}}</span></div>

            `,
      setup() {
        // reactive响应式
        const state = reactive({
          count: 0,
          // ------
          double: computed(() => {
            return state.count * 2
          })
        })
        // ref的使用
        const num = ref(2)
        function addCount() {
          state.count++
        }
        function addNum() {
          num.value++
        }
        // ---only getter
        const totalCount = computed(() => {
          state.count +  2
        })

        // getter & setter
        const doubleCount = computed({
          get() {
            return state.count * 2
          },
          set (newVal) {
            state.count = newVal / 2
         
          }
        })
        return {
          ...toRefs(state),
          // ...state,
          num,
          addNum,
          addCount,
          totalCount,
          // doubleCount
        }
      }
    }
    createApp(MyComponent).mount('#app')

  </script>
</body>

</html>

 (4)、watch & watchEffect

   在Vue2.x中用watch来监听属性

   在Vue3.x中用watch支持监听单个属性,也支持监听多个属性

   在Vue3.x中watchEffect方法会返回一个方法,用于停止监听

   watch跟watchEffect不同的地方在于,watchEffect注册后会立即调用,而watch默认不会,除非

显示指定immediate=true,而且watchEffect可以停止监听

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <!-- <script src="../../packages/vue/dist/vue.global.js"></script>
   -->
  <script src="../../vue-next/packages/vue/dist/vue.global.js"></script>
</head>

<body>
  <div id="app"></div>
  <script>
    const {
      createApp,
      reactive,
      computed,
      ref,
      toRefs,
      watch,
       watchEffect 
    } = Vue
    const MyComponent = {
      template: `
                <div><button @click="addCount">点击增加, 数量{{count}}
               <span>{{count}}</span>
                </button></div>
                <div><button @click="addNum">点击减少</button>
                <span>{{num}}</span></div>
                <div>333{{totalCount}}</div>
                <input type="text" v-model="totalCount" />
            `,
      setup() {
        // reactive响应式
        const state = reactive({
          count: 0,
          // ------
          double: computed(() => {
            return state.count * 2
          }),
          midObj: {
            innerObj: {
              size: 0
            }
          }
        })
        // ref的使用
        const num = ref(2)
        function addCount() {
          state.count++
        }
        function addNum() {
          num.value++
        }
        // ---only getter
        const totalCount = computed(() => {
          return state.count + 2
        })
        // 监听单个属性
        watch(() => totalCount.value,(newVal, oldVal) => {
          console.log(`count + num = ${newVal}`)
        })

        // 监听多个属性
        watch([num, () => totalCount.value], ([numVal, totalVal],[oldNumVal, OldTotalVal]) => {
          console.log(`num is ${numVal}, count + num = ${totalVal}`)
        })
        // 副作用,会立即执行
        let callTimes = 0
        const stopEffect = watchEffect(() => {
          console.log('watchEffect is called!')
          const div = document.createElement('div')
          div.textContent = `totalCount is ${totalCount.value}`
          document.body.appendChild(div)
          // 调用5次后,取消fetch监听
          callTimes++
          if(callTimes >= 5)  stopEffect()
        })
        return {
          ...toRefs(state),
          num,
          addNum,
          addCount,
          totalCount,
        }
      }     
    }  
    createApp(MyComponent).mount('#app')
  </script>
</body>
</html>

   运行上图的代码且点击按钮五次后,页面的效果如下:

 

3、生命周期钩子

在Vue2.x中生命周期钩子与data,methods同级

在Vue3.x中,需要先导入钩子,并且在setup方法中注册钩子回调,并且钩子命名也跟React保持一样了

Vue3.x中移除了Vue2.x中的beforeCreate和created钩子,通过setup代替,如下图:

 

 与React Hooks相比:

基于函数的组合式 API 提供了与 React Hooks 同等级别的逻辑组合能力,
但是它们还是有很大不同:组合式 API 的 setup() 函数只会被调用一次,这意味着使用 Vue 组合式 API 的代码会是:
不需要顾虑调用顺序,也可以用在条件语句中;
不会在每次渲染时重复执行,以降低垃圾回收的压力;
不存在内联处理函数导致子组件永远更新的问题,也不需要 useCallback;
不存在忘记记录依赖的问题,也不需要“useEffect”和“useMemo”并传入依赖数组以捕获过时的变量。Vue 的自动依赖跟踪可以确保侦听器和计算值总是准确无误。
我们感谢 React Hooks 的创造性,它也是本提案的主要灵感来源,然而上面提到的一些问题存在于其设计之中,且我们发现 Vue 的响应式模型恰好为解决这些问题提供了一种思路。

 新增的生命周期钩子:

onRenderTracked
onRenderTriggered
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <!-- <script src="../../packages/vue/dist/vue.global.js"></script>-->
  <script src="../../vue-next/packages/vue/dist/vue.global.js"></script>
</head>

<body>
  <div id="app"></div>
  <script>
    const {
      createApp,
      reactive,
      ref,
      toRefs,
      watch,
      watchEffect,
      computed,
      // 生命周期钩子
      onBeforeMount,
      onMounted,
    } = Vue
    const MyComponent = {
      template: `
                <div><button @click="addCount">点击增加, 数量{{count}}
                <span>{{count}}</span>
                </button></div>
                <div><button @click="addNum">点击减少</button>
                <span>{{num}}</span></div>
                <div>333{{totalCount}}</div>
                <input type="text" v-model="totalCount" />
            `,
      setup() {
        // 生命周期钩子
        onBeforeMount(() => {
          console.log('component is onBeforeMount')
        })
        onMounted(() => {
          console.log('component is onMounted')
        })
        // reactive响应式
        const state = reactive({
          count: 0,
          // ------
          double: computed(() => {
            return state.count * 2
          }),
          midObj: {
            innerObj: {
              size: 0
            }
          }
        })
        // ref的使用
        const num = ref(2)
        function addCount() {
          state.count++
        }
        function addNum() {
          num.value++
        }
        // ---only getter
        const totalCount = computed(() => {
          return state.count + 2
        })
        // 监听单个属性
        watch(() => totalCount.value, (newVal, oldVal) => {
          console.log(`count + num = ${newVal}`)
        })

        // 监听多个属性
        watch([num, () => totalCount.value], ([numVal, totalVal], [oldNumVal, OldTotalVal]) => {
          console.log(`num is ${numVal}, count + num = ${totalVal}`)
        })
        // 副作用,会立即执行
        let callTimes = 0
        const stopEffect = watchEffect(() => {
          console.log('watchEffect is called!')
          const div = document.createElement('div')
          div.textContent = `totalCount is ${totalCount.value}`
          document.body.appendChild(div)
          // 调用5次后,取消fetch监听
          callTimes++
          if (callTimes >= 5) stopEffect()
        })
        return {
          ...toRefs(state),
          num,
          addNum,
          addCount,
          totalCount,
        }
      }
    }
    createApp(MyComponent).mount('#app')
  </script>
</body>

</html>

 

4、Fragment

Vue2.x 的vue template只允许有一个根节点

Vue3.x的vue template支持多个节点

5、Teleport

teleport 参照React中的portal,可以将元素渲染在父节点以外的其他地方,

6、Suspense

通常在发生异步操作或者在异步的组件中使用

 

 

后面还会继续补充添加代码

参考:https://juejin.cn/post/6867123074148335624#heading-9

 

 

  

 

 

posted on 2021-02-25 10:02  人鱼之森  阅读(433)  评论(0编辑  收藏  举报