zoukankan      html  css  js  c++  java
  • vue3的新特性

    不知不觉的VUE3.0发布已经很久了。

    在B站上看了教学视屏 瞬间勾起的我浓厚的学习兴趣。

    https://www.bilibili.com/video/BV1yK4y1M7Fz?p=8&spm_id_from=pageDriver

    Vue 3全新的Web开发构建工具Vite

    Vite是Vue的作者尤雨溪开发的Web开发构建工具,它是一个基于浏览器原生ES模块导入的开发服务器,在开发环境下,利用浏览器去解析import,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随启随用。同时不仅对Vue文件提供了支持,还支持热更新,而且热更新的速度不会随着模块增多而变慢。在生产环境下使用Rollup打包。

    Vite具有以下特点:

    快速的冷启动即时热模块更新(HMR,Hot Module Replacement)真正按需编译Vite是在推出Vue 3的时候开发的,目前仅支持Vue 3.x,这意味着与Vue 3不兼容的库也不能与Vite一起使用。

    与Vue CLI类似,Vite也提供用npm或者yarn来生成项目结构的方式。选择一个目录,打开命令提示窗口,依次执行下面的命令构建脚手架项目,并启动项目。

    npm init vite-app <project-name>
    
    cd <project-name>
    
    npm install
    
    npm run dev

    如果使用yarn,则依次执行下面的命令:

    yarn create vite-app <project-name>
    
    cd <project-name>
    
    yarn
    
    yarn dev

    由于Vite使用了浏览器原生的ES模块导入功能,但IE 11并不支持ES的模块导入,因此基于Vite开发项目,浏览器不能使用IE11,其他主流的浏览器均支持ES模块的模块功能。

    我创建了一个项目 结构如下

    可以发现,Vite生成的脚手架项目的目录结构与Vue CLI生成的项目目录结构很类似,确实是这样的,而且开发方式也基本相同。不过Vite项目的默认配置文件是vite.config.js,而不是vue.config.js。

    package.json文件的内容如下所示:

    {
      "name": "webapp-vue3",
      "version": "0.0.0",
      "scripts": {
        "dev": "vite",
        "build": "vite build"
      },
      "dependencies": {
        "vue": "^3.0.4"
      },
      "devDependencies": {
        "vite": "^1.0.0-rc.13",
        "@vue/compiler-sfc": "^3.0.4"
      }
    }

     这里与Vue CLI不同地方在这里:

    "dev": "vite",

    "build": "vite build"

    体验了一波非常棒,基本上都是秒启动,改动代码以后也是秒更新。

     Vue 3采用Proxy数据劫持

    1. Vue 2.x 利用 Object.defineProperty(),并且把内部解耦为 Observer, Dep, 并使用 Watcher 相连
    2. Vue 在 3.x 版本之后改用 Proxy 进行实现

    那么他们之前有什么优缺点呢?

    1、Object.defineProperty() 的问题主要有三个:

    • 不能监听数组的变化
    • 必须遍历对象的每个属性
    • 必须深层遍历嵌套的对象
    • 不能监听数组的变化

      数组的这些方法是无法触发set的:push, pop, shift, unshift,splice, sort, reverse.
      Vue 把会修改原来数组的方法定义为变异方法 (mutation method)
      非变异方法 (non-mutating method):例如 filter, concat, slice 等,它们都不会修改原始数组,而会返回一个新的数组。
      Vue 的做法是把这些方法重写来实现数组的劫持。
    • 必须遍历对象的每个属性
      使用 Object.defineProperty() 多数要配合 Object.keys() 和遍历,,于是多了一层嵌套

     

    Object.keys(obj).forEach(key => {
      Object.defineProperty(obj, key, {
        // ...
      })
    })

     必须深层遍历嵌套的对象
    当一个对象为深层嵌套的时候,必须进行逐层遍历,直到把每个对象的每个属性都调用 Object.defineProperty() 为止。 Vue 的源码中这样的逻辑----walk 方法.

    2、Proxy:
    Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。

    • 针对对象:针对整个对象,而不是对象的某个属性
    • 支持数组:不需要对数组的方法进行重载,省去了众多 hack
    • 嵌套支持: get 里面递归调用 Proxy 并返回
    • 其他
      针对对象
      不需要对 keys 进行遍历。这解决Object.defineProperty() 的第二个问题.Proxy 是针对整个 obj 的。所以 obj 内部包含的所有的 key ,都可以走进 set。(省了一个 Object.keys() 的遍历)
    let obj = {
      name: 'Eason',
      age: 30
    }
    let handler = {
      get (target, key, receiver) {
        console.log('get', key)
        return Reflect.get(target, key, receiver)
      },
      set (target, key, value, receiver) {
        console.log('set', key, value)
        return Reflect.set(target, key, value, receiver)
      }
    }
    let proxy = new Proxy(obj, handler)
    proxy.name = 'Zoe' // set name Zoe
    proxy.age = 18 // set age 18

    另外 Reflect.get 和 Reflect.set 可以理解为类继承里的 super,即调用原来的方法

    嵌套支持
    Proxy 也是不支持嵌套的,这点和 Object.defineProperty() 是一样的。因此也需要通过逐层遍历来解决。Proxy 的写法是在 get 里面递归调用 Proxy 并返回

    let obj = {
      info: {
        name: 'eason',
        blogs: ['webpack', 'babel', 'cache']
      }
    }
    let handler = {
      get (target, key, receiver) {
        console.log('get', key)
        // 递归创建并返回
        if (typeof target[key] === 'object' && target[key] !== null) {
          return new Proxy(target[key], handler)
        }
        return Reflect.get(target, key, receiver)
      },
      set (target, key, value, receiver) {
        console.log('set', key, value)
        return Reflect.set(target, key, value, receiver)
      }
    }
    let proxy = new Proxy(obj, handler)
    // 以下两句都能够进入 set
    proxy.info.name = 'Zoe'
    proxy.info.blogs.push('proxy')

    其它方面

        优势:Proxy 的第二个参数可以有 13 种拦截方法,比 Object.defineProperty() 要更加丰富,Proxy 作为新标准受到浏览器厂商的重点关注和性能优化,相比之下 Object.defineProperty() 是一个已有的老方法。
        劣势:Proxy 的兼容性不如 Object.defineProperty() (caniuse 的数据表明,QQ 浏览器和百度浏览器并不支持 Proxy,这对国内移动开发来说估计无法接受,但两者都支持 Object.defineProperty()),不能使用 polyfill 来处理兼容性

     Vue 3采用Proxy数据劫持

    Vue3 的新特性(二) —— Composition-Api

    Composition API : 一组低侵入式的、函数式的 API,它使我们能够更灵活地「组合」组件的逻辑。

    Composition API 的灵感来自于 React Hooks ,是比 mixin 更强大的存在。它可以提高代码逻辑的可复用性,从而实现与模板的无关性;同时函数式的编程使代码的可压缩性更强。另外,把 Reactivity 模块独立开来,意味着 Vue3.0 的响应式模块可以与其他框架相组合。

     如上图,在较大组件的编写中, Composition-Api 可以把复杂组件的逻辑抽地更紧凑,而且可以将公共逻辑进行抽取。

    1. reactive()

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

    在Vue2.x的版本中,我们只需要在 data() 中定义一个数据就能将它变为响应式数据,在 Vue3.0 中,需要用 reactive 函数或者 ref 来创建响应式数据。

    setup() {
        // 创建响应式对象
        const state = reactive({
            count:0
        });
    
        // 将响应式对象return出去,暴露给模板使用
        return state;
    }

    使用响应式对象

    <p>当前的count的值为:{{count}}</p>
    
    <button @click="count++">点击增加count<  button>

    2. ref()

    ref() 函数可以根据给定的来创建一个响应式的数据对象,返回值是一个对象,且只包含一个 .value 属性。

    • 用 ref 创建响应式对象

    setup() {
        // 创建响应式对象
        const count = ref(0);
    
        return {
            count
        }
    }

    使用响应式对象

    <p>当前的count的值为:{{count}}</p>
    
    <button @click="count++">点击增加count</button>

    ref 的注意事项

        在 setup() 函数内,由 ref() 创建的响应式数据返回的是对象,所以需要用 .value 来访问;

        而在 setup() 函数外部则不需要 .value ,直接访问即可。

        可以在 reactive 对象中访问 ref() 函数创建的响应式数据。

        新的 ref() 会覆盖旧的 ref() 。

    watchEffect()

    watchEffect() 会立即执行传入的函数,并响应式侦听其依赖,并在其依赖变更时重新运行该函数。

    const count = ref(0)
    
    // 初次直接执行,打印出 0
    watchEffect(() => console.log(count.value))
    
    setTimeout(() => {
      // 被侦听的数据发生变化,触发函数打印出 1
      count.value++
    }, 1000)

    停止侦听

    watchEffect() 使用时返回一个函数,当执行这个返回的函数时,就停止侦听

    const stop = watchEffect(() => {
      /* ... */
    })
    
    // 停止侦听
    stop()

    watch()

    composition-api 中的 watch 和 Vue2.x 中是一样的,watch 需要侦听数据,并执行它的侦听回调。默认情况下初次渲染不执行。

    • watchwatchEffect 的不同

      1. watch 初次渲染不执行
      2. watch 侦听的更具体
      3. watch 可以访问侦听数据变化前后的值
    // 侦听一个 getter
    const state = reactive({ count: 0 })
    watch(
      () => state.count,
      (count, prevCount) => {
        /* ... */
      }
    )
    
    // 直接侦听一个 ref
    const count = ref(0)
    watch(count, (count, prevCount) => {
      /* ... */
    })
    

    watch 侦听多个数据源

    在侦听多个数据源时,把参数以数组的形式给 watch

    watch([ref1, ref2], ([newRef1, newRef2],   [prevRef1, prevRef2]) => {
      /* ... */
    })

    setup() 函数

    在学习 Composition-Api 之前,我们需要先了解一下 setup() 函数。 setup() 是 Vue3 中的新增内容。它为基于 Composition API 的新特性提供了统一的入口。

    在Vue3中,定义 methodswatchcomputeddata数据 等都放在了 setup() 函数中

    注意:在 setup() 函数中访问不到Vue的 this 实例

    1. 执行时机

    setup()函数会在created()生命周期之前执行。

    import { ref } from "vue";
    // setup 在init执行的
    export default {
      name: 'HelloWorld',
      setup () {
        console.log('setup')
        const name = ref('啊sir')
        // onMounted(()=>{
        //   alert('1111')
        // })
        return {
          name
        }
      },
      mounted () {
        console.log('mounted')
      },
      beforeCreate () {
        console.log('beforeCreate')
      },
      created () {
        console.log('created')
      }
    }

     2. 接收props数据(由于setup没有this,所以访问内部属性只能传递参数)

     setup() 函数的第一个参数是 props ,组件接收的 props 数据可以在 setup() 函数内访问到。

    3. context上下文对象

    contextsetup() 的第二个参数,它是一个上下文对象,可以通过 context 来访问Vue的实例 this

    setup(props,context) {
        console.log(this)
        console.log(context)
    }

    如果这篇文章对您有帮助,您可以打赏我

    技术交流QQ群:15129679

  • 相关阅读:
    指针问题,p+i什么意思i代表什么
    怎么用C语言写一个飞机程序
    switch()语句中()中必须是常量吗
    一元二次方程运行结果中输入上系数后总显示输入不合法无论系数可以得出实根
    我想学号图论求大神请教
    c-freelib库
    十进制转十六进制问题(有代码)
    关于逐个读取同一目录下txt文本的问题
    JAVA-JDK1.7-ConCurrentHashMap-测试和验证
    JAVA-JDK1.7-ConCurrentHashMap-源码并且debug说明
  • 原文地址:https://www.cnblogs.com/yeminglong/p/15098308.html
Copyright © 2011-2022 走看看