Vue3笔记

Vue3的理解或者了解

主要就是几点

  1. 性能更好了
    相应是的原理变成了Proxy,VNode Diff算法进行了优化

  2. 体积更小了
    所有的API都是按需导入的

  3. 对TS的支持更好了 本身就是TS写的

  4. Composition API(组合API)
    对于大型项目更利于代码的组织和复用

  5. 新增加了一些特性(Fragment、Suspense、Teleport…)

1.Vue3之所以设计为按需导入,是为了使得开发中尽可能减小对源码的依赖,减少源码的文件大小,是的B/S加载文件速度加快,这就称为tree-shaking

2.Vue3速度快的原因

  • 按需导入(tree-shaking),能够在加载时不用加载那么多的源码
  • 静态提升(hoistSatic,源于Diff算法的优化),对那些动态变化的节点标记在更新时就只需要对比节点的元素(就是原来Vue2会比较追层比较所有节点,Vue3就不会比较全部了)
  • 事件侦听器(cacheHandlers),Vue3中,事件函数如果执行过一次,那么就会缓存起来等待复用
  • Vue3的源码都是TS写的

注意

  1. Vue3中奖同一功能的数据和处理数据的业务逻辑放在一起
  2. Vue2适合开发小项目,Vue3组合API更加适合开发大型项目
  3. Vue3不必只有一个根节点(这中特性称为Fragment,内部操作会嵌套一层虚拟节点)

使用Vite创建Vue项目

npm init vite-app <project-name>
cd  <project-name>
npm install
npm run dev
vite打包和webpack打包的区别

在这里插入图片描述
在这里插入图片描述
main.js中的内容
在这里插入图片描述

对比Vue2中的main.js
import Vue from 'vue'
import App from './App'

new Vue({

el: '#app',

render: h => h(App)

})

组合API

setup入口函数

在这里插入图片描述

  1. 执行时机比beforeCreate 函数早
  2. this 为undefined
  3. vue3 可以在setup()中渲染dom, 也就是说可以不用通过在template 标签中书写dom
  4. 建议数据和方法都写在 setup 函数中,并通过 return 进行返回可在模版中直接使用(一般情况下 setup 不能为异步函数)
  5. return 的值要用{}包起来
  6. setup 中的第一个参数能够拿到 props 中的数据
reactive

reactive 是一个函数,用来将普通对象/数组包装成响应式式数据使用(基于 Proxy)

  1. 需要从vue中导入在使用
import { reactive } from 'vue'
//reactive 内部的对象也是一个 reactive类型的数据
console.log(isReactive(state.hobby))
ref

也是用来包装响应式数据, 如果不确定数据是什么数据类型, 一般就用ref, 建议就都用ref 包装所有数据, 可以替代reactive
在这里插入图片描述

  1. 需要从vue中导入再使用
import { ref } from 'vue'
  1. 如果要拿到ref 包装的数据, 要加上 .value
  2. 这种写法会比reactive 调用数据多写一点, 如果是确定的数据类型, 可以用reactive
  3. ref 的底层是利用 reactive 进行包装 ( 比如将 ref(12), 等价于, reactive({value:12}) ), 所以在调用 ref 数据时需要加一个 .value ; ref 数据在视图中的调用不用加 .value
toRef 让数据具备响应式

在这里插入图片描述

  1. 对state.age 的修改会影响转换后的 age , 对 age 的修改会影响原来的 state.age
toRefs 可以转换响应式对象中的所有的属性为单独的响应式的 ref 对象
  1. 第一种方式
//toRefs 可以转换响应式对象中的所有的属性为单独的响应式的ref对象
const { name, age, address } = toRefs(state) 
  1. 第二种方式
    在这里插入图片描述
  2. toRefs用来把响应式对象转换成普通对象,把对象中的每一个属性,包裹成ref对象
补充

也就是说这里的hobby 是ref中包裹的复杂数据类型, 也就具备reactive类型, 但如果同级有一个简单数据类型如name:‘zs’, 那么这里的name 就不具备reactive 类型
在这里插入图片描述

ref、toRef、toRefs 小结

建议就用 ref 来设置响应式数据, 用 toRefs 对对象中所有属性进行响应式设置

  1. ref、toRef、toRefs 都可以将某个对象中的属性变成响应式数据

  2. ref的本质是拷贝,修改响应式数据,不会影响到原始数据,视图会更新

  3. toRef、toRefs的本质是引用,修改响应式数据,会影响到原始数据,视图不会更新

  4. toRef 一次仅能设置一个数据,接收两个参数,第一个参数是哪个对象,第二个参数是对象的哪个属性

  5. toRefs接收一个对象作为参数,它会遍历对象身上的所有属性,然后挨个调用toRef执行

watch

在这里插入图片描述

  1. 监听 reactive 内部数据时,强制开启了深度监听,且配置无效;监听对象的时候 newValue 和 oldValue 是全等的。
  2. reactive 的【内部对象】也是一个 reactive 类型的数据。
  3. 对 reactive 自身的修改则不会触发监听(比如说对于侦听对象本身赋值新对象不会触发监听, 因为新对象不具备 reactive 的环境, 如果是对于对象中的数据进行修改则能监听到)
    监听多个变量时, 可以写在一个数组中
  4. 设置immediate : true 能够在第一次调用数据时就执行
ref监听
  1. 对ref 数据的第一层进行修改 (相当于修改的是 obj.value)
    在这里插入图片描述
  2. 对ref 数据开启深度侦听 deep: true
watch(
  obj,
  (newValue, oldValue) => {
    console.log(newValue, oldValue)
    console.log(newValue === oldValue)
  },
  {
    deep: true
  }
)
  1. 还可以通过监听 ref.value 来实现同样的效果 (ref不是 reactive 类型, ref.value 是 reactive 类型, reactive 或 ref对象中的第一层复杂数据类型都是reactive 数据, 简单数据类型不是reactive 数据)
<template>
  <p>{{ obj.hobby.eat }}</p>
  <button @click="obj.hobby.eat = '面条'">修改 obj</button>
</template>

<script>
  import { watch, ref } from 'vue'
  export default {
    name: 'App',
    setup() {
      const obj = ref({
        hobby: {
          eat: '西瓜'
        }
      })
      watch(obj.value, (newValue, oldValue) => {
        console.log(newValue, oldValue)
        console.log(newValue === oldValue)
      })

      return { obj }
    }
  }
</script>
组件间的数据传递

在这里插入图片描述

注意
  1. 两种操作会失去响应式

    对数据的直接解构赋值

//下面的操作也会是state是取响应式
return {
	name:state.name,
	age:state.age,
	updateAge,
}
  1. ref 和 toRef 区别 ( ref 是用来将数据变为响应式的数据, 而 toref 是用来将数据和数据源形成响应式连接)
    在这里插入图片描述
  2. watch 可以监听 函数 / ref / 数组 / 对象 / reactive , 但不能监听到普通值, 可以写在箭头函数中返回的方式监听普通值
    在这里插入图片描述
  3. vue3 中同一个生命周期钩子能够重复调用, 不会覆盖
  4. vue3 中用setup() 替代了之前的created 和 beforeCreate
  5. reactive 或 ref对象中的第一层复杂数据类型都是reactive 数据, 简单数据类型不是reactive 数据
补充
  1. 通过isRef 和 isReactive 方法判断变量
  2. setup 中参数 attrs 能拿到 非props 数据
  3. setup 中参数 slots 能拿到 插槽 信息
provide/inject (跨层级组件数据传递)

当涉及到多层组件数据传递时, 可以通过 provide(‘变量或方法名’, 变量或方法) 将数据传递出去, 能够在任意层级通过 inject(‘变量或方法名’) 调用

在这里插入图片描述

  1. 这里的 provide 中的数据可以写成对象的形式, 就不用写多个 provide 进行抛出了
vue3 中的 v-model
  1. vue2 与 vue3 中 v-model 比较

这里的 $event 拿到的是子组件中 $emit(‘父组件中触发事件名’, 传递参数) 传递过来的第二个参数, 这两种写法都等价于 v-model=“msg” (给标签一个属性和一个事件)

<Son :value="msg" @input="msg=$event" />
<Son :modelValue="msg" @update:modelValue="msg=$event" />
  1. vue3 的 v-model 拆解

这里的v-model:text 相当于修改传到子组件值的名字, 默认为 modelValue ,有冒号就修改为 text, 在子传父的时候也就不再写成 update:modelValue , 而是 update:text

  • 父组件
<template>
  <!-- 组件绑定 v-model -->
  <hy-input v-model="message" v-model:text="inputText"></hy-input>
  <h2>{{message}}</h2>
  <h2>{{inputText}}</h2>
</template>

<script>
import {  ref } from '@vue/reactivity'
import HyInput from "../components/HyInput.vue"
export default {
  components: {HyInput },
    setup(){
        let message = ref("嘿嘿嘿ヽ(*^ー^)(^ー^*)ノ")
        let inputText = ref("嘻嘻嘻嘻")
  
        return{
            message,
            inputText
        }
    }
}
</script>
  • 子组件
<template>
   <button @click="handelClick">O(∩_∩)O哈哈~</button>
   <br>
   <input type="text" v-model="customText">
   <br>
</template>

<script>
import {computed} from "vue"
    export default {
        props:{
            modelValue:String,
            text:String
        },
        emits:['update:modelValue',"update:text"],
        setup(props,context){
            function handelClick() {
                context.emit("update:modelValue","O(∩_∩)O哈哈~")
            }
            let customText = computed({
                set(value){
                    context.emit("update:text",value)
                },
                get(){
                    return props.text
                }
            })

            return{
                handelClick,
                customText,
            }
        }
    }
</script>

  1. vue3 中的 v-model 可以在一个标签中多次使用(将 vue2 中的 v-model 和 .sync 特性结合起来了)
  2. 几种写法等价
<Son :modelValue="age" @update:modelValie="age = $event"/>
<Son v-model:modelValue = "age" />
<Son v-model="age" />
子传父 过程中的自定义事件

如果App 中的自定义事件中绑定的事件没有括号, 那么能够拿到右边组件中传递过来的所有参数; 如果有括号, 那么括号中的接收参数就只能拿到右边组件中的第二个参数 (也就是说图中的情况只能拿到’world’字符串, 而不能拿到 $event , 如果要拿到右边组件的所有参数, 可以对右边参数的第二个参数设置为对象或数组)
在这里插入图片描述

利用 ref 绑定并调用组件中方法

在这里插入图片描述

  1. 创建 ref 实例
  2. 导出实例
  3. 在组件上绑定 ref 实例
  4. 点击触发子组件 组件上绑定的ref值.value 拿到子组件的数据和方法
teleport

能够将 teleport 标签中的 dom 内容移动到 to 设置的标签页中

<teleport to="body">
  <dialog v-if="bBar" />
</teleport>
ref 和 toref
import { createApp, ref } from 'vue'

export default {
  name: 'demo',
  setup () {
  	let obj = {x: 1, y: 2} // 原数据
  	let x = ref(obj.x)
  	let y = toRef(obj, 'y')
  	
  	const change = () => {
  		x.value = 2
  		y.value = 1
  		console.log(obj) 
                // 输出 obj{x: 1, y: 1},x, y分别在UI界面上显示2 ,2
		}
		
		return {
			x,
			y
		}
	}
}
  1. 注意这里的 ref 操作只是拷贝了 obj 中属性的值并赋值给 x, 而 toref 将 obj 的属性变为, 它会保持对其源 property 的响应式连接
  2. reactive 用于为对象添加响应式状态。
  3. ref 用于为数据添加响应式状态。
  4. toRef 用于为源响应式对象上的属性新建一个ref,从而保持对其源对象属性的响应式连接。
  5. toRefs 用于将响应式对象转换为结果对象,其中结果对象的每个属性都是指向原始对象相应属性的ref。

vue3 生命周期中钩子函数

vue2 与 vue3 钩子函数对应

注意 beforeCreate 和 created 在 vue3 中不再使用, 中间的四个函数没怎么变, 然后销毁函数变为 unmounted, 捕捉错误的函数都没怎么用过, 所有的钩子函数都写在 setup 函数中

  • beforeCreate -> use setup()
  • created -> use setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured
注意
  1. 在 setup() 内部,this 不是该活跃实例的引用,因为 setup() 是在解析其它组件选项之前被调用的,所以 setup() 内部的 this 的行为与其它选项中的 this 完全不同。这使得 setup() 在和其它选项式 API 一起使用时可能会导致混淆。
解决路由缓存问题
  1. 给router-view 添加key属性
<router-view :key="$route.fullPath"/>
  1. 使用watch监听id变化重新拉取接口
watch(
  ()=>{ return route.params.id },
  ()=>{ loadCategoryList() } // 在id变化的时候重新使用最新的路由id拉取最新数据
)
  1. 使用onBeforeRouteUpdate 钩子函数
async function loadCategoryList (id) {
  const res = await findTopCategory(id)
  categoryData.value = res.result
  breadName.value = res.result.name
}
onMounted(() => {
  loadCategoryList(route.params.id)
})
// 在路由跳转之后更新之前自动执行
// beforeEach((to,from,next)=>{})
onBeforeRouteUpdate((to) => {
  // to指代的是目标路由对象 to拿到最新的路由参数id
  // 使用最新id获取数据
  loadCategoryList(to.params.id)
})

Vue3中this的替代方案

export default defineComponent ({
  setup(){
    const { proxy, ctx } = getCurrentInstance()
    console.log('getCurrentInstance()中的proxy:', proxy)
    return {}
  }
})

  • 打印结果
    在这里插入图片描述
vue3 中全局挂载 axios 方法
  1. 下 axios 包
  2. 在main.js中配置全局引入
const app = createApp(App);

import axios from "axios";
app.config.globalProperties.$axios = axios;

app.use(store).use(router).mount("#app");

  1. 在组建中使用axios,这里是要是用setup()
<template>
  <div class="home">
    {{ data.name }}
  </div>
</template>

<script>
// @ is an alias to /src
import { reactive, getCurrentInstance, onMounted } from "vue";

export default {
  setup() {
    let { proxy } = getCurrentInstance();

    let data = reactive({
      name: "hello"
    });

    onMounted(() => {
      console.log(proxy.$axios);
    });

    return { data, proxy };
  }
};
</script>
vue3 中通过 ref 获取元素

vue3 需要借助生命周期方法,原因很简单,在setup执行时, template中的元素还没挂载到页面上,所以必须在onMounted之后才能获取到元素。

<template>
  <div ref='box'>I am DIV</div>
</template>
<script>
import {ref,onMounted}
export default{
  setup(){
    let box = ref(null);
    onMounted(()=>{
      console.log(box.value)
    });
    return {box}
  }
}
</script>
补充

!!数据 能将数据转化成布尔值

注意
  1. vue3 中 computed 计算属性的写法, 如果不用双向绑定时, 就直接在 computed 中包裹一个函数就行, 如果是双向绑定(一般用于 input 标签中), 就需要在 computed 中包裹一个对象, 对象中写 get 和 set 函数
const isShowClear = computed(() => {
  return state.list.some((item) => item.flag === true)
}),
const isAll = computed({
  get(){
    return state.list.every(item=>item.flag)
  },
  set(val){
    state.list.forEach(item=>item.flag = val)
  }
})

第一处能够在 list 数组本身发生变化的时候监听到, 但是如果是数组内部的数据发生变化时监听不到; 所以需要在第二处添加深度监听 (这样就不仅能监听数组发生, 还能监听到数组内部的变化)

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值