Leo-lin214 / keep-learning

:books: 好好学习,天天向上
6 stars 0 forks source link

Vue3.0 都有哪些新特性 #28

Open Leo-lin214 opened 4 years ago

Leo-lin214 commented 4 years ago

在接下来要出现的 Vue 3.0 中,它更注重的点就在于以下几点。

那么下面我就看看都有哪些大的改动。

Virtual DOM重构

在 Vue 2.x 中,Virtual DOM 的最小粒度就是组件,那么只有相应的组件发生改变时,才会执行相应的 compiler --> render --> generate 三个阶段。

那么问题来了,在旧版本的 Vue 中,每次的更新都会遍历整个模板进行编译,包括很多静态节点每次更新导致的静态节点的重复遍历就会导致很多性能浪费

其实在 Vue 2.0 后续的版本中,已经有对这一步进行相应的优化,那就是将解析得到的 AST 进行相应的静态节点或静态树标注,这样可以避免下次在遍历的过程中直接跳过。但是另外一个问题出来了,那就是依然还需要对整个模板 Template 进行相应的遍历

在 Vue 3.0 之后,就采取动静结合策略,来处理这种情况。

简单来说,就是在编译时,现将 Template 中有用到指令的节点记录保存下来,并存到一个数组当中,那么下一次更新遍历时,只需要对该数组进行相应的遍历更新即可。这样就极大滴将 Virtual DOM 的最小粒度将到了动态指令当中,而对于那些静态节点只会在第一次编译时处理,其他情景都会忽略。

当然,动静结合使得一个 VNode Tree 直接划分成了一个区块树 Block Tree。拿尤大大 PPT 中的一张图作为示例。

转化后的区块树长的是这个模样。

Proxy 代理数据绑定

相信我们知道,在 Vue 3.0 版本之前,都是基于 Object.defineProperty 实现相应的数据绑定,通过设置相应的 getter 以及 setter 来将一个对象的属性进行响应式设置。

那么问题来了,对于以下的情况,Object.defineProperty 是无法进行相应的数据绑定的。

对于上述的问题,Vue 还特意使用 \$set 全局 API 实现上述的监听。为此在 Vue 3.0 之后,便不再需要担心这些问题的出现啦,通过 ES6 中的 Proxy API 可以完美解决上述的问题。

有兴趣的童鞋可以直接跳到以下链接看看。

Proxy API

抛弃 Class API,拥抱 Function-based API

class API 固然可以更好滴支持 TS,但是依旧存在的问题就是,Props 和其他需要注入到 this 的属性仍然存在声明类型的问题。另外就是,除了类型支持外,class API 并没有带来更好的优势

那么我们先看看,所谓的 Function-based API 长的是什么样子的。

const App = {
    setup() {
        // data
        const count = value(0)
        // computed
        const plusOne = computed(() => count.value + 1)
        // method
        const increment = () => { count.value++ }
        // watch
        watch(() => count.value * 2, v => console.log(v))
        // lifecycle
        onMounted(() => console.log('mounted!'))
        // 暴露给模板或渲染函数
        return { count }
    }
}

相比 class API,Function-based API 具有以下优势。

另外的一点,Function-based API 对于 Mixin 特别友好。

需要说明一点,原本 Mixin 会存在以下问题。

那么 React 中的高阶组件依然存在着问题。

但是使用 Function-based API 后,将会更友好滴解决以上问题。

// 旧Mixin写法
const mousePositionMixin = {
  data() {
    return {
      x: 0,
      y: 0
    }
  },
  mounted() {
    window.addEventListener('mousemove', this.update) 
  },
  destroyed() {
    window.removeEventLister('mousemove', this.update)
  },
  methods: {
    update(e) {
      this.x = e.pageX
      this.y = e.pageY
    }
  }
}

// Function-based API
const useMousePosition = function() {
  const x = value(0)
  const y = value(0)
  const update = e => {
    this.x = e.pageX
    this.y = e.pageY
  }
  onMounted(() => {
    window.addEventListener('mousemove', this.update) 
  })
  onDestroyed(() => {
    window.removeEventLister('mousemove', this.update)
  })
  return {x, y}
}

// 在组件中使用Function-based API包装的Mixin
new Vue({
  template: '...',
  data() {
    const {x, y} = useMousePosition()
    return {x, y}
  }
})

Function-based API 跟 React Hooks 非常的类似,同样具有逻辑复用功能。但是唯一的一点不同在于,React Hooks 在组件更新时都会将所有的 Hooks 都调用一遍,而 Function-based API 则只会调用一次

sysadmin-mud commented 2 years ago

great notes

关于 vscode 的 vue 插件: vetur 只支持 vue 2 , volar 只支持 vue 3 volar 支持 vue 2 / 3 , vetur 和 volar 两者冲突。

vscode volar 本身有一个接管模式 vscode volar 在配置 vue 2.7 时候可能会遇到麻烦

usercao commented 1 year ago

使用VolarVue 2.7.xjsconfig.json增加:

{
  "compilerOptions": {},
  "vueCompilerOptions": {
    "target": 2.7,
    "extensions": [".vue"]
  }
}