文档传送门

https://vue.w3ctech.com/

尤雨溪vue3有关演讲

回顾

1. 为什么还没发布

因为ie11不支持proxy且市场占有率还不低,发布早了这个功能其实很多人很难用得到

2. vue3的目标

更快(vdom优化)和ts更好支持是两个主要目标

vdom优化

传统vdom的性能瓶颈

  1. 虽然 Vue 能够保证触发更新的组件最小化,但在单个组件内部依然需要遍历该
    组件的整个 vdom 树
  2. 传统 vdom 的性能跟模版大小正相关,跟动态节点的数量无关。在一些组件整个
    模版内只有少量动态节点的情况下,这些遍历都是性能的浪费
  3. 传统vdom为啥要那么做?因为JSX 和手写的 render function 是完全动态的,过度的灵活性导致运行时可以用于优化的信息不足(react是通过时间分片来解决这个问题)
  4. 而如果使用模板template来编译成vdom,就可以有更多信息提供给引擎优化
  5. vue3认为,如果编译足够快,不需要通过类似时间分片去弥补动态渲染的性能瓶颈问题
  6. 另一个极致的实现是某些框架SVELTE不用vdom,而是直接用静态模板去编译,实现运行时更快

vue并不抛弃vdom

vue并不会走这种极端,因为:

  1. jsx和render等比模板更底层的方法能够实现比模板更复杂的功能
  2. 生成代码更简洁(对比静态模板,有时候生成代码量很大,尽管运行时很“轻”)
  3. vue2兼容

vue特有的

  1. 底层是 Virtual DOM
  2. 上层有包含大量静态信息的模版

vue3目标

  1. 兼容手写 render function
  2. 最大化利用模版静态信息

如何最大化的动静结合?

新的策略:

  1. 将模版基于动态节点指令切割为嵌套的区块
  2. 每个区块内部的节点结构是固定的
  3. 每个区块只需要以一个 Array 追踪自身包含的动态节点

因为遍历是耗时的,新策略将 vdom 更新性能由与模版整体大小相关提升为与动态内容的数量相关

Typescript

为什么撤销了class API

  1. 原本的目的是更好的ts支持
    Props 和其它需要注入到 this 的属性导致类型声明依然存在问题
  2. 类型支持外没太大的优势,除了似乎用了原生api
    写UI组件时更多是组合逻辑,而不是OOP的继承的逻辑,所以Vue有更好的选择

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 } } }

把vue实例的选项全部放入setup函数,value表示包装类型,使得能够count.value这样使用,等于对vue的很大改动

funtion-base API优点

对比 Class API

  1. 更好的 TypeScript 类型推导支持
    ts对对象的推到不如对函数推导,上面的代码形式更容易被ts推导
  2. 更灵活的逻辑复用能力
    都放在函数中了,因此函数调用比组件调用更灵活
  3. Tree-shaking 友好
    原来的形式导致没有数据也会编译出data methods之类的选项,新的形式如果没使用就会去掉该选项,使得vue代码大小与使用的功能正相关
  4. 代码更容易被压缩
    function的参数可以被压缩为单个字母,但对象的内容一般是不压缩的

逻辑复用案例-鼠标位置侦听

可以有以下方法:

1. mixin
  • 命名空间冲突
  • 版数据来源不清晰
2. 高阶组件(Higher-order Components)
  • props 命名空间冲突
  • props 来源不清晰
  • 额外的组件实例性能消耗
3. Renderless Components(作用域插槽)
  • 没有命名空间冲突
  • 数据来源清晰
  • 额外的组件实例性能消耗
4. new API
function useMousePosition() { const x = value(0) const y = value(0) const update = e => { x.value = e.pageX y.value = e.pageY } onMounted(() => { window.addEventListener('mousemove' , update) }) onUnmounted(() => { window.removeEventListener('mousemove' , update) }) return { x, y } }
new Vue({ template: ` <div> Mouse position: x {{ x }} / y {{ y }} </div> `, data() { const { x, y } = useMousePosition() return { x, y, // ... other data } } })

使用时,不用再关心x和y是包装类型,当普通值使用即可

对比 React Hooks

  • 同样的逻辑组合、复用能力
  • 只调用一次
    • 符合 JS 直觉
    • 没有闭包变量问题
    • 没有内存/GC 压力
    • 不存在内联回调导致子组件永远更新的问题

Vue Beyond Vue Loader(vue的用法总结)

蒋豪群,vue-loader和vue/cli维护者

vue写法分几种?

大体有三种,模板字符串、id、render函数,本质是前两种也要解析成render函数

写法分类

1. Vue.component()

字符串模板直接写在js里

Vue.component('compName',{ props: ['todo'], template: '<li>{{todo.text}}</li>' })

2. el方式

字符串模板写在html中,通过id选择

Vue.component('compName',{ props: ['todo'], template: '#domId' })

3. render函数

render过程解析

模板:

<div> <h1>My title</h1> Some text content <!--todo:add tagline--> </div>

解析为dom树:
dom.png![dom.png]

vue在生成虚拟dom时,需要用到这些函数
shiji.png

vue对这些函数做了简化,直接可以用h函数,h函数就是以上所有的函数的简写,根据使用方法决定是哪个函数,h是html的hyper的首字母,通常读作createElement,当然实际实现的是图中所有函数
createElement.png

vue-loader

vue通过webpack+vue-loader来预编译

vue-loader做了什么

主要工作:

  1. 模板解析和编译(vue-template-compiler)
  2. 表达式的新语法支持+作用域分析(vue-template-es2015-compiler,只在vue-loader中引用,只有在预编译的一步做,运行时交给js引擎做)
  3. 合并单文件组件的所有区块,并支持scoped css和url转换等(vue/component-compiler-utils)

vueloader.png

  • vue-template-es2015-compiler支持所有新语法,如es2016及更新版本
  • vue/component-compiler-utils 函数库
  • vue-loader是webpack相关的逻辑,主要是支持单文件组件(不使用webpack,最后这一层可以放弃)

不用webpack怎么支持单文件解析与打包

1. 官方插件rollup-plugin-vue

完美适用于库文件的打包,tree-shaking能力远超过webpack

rollup.png

2. @vue/dev-server

  1. 静态文件服务器中间件
  2. 可以直接在浏览器中使用 import App from “APP.vue”
原理
  • 遇到.vue解析成ES modules
  • 浏览器只需要MIME类型,不关心扩展名是什么(但是得有扩展名)
实例
  1. 安装dev-server静态资源服务器
yarn global add @vue/dev-server

注意,global使得命令“vue-dev-server”全局可用
2. 写静态文件

index.html:

<!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> </head> <body> <div id="app"></div> <script type="module"> import './main.js'; </script> </body> </html>

注意,只需要写type=“module”即可使用import,即js的module方案

main.js:

import Vue from 'vue'; import App from './test.vue'; new Vue({ render: h => h(App) }).$mount('#app')

test.vue:

<template> <h1>{{msg}}</h1> </template> <script> export default { data() { return { msg: 'hello world' } } } </script> <style scoped> h1 { color:lightcoral; } </style>
  1. 运行静态文件
vue-dev-server

运行后有提示监听端口,打开即可

3. 对vue文件支持插件-@vue/component-compiler-utils

如果不用dev-server,可以借助@vue/component-compiler-utils来实现开源项目对vue文件的支持

4. 不使用单文件组件但要vue纯逻辑组件的能力时

jsx

JSX手动拼装vnode的数据结构,即等同于h开头的函数所做的工作

涉及:
@vue/babel-preset-jsx
@babel/plugin-syntax-jsx

template-strings

vue-html这个库 利用了js模板字符串,等于换了一种方式拼装vnode,mixin改写render函数传入的参数,运行时拿到的与h函数的返回值一样,都是vnode

typescipt与类型安全

现存问题

  • vue2中使用vue-class-component、vue-property-decorator,利用了decorator标准来实现类型安全
  • decorator存在以下问题:
    • 但decorator本身一直很不稳定
    • ts实现的是decorator的早期标准
    • ts与babel的实现也有差异

vue3

  1. Class Api不再在vue core中实现
  2. Composition function(function-base api)实现更好的类型推断(ts对函数及其参数的类型推断支持很好,Composition function写出的代码和ts代码一致)
  3. vue-class-component、vue-property-decorator仍然会保留

vuepress1.x

详细的官网文档

简介

  • vuepress是一个静态网站生成器,竞品包括Wordpress、Hexo等建站工具
  • 一个 VuePress 网站是一个由 Vue、Vue Router 和 webpack 驱动的单页应用
  • 它也借鉴了nuxt的nuxt generate来实现ssr

vuepress1.x提供功能

  • 插件API
  • 增强主题
  • 新增博客主题