【vue3总结知识点——精简一】

vue3总结知识点

  • 认识vue3
  • Composition API
    • setup
      • 执行时机
      • setup 包含的生命周期
    • ref获取页面数据
    • reactive
    • reactive与ref的异同
  • 比较Vue2与Vue3的响应式
    • vue2的响应式
    • Vue3的响应式
  • 计算属性与监视
  • Vue3与Vue2的生命周期对比
  • 自定义hook函数
  • toRefs
  • ref获取元素

认识vue3

Vue是一套用于构建用户界面的渐进式框架。
Vue3也支持Vue2的大多数特性
更好的支持了TypeScript
性能得到了更大的提升:使用proxy代替了defineProperty实现数据响应式
增加了很多的新特性:Composition API(组合式API),新组件(Fragment/Teleport/Suspense)等等.

作者也是海贼王的海粉,有兴趣的可以讨论讨论
【vue3总结知识点——精简一】_第1张图片

Composition API

setup

新的option, 所有的组合API函数都在此使用, 只在初始化时执行一次(beforeCreate之前执行)
函数如果返回对象, 对象中的属性或方法, 模板中可以直接使用

注意:
this是undefined, 不能通过this来访问data/computed/methods / props
methods中可以访问setup提供的属性和方法, 但在setup方法中不能访问data和methods\

  • setup的参数
    • setup(props, context) / setup(props, {attrs, slots, emit})

    • props: 包含props配置声明且传入了的所有属性的对象

    • context:data内容

    • attrs: 包含没有在props配置中声明的属性的对象, 相当于 this.$attrs

    • slots: 包含所有传入的插槽内容的对象, 相当于 this.$slots

    • emit: 用来分发自定义事件的函数, 相当于 this.$emit

编写方式

<template>
  <div class="hello">
    <h1>{{ name }}h1>
  div>
template>
<script>
export default {
  name: "hello",
  setup(msg) {
    console.log(msg);
    return { name:"cloud" };
  },
};
script>
<style scoped>
style>

执行时机

setup 会在 beforeCreate 之前执行。

setup 包含的生命周期

需要导入相应的生命周期这些生命周期都在依赖中注意写花括号 { } es6语法

  • onBeforeMount——挂载开始前调用
  • onMounted——挂载后调用
  • onBeforeUpdate——当响应数据改变,且重新渲染前调用
  • onUpdated——重新渲染后调用
  • onBeforeUnmount——Vue实例销毁前调用
  • onUnmounted——实例销毁后调用
  • onActivated——当keep-alive组件被激活时调用
  • onDeactivated——当keep-alive组件取消激活时调用
  • onErrorCaptured——从子组件中捕获错误时调用
import { onMounted } from 'vue'
export default {
  name: "hello",
  setup(msg) {
    onMounted(()=>{
      console.log("onMounted");
    })
    console.log(msg);
    return { name:"cloud" };
  },
  beforeCreate(){
    console.log("beforeCreate");
  }
};

ref获取页面数据

(1)作用: 定义一个数据的响应式
(2)语法: const xxx = ref(initValue):
(3)创建一个包含响应式数据的引用(reference)对象;
js中操作数据: xxx.value;
模板中操作数据: 不需要.value;
(4)一般用来定义一个基本类型的响应式数据

别忘了引入ref

import { ref,onMounted } from 'vue'
	//创建定时器增加count值
    let count = ref(1);
    setInterval(()=>{
      count.value++
    },1000)
    return { name:"cloud",count:count };

reactive

1、作用: 定义多个数据的响应式
2、语法:const proxy = reactive(obj):
接收一个普通对象然后返回该普通对象的响应式代理器对象
响应式转换是“深层的”:会影响对象内部所有嵌套的属性
基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据都是响应式的

<template>
  <h2>name: {{state.name}}h2>
  <h2>age: {{state.age}}h2>
  <h2>wife: {{state.wife}}h2>
  <hr>
  <button @click="update">更新button>
template>

<script>
import {
  reactive,
} from 'vue'
export default {
  setup () {
    const state = reactive({
      name: 'tom',
      age: 25,
      wife: {
        name: 'marry',
        age: 22
      },
    })
    console.log(state, state.wife)
    const update = () => {
      state.name += '--'
      state.age += 1
      state.wife.name += '++'
      state.wife.age += 2
    }
    return {
      state,
      update,
    }
  }
}
script>

reactive与ref的异同

同:

  • 是Vue3的 composition API中2个最重要的响应式API

异:

  • ref用来处理基本类型数据, reactive用来处理对象(递归深度响应式)
  • 如果用ref对象/数组, 内部会自动将对象/数组转换为reactive的代理对象
  • ref内部: 通过给value属性添加getter/setter来实现对数据的劫持
  • reactive内部: 通过使用Proxy来实现对对象内部所有数据的劫持, 并通过Reflect操作对象内部数据

比较Vue2与Vue3的响应式

vue2的响应式

核心:
对象: 通过defineProperty对对象的已有属性值的读取和修改进行劫持(监视/拦截);
数组: 通过重写数组更新数组一系列更新元素的方法来实现元素修改的劫持;
问题:
对象直接新添加的属性或删除已有属性, 界面不会自动更新;
直接通过下标替换元素或更新length, 界面不会自动更新 arr[1] = {};

//核心方法  -
Object.defineProperty(obj, prop, descriptor)
// obj:要在其上定义属性的对象。
// prop:要定义或修改的属性的名称。
// descriptor:将被定义或修改的属性描述符。
Object.defineProperty(对象, 属性, {   
  get () {},      
  set () {} 
}) 

Vue3的响应式

核心:

(1)通过Proxy(代理): 拦截对data任意属性的任意(13种)操作, 包括属性值的读写, 属性的添加, 属性的删除等;

(2)通过 Reflect(反射): 动态对被代理对象的相应属性进行特定的操作

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Proxy 与 Reflecttitle>
head>
<body>
  <script>
    const user = {
      name: "John",
      age: 12
    };
    /* 
    proxyUser是代理对象, user是被代理对象
    后面所有的操作都是通过代理对象来操作被代理对象内部属性
    */
    const proxyUser = new Proxy(user, {
      get(target, prop) {
        console.log('劫持get()', prop)
        return Reflect.get(target, prop)
      },
      set(target, prop, val) {
        console.log('劫持set()', prop, val)
        return Reflect.set(target, prop, val); // (2)
      },
      deleteProperty (target, prop) {
        console.log('劫持delete属性', prop)
        return Reflect.deleteProperty(target, prop)
      }
    });
    // 读取属性值
    console.log(proxyUser===user)
    console.log(proxyUser.name, proxyUser.age)
    // 设置属性值
    proxyUser.name = 'bob'
    proxyUser.age = 13
    console.log(user)
    // 添加属性
    proxyUser.sex = '男'
    console.log(user)
    // 删除属性
    delete proxyUser.sex
    console.log(user)
  script>
body>
html>
new Proxy(data, {
	// 拦截读取属性值
    get (target, prop) {
    	return Reflect.get(target, prop)
    },
    // 拦截设置属性值或添加新属性
    set (target, prop, value) {
    	return Reflect.set(target, prop, value)
    },
    // 拦截删除属性
    deleteProperty (target, prop) {
    	return Reflect.deleteProperty(target, prop)
    }
})
proxy.name = 'tom'   

计算属性与监视

computed函数:
与computed配置功能一致;
有getter和setter;

watch函数
与watch配置功能一致;
只有getter;
监视指定的一个或多个响应式数据, 一旦数据变化, 就自动执行监视回调;
默认初始时不执行回调, 但可以通过配置immediate为true, 来指定初始时立即执行第一次;
通过配置deep为true, 来指定深度监视;

watchEffect函数
不用直接指定要监视的数据, 回调函数中使用的哪些响应式数据就监视哪些响应式数据;
默认初始时就会执行第一次, 从而可以收集需要监视的数据;
监视数据发生变化时回调;

<template>
  <h2>Apph2>
  fistName: <input v-model="user.firstName"/><br>
  lastName: <input v-model="user.lastName"/><br>
  fullName1: <input v-model="fullName1"/><br>
  fullName2: <input v-model="fullName2"><br>
  fullName3: <input v-model="fullName3"><br>
template>
<script lang="ts">
import {
  reactive,
  ref,
  computed,
  watch,
  watchEffect
} from 'vue'
export default {
  setup () {
    const user = reactive({
      firstName: 'A',
      lastName: 'B'
    })
    // 只有getter的计算属性
    const fullName1 = computed(() => {
      console.log('fullName1')
      return user.firstName + '-' + user.lastName
    })
    // 有getter与setter的计算属性
    const fullName2 = computed({
      get () {
        console.log('fullName2 get')
        return user.firstName + '-' + user.lastName
      },
      set (value: string) {
        console.log('fullName2 set')
        const names = value.split('-')
        user.firstName = names[0]
        user.lastName = names[1]
      }
    })
    const fullName3 = ref('')
    /* 
    使用watch的2个特性:深度监视  初始化立即执行
    */
    watch(user, () => {
      fullName3.value = user.firstName + '-' + user.lastName
    }, {
      immediate: true,  // 是否初始化立即执行一次, 默认是false
      deep: true, // 是否是深度监视, 默认是false
    })
    /* 
    watch默认在数据发生改变时执行回调
    */
    watch(fullName3, (value) => {
      console.log('watch')
      const names = value.split('-')
      user.firstName = names[0]
      user.lastName = names[1]
    })
    return {
      user,
      fullName1,
      fullName2,
      fullName3
    }
  }
}
script>

Vue3与Vue2的生命周期对比

与 2.x 版本生命周期相对应的组合式 API

1、 beforeCreate -> 使用 setup()
2、created -> 使用 setup()
3、 beforeMount -> onBeforeMount
4、mounted -> onMounted
5、beforeUpdate -> onBeforeUpdate
6、updated -> onUpdated
7、beforeDestroy -> onBeforeUnmount
8、destroyed -> onUnmounted
9、errorCaptured -> onErrorCaptured

新增的钩子函数

组合式 API 还提供了以下调试钩子函数:

onRenderTracked
onRenderTriggered

自定义hook函数

  • 使用Vue3的组合API封装的可复用的功能函数
  • 自定义hook的作用类似于vue2中的mixin技术
  • 自定义Hook的优势: 很清楚复用功能代码的来源, 更清楚易懂

鼠标点击位置坐标案例:

<template>
<div>
  <h2>x: {{x}}, y: {{y}}h2>
div>
template>
<script>
import {
  ref
} from "vue"
//在组件中引入并使用自定义hook
import useMousePosition from './hooks/useMousePosition'
export default {
  setup() {
    const {x, y} = useMousePosition()
    return {
      x,
      y,
    }
  }
}
script>

//hook.js
import { ref, onMounted, onUnmounted } from 'vue'
//收集用户鼠标点击的页面坐标
//自定义hook函数
export default function useMousePosition () {
  // 初始化坐标数据
  const x = ref(-1)
  const y = ref(-1)
  // 用于收集点击事件坐标的函数
  const updatePosition = (e: MouseEvent) => {
    x.value = e.pageX
    y.value = e.pageY
  }
  // 挂载后绑定点击监听
  onMounted(() => {
    document.addEventListener('click', updatePosition)
  })
  // 卸载前解绑点击监听
  onUnmounted(() => {
    document.removeEventListener('click', updatePosition)
  })
  return {x, y}
}

toRefs

把一个响应式对象转换成普通对象,该普通对象的每个 property 都是一个 ref

应用: 当从合成函数返回响应式对象时,toRefs 非常有用,这样消费组件就可以在不丢失响应式的情况下对返回的对象进行分解使用

问题: reactive 对象取出的所有属性值都是非响应式的

解决: 利用 toRefs 可以将一个响应式 reactive 对象的所有原始属性转换为响应式的 ref 属性

<template>
  <h2>App</h2>
  <h3>foo: {{foo}}</h3>
  <h3>bar: {{bar}}</h3>
  <h3>foo2: {{foo2}}</h3>
  <h3>bar2: {{bar2}}</h3>
 
 
</template>
 
<script lang="ts">
import { reactive, toRefs } from 'vue'
/*
toRefs:
  将响应式对象中所有属性包装为ref对象, 并返回包含这些ref对象的普通对象
  应用: 当从合成函数返回响应式对象时,toRefs 非常有用,
        这样消费组件就可以在不丢失响应式的情况下对返回的对象进行分解使用
*/
export default {
 
  setup () {
    const state = reactive({
      foo: 'a',
      bar: 'b',
    })
 
    const stateAsRefs = toRefs(state)
 
    setTimeout(() => {
      state.foo += '++'
      state.bar += '++'
    }, 2000);
 
    const {foo2, bar2} = useReatureX()
 
    return {
      // ...state,
      ...stateAsRefs,
      foo2, 
      bar2
    }
  },
}
 
function useReatureX() {
  const state = reactive({
    foo2: 'a',
    bar2: 'b',
  })
 
  setTimeout(() => {
    state.foo2 += '++'
    state.bar2 += '++'
  }, 2000);
 
  return toRefs(state)
}
 
</script>

ref获取元素

利用ref函数获取组件中的标签元素

注意:声明一个 ref 来存放该元素的引用;
必须和模板里的 ref 同名;

让输入框自动获取焦点:

<template>
  <h2>App</h2>
  <input type="text">---
  <input type="text" ref="inputRef">
</template>
 
<script lang="ts">
import { onMounted, ref } from 'vue'
/* 
ref获取元素: 利用ref函数获取组件中的标签元素
功能需求: 让输入框自动获取焦点
*/
export default {
  setup() {
    //声明一个 ref 来存放该元素的引用
		//必须和模板里的 ref 同名
    const inputRef = ref<HTMLElement|null>(null)
 
    onMounted(() => {
      inputRef.value && inputRef.value.focus()
    })
 
    return {
      inputRef
    }
  },
}
</script>

Remember, Hope is a good thing, maybe the best of things. And no good thing ever dies.

记着,希望是个好东西,也许是世间最好的东西,好东西从不会逝去。

你可能感兴趣的:(前端基础,javascript,前端,vue.js)