快速上手Vue3

一.快速上手Vue3

1.使用Vue3的CDN

<script src="https://lib.baomitu.com/vue/3.0.2/vue.global.js"></script>

2.vue-cli

升级到vue-cli v4.5 (删除后再安装)

npm i -g @vue/cli@next

3.使用Vite

利用ES6的import会发送请求去加载文件的特性,拦截这些请求,做一些预编译,省区webpack冗长的打包时间

// npm
$ 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

Vue3的亮点:

1、性能比Vue2快(diff算法优化,)
2、按需编译,体积更小
3、Composition API 组合API
4、更好的支持TS
5、暴露了自定义渲染API
6、更多新的先进的组件

Diff算法优化:

Vue2中的虚拟DOM是进行全量的对比

Vue3的diff算法在创建虚拟DOM的时候会根据DOM中的内容是否会发生变化,添加静态标记(静态标记不同值会有不同的比较方式)

Vue Template Explorer (vue-next-template-explorer.netlify.app)

静态提升:

Vue2中无论元素是否参加更新,每次都会重新创建,然后再渲染

Vue3中对于不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用即可

<div>
  <p>1</p>
  <p>2</p>
  <p>{{msg}}</p>
</div>
import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

const _hoisted_1 = /*#__PURE__*/_createElementVNode("p", null, "1", -1 /* HOISTED */)
const _hoisted_2 = /*#__PURE__*/_createElementVNode("p", null, "2", -1 /* HOISTED */)

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock("div", null, [
    _hoisted_1,
    _hoisted_2,
    _createElementVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)
  ]))
}
cacheHandlers事件监听器缓存:

默认情况下onClick会被视为动态绑定,所以每次都会去追踪他的变化

但是因为是同一个函数,所以没有追踪变化,直接缓存起来复用即可

//未使用cacheHandlers
import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

const _hoisted_1 = ["onClick"]

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock("div", null, [
    _createElementVNode("button", { onClick: _ctx.click }, "123", 8 /* PROPS */, _hoisted_1)
  ]))
}
//使用cacheHandlers 不存在静态标记变量,不需要再次比较
import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock("div", null, [
    _createElementVNode("button", {
      onClick: _cache[0] || (_cache[0] = (...args) => (_ctx.click && _ctx.click(...args)))
    }, "123")
  ]))
}
SSR渲染:

当有大量静态内容时,这些内容会被当做纯字符串推进一个buffer里面,即使存在动态的绑定,会通过模板插值嵌入进去。这样会比通过虚拟dom来渲染的快上很多很多

当静态内容大到一定量级时候,会用_createStaticVNode方法再客户端去省城一个static node,这些静态node会被直接innerHtml,不需要创建对象然后根据对象渲染

Vue3中的Composition API

一,Setup函数

1.setup参数

接收两个参数:propscontext

props:响应式的,当传入新的 prop 时,它将被更新。(不能使用 ES6 解构

export default {
  props: {
    title: String
  },
  setup(props) {
    console.log(props.title)
  }
}

context:普通 JavaScript 对象,暴露了其它可能在 setup 中有用的值

export default {
  setup(props, context) {
    // Attribute (非响应式对象,等同于 $attrs)
    console.log(context.attrs)

    // 插槽 (非响应式对象,等同于 $slots)
    console.log(context.slots)

    // 触发事件 (方法,等同于 $emit)
    console.log(context.emit)

    // 暴露公共 property (函数)
    console.log(context.expose)
  }
}
2.setup执行时机

setup执行先于beforecreate

选项式 APIHook inside setup
beforeCreateNot needed*
createdNot needed*
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted
errorCapturedonErrorCaptured
renderTrackedonRenderTracked
renderTriggeredonRenderTriggered
activatedonActivated
deactivatedonDeactivated
3.setup注意点

3.1 由于在执行setup()的时候,还没有执行声明周期函数,所以在setup中无法使用data和methods

3.2 在 setup() 内部,this 不是该活跃实例的引用,解析其它组件选项之前被调用的,所以 setup() 内部的 this 的行为与其它选项中的 this 完全不同

3.3 setup()只能是同步的不能是异步的

二,Vue3中的响应式数据处理

1.reactive,ref

Vue3中响应式数据通过ES6的Proxy来实现,reactive和ref作用是创建响应式数据

reactive参数必须是对象

ref从性能角度适用于监听简单类型数据。对于复杂类型objet也可以实现响应式(在vue官网中对ref频频出现对arr,object的响应包装,只是在使用时需要.value形式,导致他响应式创建复杂,访问复杂)

ES6结构赋值通常会使数据响应性丢失,使用toRefs保留与源对象的响应式关联

reactive 和 ref 都是用来定义响应式数据的 reactive更推荐去定义复杂的数据类型 ref 更推荐定义基本类型,refreactive 本质我们可以简单的理解为ref是对reactive的二次包装, ref定义的数据访问的时候要多一个.value,使用ref定义基本数据类型,ref也可以定义数组和对象。

<template>
    <div ref="box">
        我是div
	</div>
</template>

<script>
//ref获取dom
import {ref,onMounted} from 'vue'
export default{
    name:'App',
    setup(){
      let box = ref(null)
      
      onMounted(()=>{
          console.log('onMounted',box.value)
      })
        
      return {box}
    }
}
</script>
2.响应式数据实现

Vue2中响应式有很多局限性在Vue3中使用proxy解决:1.对属性的添加,删除动作的检测 2.对数组基于下标的修改,对于.length修改的检测 3.对接MapSet等的支持

a.Proxy

Proxy 是一个对象,它包装了另一个对象,并允许你拦截对该对象的任何交互。使用 Proxy 的一个难点是 this 绑定。我们希望任何方法都绑定到这个 Proxy,而不是目标对象,这样我们也可以拦截它们。使用ES6中的Reflect新特性可以实现

let obj  = {name:'lnj',age:18}
let state = new Proxy(obj,handler:{
         		get(target, property, receiver) {
    				return target[property]
				}
				set(target,property){
                    
                }
            })
b.Reflect(不会阻塞程序进行)

反射机制:反射机制指的是程序在运行时能够获取自身的信息

Reflect是一个内建的对象,用来提供方法去拦截JavaScript操作,他不是一个函数对象,不可构造。(与porxy handlers的方法相同)

let obj  = {name:'lnj',age:18}
let state = new Proxy(obj,handler:{
         		get(target, property, receiver) {
    				return Reflect.get(target, property, receiver)
				}
				set(target,property,value,receiver){
                    return Reflect.set(target, property,value,receiver)
                }
            })
3.递归和非递归监听

3.1 递归监听

默认情况下,无论通过ref还是reactive都是递归监听
存在问题(数据量过大非常消耗性能)

let state = reactive({
    a:'a',
    gf:{
        b:'b',
        f:{
            c:'c',
            s:{
                d:'d'
            }
        }
    }
})
function myFn(){
    console.log(state)
    console.log(state.gf)
    console.log(state.gf.f)
    console.log(state.gf.f.s)
}
return {state,myFn}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PuvHXM1p-1639649691948)(C:\Users\xupt\AppData\Roaming\Typora\typora-user-images\image-20211117174755249.png)]

3.2 非递归监听(shallowReactive,shallowRef)

shallowRef创建数据,Vue监听的是.value的变化,并不是第一层的变化

let state = shallowReactive({
    a:'a',
    gf:{
        b:'b',
        f:{
            c:'c',
            s:{
                d:'d'
            }
        }
    }
})
function myFn(){
    console.log(state)
    console.log(state.gf)
    console.log(state.gf.f)
    console.log(state.gf.f.s)
}
return {state,myFn}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SvsXSKe2-1639649691950)(C:\Users\xupt\AppData\Roaming\Typora\typora-user-images\image-20211117174852825.png)]

3.3 triggerRef方法

根据传入的数据主动去更新界面(没有triggerReactive方法)

let state = shallowRef({
    a:'a',
    gf:{
        b:'b',
        f:{
            c:'c',
            s:{
                d:'d'
            }
        }
    }
})
function myFn(){
    state.value.gf.f.s.d = '4'
    triggerRef(state)
}
return {state,myFn}

3.4 一般情况下我们使用refreactive即可,如果需要监听数据量比较大的时候,使用shallowRefshallowReactive

4. toRaw

proxy代理生成一个proxy对象,但是和原对象的引用指向是一样的

setup(){
    let obj = {name:'l',age:18}
    let state = reactive(obj)
    function myFn(){
        obj.name = 'zs'
        console.log(obj)
    }
    return {state,myFn}
}
//如果直接修改OBJ无法触发响应式,只有修改state才能更新界面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fme0FZz4-1639649691951)(C:\Users\xupt\AppData\Roaming\Typora\typora-user-images\image-20211117182038478.png)]

setup(){
    let obj = {name:'l',age:18}
    let state = reactive(obj)
    let obj2 = toRaw(state)
    console.log(obj === obj2)	//true
    function myFn(){
        obj2.name = 'zs'
        console.log(obj)
    }
    return {state,myFn}
}
//toRaw方法可以获取原始数据

ref和reactive数据类型每次修改都会被追踪,都会更新UI界面,非常损耗性能

如果我们操作不需要追踪更新UI界面,可以使用toRaw方法拿到他的原始数据进行操作,节省性能

setup(){
    let obj = {name:'l',age:18}
    let state = ref(obj)
    let obj2 = toRaw(state)
    let obj3 = toRaw(state.value)
    //ref(obj) —> reactive({value:obj})
    console.log(obj === obj2)	//false
    console.log(obj === obj3)	//true
    function myFn(){
        obj2.name = 'zs'
        console.log(obj)
    }
    return {state,myFn}
}
//toRaw方法可以获取原始数据
5.markRaw
setup(){
    let obj = {name:'l',age:18}
    obj = markRaw(obj)
    let state = reactive(obj)
    function myFn(){
        obj2.name = 'zs'
        console.log(obj)
    }
    return {state,myFn}
}
//永远不被响应式
6.toRef和toRefs

6.1 toRef

setup(){
    let obj = {name:'l',age:18}
    //ref(obj.name)—>ref('l')->reactive({value:'l'})
    //let state = ref(obj.name)
    let state = toRef(obj,'name')
    function myFn(){
        state.value = 'zs'
    }
    return {state,myFn}
}
//如果利用ref将某个对象中的属性变成响应式的数据,我们修改响应式的数据不会影响原始数据
//toRef将一个对象中的属性变成响应式的数据,修改响应式数据会影响原始数据,但是不会触发UI界面更新

ref:赋值,修改响应式不会影响以前数据,界面会更新
toRef:引用,修改响应式数据会影响以前的数据,界面不会更新

6.2 toRefs

setup(){
    let obj = {name:'l',age:18}
    //let state = toRef(obj,'name','age')	//报错
    
    //let name = toRef(obj,'name')
    //let age = toRef(obj,'age')
    
    let {name,age} = ...toRefs(obj)
    function myFn(){
        state.value = 'zs'
    }
    return {name,age,myFn}
}
7.readonly

readonly:创建只读数据,并且是递归只读

shallowReadonly:非递归只读

isReadonly:判断是否是只读

Vue3进阶

一.setup语法糖

1.组件自动注册

<template>
    <Child />
</template>
<script setup>
import Child from './Child.vue'
</script>

2.组件核心API的使用

使用props

通过defineProps指定当前 props 类型,获得上下文的props对象

<script setup>
  import { defineProps } from 'vue'
  const props = defineProps({
    title: String,
  })
</script>

使用emits

使用defineEmit定义当前组件含有的事件,并通过返回的上下文去执行 emit

<script setup>
  import { defineEmits } from 'vue'
  const emit = defineEmits(['change', 'delete'])
</script>

获取 slots 和 attrs

可以通过useContext从上下文中获取 slots 和 attrs。不过提案在正式通过后,废除了这个语法,被拆分成了useAttrsuseSlots

<script setup>
  import { useContext } from 'vue'
  const { slots, attrs } = useContext()
    
  import { useAttrs, useSlots } from 'vue'
  const attrs = useAttrs()
  const slots = useSlots()
</script>

3.defineExpose API

传统的写法,我们可以在父组件中,通过 ref 实例的方式去访问子组件的内容,但在 script setup 中,该方法就不能用了,setup 相当于是一个闭包,除了内部的 template模板,谁都不能访问内部的数据和方法。

如果需要对外暴露 setup 中的数据和方法,需要使用 defineExpose AP

<script setup>
	import { defineExpose } from 'vue'
	const a = 1
	const b = 2
	defineExpose({
	    a
	})
</script>

4.属性和方法无需返回,直接使用

在以往的写法中,定义数据和方法,都需要在结尾 return 出去,才能在模板中使用。在 script setup 中,定义的属性和方法无需返回,可以直接使用

<template>
  <div>
   	<p>My name is {{name}}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const name = ref('Sam')
</script>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值