vue3.0新特性

性能提升

  • 打包大小减少41%
  • 初次渲染快55%,更新快133%
  • 内存使用减少54%
  • 原因:重写虚拟dom的优化和treeshaking的优化

Componsition API(API组合)

  • ref 和 reactive
  • computed 和watch
  • 新的生命周期函数
  • 自定义函数--hooks函数
  • Teleport - 瞬移组件的位置
  • Suspense - 异步加载组件的新福音
  • 全局API的修改和优化
  • 更多的誓言性特性

更好的Typescript 支持

  • vue3.0源码就是ts写的

为什么要有vue3.0?

vue2 遇到的难题

  • 随着功能的增长,复杂组件的代码变得难以维护

Mixin 的缺点

  • 命名冲突
  • 不清楚暴露吃了变量的作用
  • 重用到其他component经常会遇到问题

对typeScript 的支持非常有限

  • 原因是:依赖this指向上下文,主要是没考虑的ts的集成

总结:vue3 完美解决上诉2.0的问题

ts+ vue Cli 项目搭建环境

image.png
  • 选择多项选择可以更好的支持ts
  • 之后选择版本3.0就行
安装好用的vscode插件
  • eslint 语法检查

3 vue3.0新特性介绍

3.1 ref的妙用

通过vue 3.0实现一个计数器

  • 使用ref一般传入的是原始值,比如count初始化为0
  • setup函数中定义的对象及方法都是响应式的



  • 注意:setup方法中无法使用this
  • 在setup 方法中定义的函数,变量需要使用return导出才能在template中使用
  • 通过refAPI定义的变量,是一个对象,操作值得时候需要操作value

3.2 reactive函数的用法

  • 将上面的计算器代码优化下



  • 也可以监听data里面的某个变量

注意直接监听 data.count会失去响应式
at; 可以将数组里面的第二个参数变成getter函数

// 会报警告Invalid watch source:  0 A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types.
 watch([greetings, data.count], (newval, oldavl) => {
       console.log("new", newval, "old", oldavl);
       document.title = "1" + greetings.value;
     });
  • 此时根据警告提示,可以使用getter函数
watch([greetings, () => data.count], (newval, oldavl) => {
      console.log("new", newval, "old", oldavl); // 0: "violetviolet" 1:0
      document.title = "1" + greetings.value;
    });

3.5 使用模块化

  • 实现鼠标追踪器
  • 效果,点击鼠标更新鼠标位置
  1. 使用ref实现
// helloword



  1. 将这个功能模块化使用
  • 在src下新建hooks文件夹
// 新建userMousePosition.ts
import { onMounted, onUnmounted, ref } from 'vue'

function useMousePosition() {
   const x = ref(0);
     const y = ref(0);
     const updateMouse = (e: MouseEvent) => {
       x.value = e.pageX;
       y.value = e.pageY;
     };
     onMounted(() => {
       document.addEventListener("click", updateMouse);
     });
     onUnmounted(() => {
       document.removeEventListener("click", updateMouse);
     });
     // 导出x,y
     return {
       x,
       y,
     };
}

export default useMousePosition
  • 在helloword中引用



  1. 使用reactive改造这个模块
// userMousePosition.ts
import { onMounted, onUnmounted, reactive, toRefs } from 'vue'

function useMousePosition() {
  const data = reactive({
    x: 0,
    y: 0,
  })
  const updateMouse = (e: MouseEvent) => {
    data.x = e.pageX
    data.y = e.pageY
  }
  onMounted(() => {
    document.addEventListener('click', updateMouse)
  })
  onUnmounted(() => {
    document.removeEventListener('click', updateMouse)
  })
  // 注意使用toRefs将data转换成响应式数据
  const refsData = toRefs(data)
  return {
    ...refsData,
  }
}

export default useMousePosition

3.6 hooks模块化理解

  1. 异步请求模块
  • 在src/hooks中新建useUrlLoader.ts文件
import { reactive, toRefs } from 'vue'
import axios from 'axios'
function useURLloader(url: string) {
  const data = reactive({
    result: null,
    loading: true,
    loaded: false,
    error: null,
  })

  axios
    .get(url)
    .then(res => {
      data.loading = false
      data.result = res.data
      data.loaded = true
    })
    .catch(err => {
      data.error = err
      data.loading = false
    })
  const refsData = toRefs(data)
  return {
    ...refsData,
  }
}
export default useURLloader
  • 在loading.vue中使用



  • 结果


    image3.png

2. 模块化结合ts --- 泛型改造

报错(待解决): result: null ==

error  Use 'as T | null' instead of ''
// useUrlLoader.ts
import { reactive, toRefs } from 'vue';
import axios from 'axios';

function useURLloader(url: string) {
  const data = reactive({
    result: null,  
    loading: true,
    loaded: false,
    error: null,
  });

  axios
    .get(url)
    .then(res => {
      data.loading = false;
      data.result = res.data;
      data.loaded = true;
    })
    .catch(err => {
      data.error = err;
      data.loading = false;
    });
  const refsData = toRefs(data);
  return {
    ...refsData,
  };
}
export default useURLloader;
  • 在页面中使用



3.7 ts对vue3的加持

  • defineComponent服务ts 而存在的
  • 兼容vue2.0的3.0的语法提示

3.8 Teleport - 瞬间移动(新增加标签)

  • 场景:全局弹窗的使用,使用v-if
  • 问题:dialog 被包裹在其他组件之中,容易被干扰
    -样式问题边的容易混乱
  • 使用
// 在index.html 中新建一个id为model的根节点与app层级一样
// index.html
// model 中挂载到model节点上
  • 新建model
// model.vue



  • 子父组件调用


3.9 Suspense - 异步请求

语法:


      
      
    
  • 异步组件的困境
  • Suspense 是Vue3推出的一个内置的特殊组件
  • 如果使用Suspense,要返回一个promise
  1. 使用Suspense实现一个简单异步请求
//AsyncShow.vue




  • 父组件调用
import AsyncShow from './components/AsyncShow.vue';
 
 // 支持具名插槽,第一个default是异步请求data,#fallback是数据会返回前展示的data
 

      
      
    
  • 结果如下:先出现加载中.....,3s之后出现42

2.Suspense支持多个请求

  • 新建一个DogShow.vue 组件
// DogShow.vue


  • 在父组件中引用

import DogShow from './components/DogShow.vue';
import AsyncShow from './components/AsyncShow.vue';

      
      
    
    // 展示错误
    

{{ error }}

  • 结果如下,先出现加载中....,等两个异步组件成功返回展示对应的数据
image4.png
  • 如果有一个异步请求失败,可以使用onErrorCaptured去监听错误
import { defineComponent, onErrorCaptured, ref } from 'vue';
export default defineComponent({
  name: 'App',
  components: { HelloWorld, Model, AsyncShow, DogShow },
  setup() {
    const error = ref(null);
    // 通过这个生命周期函数可以监听Suspense里面的错误
    onErrorCaptured((err: any) => {
      error.value = err;
      return true;
    });
    
      error,
    };
  • 结果展示如下:

AsyncShow展示42,DogShow接口失败,报错

image5.png

3.10 Global API Change(全局API修改)

Vue2全局API遇到的问题
  1. 在单元测试中,全局配置非常容易污染全局环境
  2. 在不同的apps中,共享一份有不同配置的Vue对象,也变的非常困难

vue3.0 解决了直接修改vue,防止污染

  1. 全局配置修改:
  • Vue.config => app.config
  • config.productionTip 被删除
  • config.ignoredElements 改名为 config.isCustomElement
  • config.keyCodes被删除
  1. 全局注册类API
  • Vue.component -> app.component
  • Vue.directtive -> app.directtive
  1. 行为类API
  • Vue.mixins -> app.mixins
  • Vue.use -> app.use
  1. Global API Treeshaking
// vue2 全局导入,API挂载在Vue原型上
import Vue from 'vue'
Vue.nextTick(()=> {})
const obj = Vue.observable()

// vue3  实名导出,方便Treeshaking
import Vue,{nextTick,observable} from 'vue'
Vue.nextTick // undefined

nextTick(()=> {})
const obj = observable()

你可能感兴趣的:(vue3.0新特性)