慕课1299前端面试-VUE3相关整理

VUE3模块

1. VUE3 比 VUE2 有什么优势?

在这里插入图片描述

2. VUE3 生命周期

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3. ref 、toRef、reactive、toRefs示例

ref 示例

在这里插入图片描述

<template>
  <p>ref demo {
    
    {
    
     ageRef }}{
    
    {
    
     state.name }}</p>
</template>
<script>
import {
    
     reactive, ref } from 'vue'
export default {
    
    
  name: 'Ref',
  setup() {
    
    
    const ageRef = ref(20) // 值类型 响应式
    const nameRef = ref('ref的使用')

    const state = reactive({
    
    
      name: nameRef,
    })

    setTimeout(() => {
    
    
      console.log('ageRef', ageRef.value) // 1.5s后 ageRef 25

      ageRef.value = 25 // .value 修改值
      nameRef.value = '除template模版和reactive中,其他地方都使用.value'
    }, 1500)
    return {
    
    
      ageRef,
      state,
    }
  },
}
</script>

toRef 示例

在这里插入图片描述

<template>
  <p>toRef demo --- {
    
    {
    
     ageRef }} -- {
    
    {
    
     state.name }} {
    
    {
    
     state.age }}</p>
</template>

<script>
import {
    
     toRef } from 'vue'

export default {
    
    
  name: 'toRef',
  setup() {
    
    
    const state = reactive({
    
    
      // 普通对象想实现响应式用 reactive
      age: 20,
      name: 'toRef的使用',
    })

    // toRef 如果用于普通对象(非响应式对象),产出的结果不具备响应式
    // const state = {
    
    
    //   age: 20,
    //   name: '普通对象,不具备响应式',
    // }

    // reactive 中的某一个属性想要 单独拿出来 实现响应式 使用 toRef
    const ageRef = toRef(state, 'age') // 引用 state 中的 age属性

    setTimeout(() => {
    
    
      state.age = 25
    }, 1500)

    setTimeout(() => {
    
    
      ageRef.value = 30 // .value 修改值
    }, 3000)

    return {
    
    
      ageRef,
      state,
    }
  }
}
</script>

toRefs 示例

在这里插入图片描述

<template>
  <p>toRefs demo {
    
    {
    
     age }}{
    
    {
    
     name }}</p>
</template>

<script>
import {
    
     toRefs ,reactive} from 'vue'

export default {
    
    
  name: 'toRefs',
  setup() {
    
    
    const state = reactive({
    
    
      age: 20,
      name: 'toRefs示例',
    })

    const stateAsRefs = toRefs(state) // 将响应式对象,变成普通对象

    // 每个属性,都是 ref对象。 因此取出 age 要使用 Ref 结尾命名
    // const { age: ageRef, name: nameRef } = stateAsRefs
    // return {
    
    
    //   然后 return 上面命名的 ageRef, 模版中使用 {
    
    {ageRef}}
    //   ageRef,
    //   nameRef,
    // }
    //  此时一旦 state中的属性多了,需要给每一个都命名,不利用维护.

    setTimeout(() => {
    
    
      console.log('如果直接...state,会失去响应式。而使用toRefs没事')
      state.age = 25
    }, 1500)
    // 因此这样 更加方便直观
    return {
    
    
      // ...state | 如果直接使用 ...state ,模版中 {
    
    {name}} 会丢失响应式
      // state | 如果这样使用 state,模版中 需要{
    
    {state.name}} 不会丢失响应式,但是很繁琐
      ...stateAsRefs, // = return stateAsRefs 这种写法
    }
  },
}
</script>
  • toRef 是针对 state中的 某一个属性
  • toRefs 是针对 state 中的 所有属性

在这里插入图片描述

在这里插入图片描述

4. 进阶,深入理解ref

在这里插入图片描述

为何需要 ref ?

在这里插入图片描述
不具备响应式 – 示例

<template>
  <p>
    why ref demo {
    
    {
    
     age1 }}-[...state会丢失响应式]|
    {
    
    {
    
     state.age }}-[具备响应式]
  </p>
</template>

<script>
import {
    
     reactive } from 'vue'

export default {
    
    
  name: 'WhyRef',
  setup() {
    
    
    // Proxy 对象(针对对象才具备响应式)
    const state = reactive({
    
    
      age: '20',
      name: 'reactive针对对象,ref针对普通类型',
    })

    let age1 = 20 // 普通值类型,不具备响应式

    setTimeout(() => {
    
    
      console.log('普通值类型数据,并不具备响应式')
      age1 = 25 // 普通值类型 不具备响应式
      state.age = 25 // = let age = 25 不具备响应式
    }, 1500)

    return {
    
    
      age1, // 普通值类型 不具备响应式
      ...state, // 如果直接使用 ...state ,模版中 {
    
    {age}} 会丢失响应式
    }
  },
}
</script>

具备响应式 – 示例

<template>
  <p>
    why ref demo
    {
    
    {
    
     state.age }}-[具备响应式] ,| {
    
    {
    
     age1 }}-[具备响应式]
  </p>
</template>

<script>
import {
    
     reactive } from 'vue'

export default {
    
    
  name: 'WhyRef',
  setup() {
    
    
    // Proxy 对象(针对对象才具备响应式)
    const state = reactive({
    
    
      age: '20',
      name: 'reactive针对对象,ref针对普通类型',
    })

    const age1 = computed(() => {
    
    
      return state.age + 1
    })
    // computed 返回的也是一个类似 ref的值,类似ref的机制
    // 也可以通过 .value来获取值,但是不要修改,computed的值不太适合修改
    console.log('age1.value', age1.value)

    setTimeout(() => {
    
    
      state.age = 25 // = let age = 25 不具备响应式
    }, 1500)

    return {
    
    
      state, // 模版使用 state.age具备响应式
      age1, // 具备响应式
    }
  },
}
</script>
<template>
  <p>{
    
    {
    
     x }}{
    
    {
    
     y }} -- 此时具备响应式</p>
</template>

<script>
import {
    
     reactive, toRefs } from 'vue'

function useFeatureX() {
    
    
  const state = reactive({
    
    
    x: 1,
    y: 2,
  })
  return toRefs(state)
  // return state  模版中{
    
    { state1.y }} - 不进行结构需要这种方式写
}

export default {
    
    
  name: 'WhyRef',
  setup() {
    
    
    const {
    
     x, y } = useFeatureX()
    // const state1 = useFeatureX() 不进行结构
    return {
    
    
      // state1, // 不进行结构
    }
  },
}
</script>

5. 为何需要 .value ?

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

6. VUE3 升级了哪些重要的功能 ?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

7. 怎么使用Composition API 实现逻辑复用?

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8. VUE3 如何实现响应式?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
请添加图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9. 深入 proxy ,看下面封装好的proxy

// 创建响应式
function reactive(target = {
     
     }) {
    
    
  if (typeof target !== 'object' || target == null) {
    
    
    // 不是对象或数组,则返回
    return target
  }

  // 代理配置
  const proxyConf = {
    
    
    get(target, key, receiver) {
    
    
      // 只处理本身(非原型的) 属性
      const ownKeys = Reflect.ownKeys(target)
      if (ownKeys.includes(key)) {
    
    
        console.log('get 获取', key) // 监听
      }

      const result = Reflect.get(target, key, receiver)
      //深度监听
      // 如果直接返回 retun result , data中的info 会被上面 if判断返回

      return reactive(result)// 返回结果
    },
    set(target, key, val, receiver) {
    
    
      // 重复的数据,不处理
      if (val === target[key]) {
    
    
        return true
      }

      // 只处理本身(非原型的) 属性
      const ownKeys = Reflect.ownKeys(target)
      if (ownKeys.includes(key)) {
    
    
        console.log('已有的 key', key) // 监听
      } else {
    
    
        console.log('新增的 key', key);
      }

      const result = Reflect.set(target, key, val, receiver)
      console.log('set 设置', key, val);
      // console.log('result 是否设置成功',result); // true
      return result // 返回结果
    },
    deleteProperty(target, key) {
    
    
      const result = Reflect.defineProperty(target, key)
      console.log('delete property', key);
      // console.log('result 是否设置成功',result) // true
      return result // 返回结果
    }
  }

  //  生成代理对象
  const observed = new Proxy(target, proxyConf)
  return observed
}
// 测试数据
const data = {
    
    
  name: 'proxy实现响应式', // proxyData.name | 会 get name 获取到name名
  age: 20,
  info: {
    
     // proxyData.info.city | get info 并没有 get到city
    city: '北京,需要深度监听', // 在get 时返回 reactive(result) 可以get 到 city
    a: {
    
     // 如果访问 a , a具有响应式
      b: 100 // b未被访问,b不具备响应式
    }
  }
}

// 将要实现响应式的 data对象 传入 reactive函数中
const proxyData = reactive(data)

在这里插入图片描述

  • 性能如何提升的?
  • Oject.defineProperty 是一开始就进行递归,直接递归到底
  • Proxy 是什么时候get 什么时候再进行递归,不get 获取的不进行递归

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

10. V3 移除 .sync属性,用v-model 替代

在这里插入图片描述
以下是一个示例代码,其中包括一个父组件 和一个子组件 ,它们通过 v-bind 和 $emit 实现了父子数据的双向绑定:

<!-- 父组件 TextDocument.vue -->
<template>
  <div>
    <h1>{
    
    {
    
     doc.title }}</h1>
    <title-editor v-bind:title="doc.title" v-on:update:title="updateTitle"></title-editor>
  </div>
</template>

<script>
import TitleEditor from './TitleEditor.vue'

export default {
    
    
  components: {
    
    
    TitleEditor
  },
  data() {
    
    
    return {
    
    
      doc: {
    
    
        title: "默认标题"
      }
    }
  },
  methods: {
    
    
    updateTitle(newTitle) {
    
    
      this.doc.title = newTitle;
    }
  }
};
</script>


<!-- 子组件 TitleEditor.vue -->
<template>
  <div>
    <input type="text" v-bind:value="title" v-on:input="updateTitle($event.target.value)">
  </div>
</template>

<script>
export default {
    
    
  props: ['title'],
  methods: {
    
    
    updateTitle(newTitle) {
    
    
      this.$emit('update:title', newTitle);
    }
  }
}
</script>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

11. watch 和 watchEffect 的区别 ?

在这里插入图片描述

watch 监听 ref 变化

<!-- 先看watch 监听 ref-->
<template>
  <p>watch vs watchEffect</p>
  <p>{
    
    {
    
     numberRef }}</p>
  <p>{
    
    {
    
     name }}{
    
    {
    
     age }}</p>
</template>

<script>
import {
    
     reactive, ref, toRefs, watch, watchEffect } from 'vue'

export default {
    
    
  name: 'watch',
  setup() {
    
    
    const numberRef = ref(100) // watch监听
    watch(
      numberRef,
      (newNumber, oldNumber) => {
    
    
        // watch 不需要使用.value
        console.log('ref watch', newNumber, oldNumber)
        // 调用setTimeout 打印结果 200 100
      },
      {
    
    
        immediate: true, // 初始化之前就监听,可选
        // 打印结果 ref watch 100 undefined
        // 为什么是undefined,因为没有修改值,监听初始化就是undefined
      }
    )

    // setTimeout(() => {
    
    
    //   numberRef.value = 200
    // }, 1500)

    return {
    
    
      numberRef
    }
  },
}
</script>

在这里插入图片描述

在这里插入图片描述

watch 监听 reactive 变化

<template>
  <p>watch vs watchEffect</p>
  <p>{
    
    {
    
     numberRef }}</p>
  <p>{
    
    {
    
     name }}{
    
    {
    
     age }}</p>
</template>
<script>
import {
    
     reactive, ref, toRefs, watch } from 'vue'
export default {
    
    
  name: 'watch',
  setup() {
    
    
    const numberRef = ref(100) // watch监听
    const state = reactive({
    
    
      name: 'watch 监听 reactive',
      age: 20,
    })

    watch(
      () => state.age,
      // 第二个参数,回调函数
      (newAge, oldAge) => {
    
    
        console.log('state watch', newAge, oldAge)
      },
      // 第三个参数,配置项
      {
    
    
        immediate: true, // 初始化之前就监听,可选
        deep: true, // 深度监听,
        // 如果age是一个对象或数组,就可以深度监听 其中的变化
      }
    )
    setTimeout(() => {
    
    
      state.age = 25
    }, 1500)
    setTimeout(() => {
    
    
      state.name = '是否会监听到'
    }, 3000)

    return {
    
    
      numberRef,
      ...toRefs(state),
    }
  },
}
</script>

在这里插入图片描述

watchEffect 监听 ref 和 reactive

setup中 state数据 和 上面 watch 监听代码一样
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

12. setup 中如何获取组件实例

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
const instance = getCurrentInstance() 就是组件的实例
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

13. VUE3 为何比 VUE2 快? 编译优化如下

在这里插入图片描述

PatchFlag 静态标记

在这里插入图片描述

template模版

<div>
  <span>hello vue3</span>
  <span>{
    
    {
    
    msg}} 使用TEXT标记</span>
  <span :id="name">使用ClASS标记</span>
  <span :id="name">{
    
    {
    
    msg}} 使用TEXTPROPS标记</span>
  <span :id="name" :msg="msg">使用PROPS 放入数组中标记多个</span>
</div>

patchFlag标记后

import {
    
     createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
    
    
  return (_openBlock(), _createElementBlock("div", null, [
    _createElementVNode("span", null, "hello vue3"),
    _createElementVNode("span", null, _toDisplayString(_ctx.msg) + " 使用TEXT标记", 1 /* TEXT */),
    _createElementVNode("span", {
    
     id: _ctx.name }, "使用ClASS标记", 8 /* PROPS */, ["id"]),
    _createElementVNode("span", {
    
     id: _ctx.name }, _toDisplayString(_ctx.msg) + " 使用TEXT 和 PROPS标记", 9 /* TEXT, PROPS */, ["id"]),
    _createElementVNode("span", {
    
    
      id: _ctx.name,
      msg: _ctx.msg
    }, "使用PROPS 放入数组中标记多个", 8 /* PROPS */, ["id", "msg"])
  ]))
}

// Check the console for the AST

在这里插入图片描述
1 就是 TEXT 表示 VNode 的文本内容已经发生了变化,需要更新视图
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

hositStatic 缓存合并

在这里插入图片描述
template模版中

<div>
  <span>hello vue3</span>
  <span>hello vue3</span>
  <span>hello vue3</span>
  <span>{
    
    {
    
    msg}}</span>
</div>

在这里插入图片描述

hoistStatic 使用 -1 /* HOISTED */ 就是缓存和提升

import {
    
     createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

const _hoisted_1 = /*#__PURE__*/_createElementVNode("span", null, "hello vue3", -1 /* HOISTED */)
const _hoisted_2 = /*#__PURE__*/_createElementVNode("span", null, "hello vue3", -1 /* HOISTED */)
const _hoisted_3 = /*#__PURE__*/_createElementVNode("span", null, "hello vue3", -1 /* HOISTED */)

export function render(_ctx, _cache, $props, $setup, $data, $options) {
    
    
  return (_openBlock(), _createElementBlock("div", null, [
    _hoisted_1,
    _hoisted_2,
    _hoisted_3,
    _createElementVNode("span", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)
  ]))
}

// Check the console for the AST

如果相邻节点 >= 10,会合并为一个节点

import {
    
     createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, createStaticVNode as _createStaticVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

const _hoisted_1 = /*#__PURE__*/_createStaticVNode("<span>hello vue3</span><span>hello vue3</span><span>hello vue3</span><span>hello vue3</span><span>hello vue3</span><span>hello vue3</span><span>hello vue3</span><span>hello vue3</span><span>hello vue3</span><span>hello vue3</span>", 10)

export function render(_ctx, _cache, $props, $setup, $data, $options) {
    
    
  return (_openBlock(), _createElementBlock("div", null, [
    _hoisted_1,
    _createElementVNode("span", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)
  ]))
}

// Check the console for the AST

在这里插入图片描述

cacheHandler 缓存事件

在这里插入图片描述

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("span", {
    
    
      onClick: _cache[0] || (_cache[0] = (...args) => (_ctx.clickHandler && _ctx.clickHandler(...args)))
    }, "hello vue3")
  ]))
}

// Check the console for the AST

SSR 优化

在这里插入图片描述
在这里插入图片描述

勾选 SSR 后,它在渲染的时候,渲染出了字符串,它没有经过vdom转换就可以了

<div>
  <span>hello vue3</span>
  <span>hello vue3</span>
  <span>hello vue3</span>
  <span>{
    
    {
    
     msg }}</span>
</div> 
import {
    
     mergeProps as _mergeProps } from "vue"
import {
    
     ssrRenderAttrs as _ssrRenderAttrs, ssrInterpolate as _ssrInterpolate } from "vue/server-renderer"

export function ssrRender(_ctx, _push, _parent, _attrs, $props, $setup, $data, $options) {
    
    
  const _cssVars = {
    
     style: {
    
     color: _ctx.color }}
  _push(`<div${
      
      
    _ssrRenderAttrs(_mergeProps(_attrs, _cssVars))
  }><span>hello vue3</span><span>hello vue3</span><span>hello vue3</span><span>${
      
      
    _ssrInterpolate(_ctx.msg)
  }</span></div>`)
}

// Check the console for the AST

tree shaking

编译时,根据不同的情况,引入不同的API。它不会全部引入,而是按需引入。
在这里插入图片描述

  • 根据上面 SSR 的代码,需要什么就 import什么
  • 动态去 import 引入,不需要的就不去import

在这里插入图片描述
在这里插入图片描述

总结

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_46426412/article/details/130857239