Vue3开发文档总结

Vue3中获取this的方式

Vue2中每个组件使用this指向当前组件实例, this上包含全局挂在的内容:路由、状态管理等
Vue3中每个this,想要获取组件实例有两种

  1. 获取当前组件实例
  2. 获取全局实例
<script setup>
import { getCurrentInstance } from 'vue'
// proxy:当前组件实例,=》 组件级别的this,没有全局的、路由、状态管理等
const { proxy, appContext } = getCurrentInstance();
// global全局实例
const global = appContext.config.globalProperties;
</script>

全局注册(属性/方法)

Vue2中全局挂在东西是这样滴:Vue.prototype.xxx = xxx 之后通过this.xxx获得

在Vue3中需要在全局实例上挂载(在main.js中全局注册)

// main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App);
// 添加全局属性
app.config.globalProperties.name = 'Wangzz'
// XXX.vue 其他组件中引用
import { getCurrentInstance } = from 'vue'
const { appContext } = getCurrentInstance()
const global = appContext.config.globalProperties;
console.log(global.name) // Wangzz

template

Vue2中只能存在一个根节点,Vue3中支持多个根节点
本质上Vue3组件还是一个根节点,因为DOM树是树状结构,
Vue3在编译阶段新增判断,如果当前组件不只是一个根元素,则添加一个fragment组件把这个多根组件
给包裹起来,相当于这个组件还是只有一个根节点

<template>
<div>01</div>
<div>02</div>
</template>
// -------------》 编译后
<template>
<fragment>
<div>01</div>
<div>02</div>
</fragment>
</template>

🤡Vue3中如何获取DOM???

<template>
<el-form ref='formRef'></el-form>
<child-component/>
</template>
<script setup lang='ts'>
import ChildComponent from './child.vue'
import { getCurrentInstance } from './child.vue'
import { ElForm } from 'element-plus'
// 方法一,变量名和DOM上ref属性同名之后会形成绑定
const formRef = ref(null);
console.log(formRef.value) // 获取到DOM了
// 方法二
const { proxy } = getCurrentInstance();
proxy.$refs.formRef.validate((valid) => { ... })
// 方法三, eg: 在ts中,可以直接获取组件类型
// 直接获取子组件
const formRef = ref<InstanceType<typeof ChildComponent>>();
</script>

初始化

V2中进入页面就请求接口,或其他初始化操作,一般放置在[created]或[mounted]
而Vue3中beforeCreated或created这两个钩子不需要,[setup]会在beforeCreated和created两个钩子之前执行
因此beforeCreated/created/beforeMount/mounted这几个钩子的内容可以直接放置在setup中
或者放置在🤩onMounted或onBeforeMount中🤩

<script setup>
import { onMounted } from 'vue'
// 请求接口函数
const getData = () => {
let res = xxxApi();
}
onMounted(() => {
getData();
});
</script>

如何解除绑定???

V2中一般清除定时器\监听之类的操作存在两种方法

  • 用$once搭配hook: beforeDestroy(V3不支持)
  • 用beforeDestroy/ deactivated这两个钩子,
import { onBreforeUnmount, onDeactivated } from 'vue'
// 组件卸载之前,对应V2的beforeDestroy
onBeforeUnmount(() => {
clearTimeout(timer);
window.removeAddEventListener('.........');
});
// 退出缓存组件,对应V2的deactivated
onDeactivated(() => {
clearTimeout(timer);
window.removeAddEventListener('......');
});

🤡 ref VS reactive

ref和reactive都是用来创建响应式对象

  • ref 用于创建基础类型
  • reactive 用于创建响应式

实际上ref也常用于定义数组,也有人在一个组件中定义一个reactive,之后组件的所有数据都放在这个reactive对象中

Warning 🪔
  • ref如果包裹引用数据类型,本质上还是通过reactive实现的
  • ref返回的数据在template中是直接使用的, 在script中需要通过.value访问
<template>
<div> {{count}}</div>
</template>
<script setup>
import {ref, reactive} from 'vue'
const count = ref(1)
// (❁´◡`❁) somebody usage
const arr = ref([]);
console.log(arr.value) // []
// (●'◡'●) somebody usage
const data = reactive({
name: 'wangzz',
hobbies: ['Reading', 'Running'],
info: ' a simple guy'
})
console.log(data.name);
</script>

// ref要返回一个包装对象, V2中data都是返回一个对象
// 对象引用类型,需要使用代理或劫持
// 如果只是返回基础类型的话,存储在栈中,执行栈执行完就会回收
// 无法进行代理或劫持,即无法追踪后续的变化,所以不得不返回一个对象,这样才能有响应式

🥰 toRef 和 toRefs

toRef和toRefs的共同点是用来创建响应式的引用的,取出响应式对象里的属性或解构响应对象
解构出来的属性依然是响应式属性,如果不适用这两个直接结构的话会丢失响应式效果.

主要是方便我们使用直接变量 xxx 而不需要 data.xxx 而且修改xxx的也是直接修改对象属性的

案例使用

👀监听watch的使用

watch用来监听一个已经存在属性,发生变化的时候做出某些操作

V2中的使用

watch: {
userId: 'getData',
userName(newVal, oldVal) {
this.getData()
},
userInfo: {
handler(newVal, newVal) {this.getData()},
immediate: true,
deep: true
}
}
💸V3中的监听写法

V3中watch是一个函数,可以接受三个参数,分别是1.监听的属性 2.接收的新值和老值的回调函数, 3. 配置项

<script setup>
import { watch, ref, reactive } from 'vue'
const name = ref("wangzz");
const data = reactive({
name: "wangzz",
age: 24,
children: []
});
// 监听ref属性
watch(name, (newVal, oldVal) => { ... })
// 监听其他属性,路由或状态管理
watch(
() => data.age,
(newVal, oldVal) => {...}
)
// 监听多个属性,数组放多个值,返回的新值和老值都是数组形式
watch([data.age, data.money], ([newAge, newMoney], [oldAge, oldMoney]) => {
...
});
// 第三个参数是一个对象,该对象是一个配置对象可配置5个属性
watch(data.children, (newList, oldList) => {...}, {
immediate: true,
deep: true,
// 回调函数的执行时机,默认在组件更新之前调用,更新后调用改成post
flush: 'pre', // 默认值是pre, 可以改成post或sync
// 下面两个用来调式
onTrack(e) { debugger },
onTrigger(e) { debugger },
});
</script>

副作用 watch和watchEffect是一样的

在watch回调函数中接受第三个参数onInvalidate, 为清楚副作用的函数
首次触发监听的回调函数(handler)不会执行onInvalidate,之后每次触发默认会限制性onInvalidate
默认的执行机制在更新前调用

// 回调函数会接受一个参数,为清除副作用的函数
// key触发更新的时候会先打印222再打印wangzz~
// 如果需要在更新后调用 => flsuh: post
watch(key, (newKey, oldKey, onInvalidate) => {
console.log("wangzz ~~");
// 获取DOM默认获取到的是更新前的DOM,如果是flush:post,可以获取更新后的DOM
console.log("DOM节点: ", dom.innerHTML);
onInvalidate(() => {
console.log(2222);
});
});

onInvalidate使用场景: eg: 监听的回调函数(handler)中存在一些异常操作,
当再次触发watch的时候可以用它来对前面未完成的异步任务执行取消上一次触发的watch时未完成的请求

watchEffect

V3中除了watch还增加了一个watchEffect.区别是:

  • watch是对传入一个或多个值进行监听,触发的时候会返回新值和旧值,且默认第一次不会执行;

  • watchEffect是传入一个立即执行函数,默认第一次就会执行,且不需要传入监听内容,会自动手机函数内的数据源作为依赖

watch中会作为回调的第三个参数传入, watchEffect中回调函数的第一个参数

// 监听方法赋值
cosnt unwatch = watch('kehy', callback)
const unwatchEffect = watchEffect(() => {})
// 需要停止监听的时候,手动调用停止监听
unwatch()
unwatchEffect();

🤩🤩 watchEffect的使用

<script setup>
import { watchEffect } from 'vue'
// 正常使用
watchEffect(() => {
// 会自动收集这个回调函数使用到的属性作为依赖进行监听
// 监听的是userInfo.name属性就不会监听userInfo
console.log(userInfo.name);
});
// 存在两个参数,参数一是触发监听回调函数, 参数二是可选配置项
watchEffect(() => { ... } , {
// 可配置项,和watch一样
flush: 'pre',
onTrack(e) {debugger}
onTrigger(e) {debugger}
});
// 回调函数接收一个参数,为清除副作用的函数,和watch同理
watchEffect(onInvalidate => {
console.log("Wangzz ~~~");
onInvalidate(() => {
console.log(23123124);
});
});
</script>

// 组件数据更新之前执行,还是组件数据更新之后执行

// 组件数据更新之后执行
watchPostEffect(() => {
});
// 组件数据更新之前执行
watchPreEffect(() => {
});

computed🦕🦕🦕 - 计算属性

V2中computed最常见的使用场景: mapGetters/ mapState获取状态管理的属性, 获取url上的属性
条件判断\类型转换之类的支持函数和对象两种写法

V3中computed不再是一个对象而是一个函数, 函数的第一个参数是侦听器源,用于返回计算的新值,也支持对象写法第二个参数用于调试

<script setup>
import { computed } from 'vue'
const props = defineProps(['visible', 'type'];
const emit = defineEmits(['myClick']);
// 函数写法,计算类型
const isFirst = computed(() => props.type === 1)
// 对象写法
const status = computed({
get() { return props.visible }, // 相当于V2中this.visible
set(val) { emit('myClick', val}, // 相当于V2中this.$emit('input', val)
});
// computed 第二个参数也是一个对象,调试使用
const hehe = computed(参数一上面两种都可, {
onTrack (e) { debugger }
onTrigger (e) { debugger }
})
</script>

🦉🦉🦉 nextTick

nextTick的使用方法,除了不能用this其他的和V2使用方式一样

<script setup>
import { nextTick } from 'vue'
// 方式一
const handleClick = async() => {
await nextTick();
console.log('wangzz ~~');
}
// 方式二
nextTick(() => {
console.log("wangzz ~~");
});
// 方式三
nextTick().then(() => {
console.log("测试数据 ~~~~");
});
</script>

mixins 和 hooks

Vue2中逻辑的抽离服用一般采用mixins 缺点:

  • 没有独立命令空间, mixins会和组件内部产生命名冲突
  • 不去翻代码不知道引入的mixins中有什么
  • 引入多个mixins时不知道自己使用来自哪一个mixins的

Vue3逻辑抽离服用hooks语法,本质是一个函数可以传递参数和获取返回值

// xxx.js
export const getData = () => {}
export default function unInstance() {
return { ... }
}
// xxx.vue
import unInstance, { getData } from 'xx.js'
const { ... } = unInstance();
onMounted(() => {
getData()
});

★🦉🦉🦉🦉🦉 hooks如何写出更优雅的代码还需要多写多实践

组件通信

Vue3中组件通信的方式有如下几种

  • props + defineProps
  • defineEmits
  • defineExpose + ref
  • useAttrs
  • v-modal(支持多个)
  • provide/ inject
  • mitt
  • Vuex/ Pinia

多个v-model

V2中每个组件仅能写一个v-model, 子组件没有写model的话,默认在props接受value即可
修改就是使用this.$emit('input')事件

V3中每个组件支持写多个v-model, 没有.sync和model重命名的操作

// 父组件
<template>
<child v-model:name='name' v-model:age='age'/>
</template>
<script setup>
import {ref} from 'vue'
const name = ref("wangzz");
const age = ref(24);
</script>
// 子组件
<script setup>
const emit = defineEmits(['update:name', 'update:age']);
const handleClick = () => {
console.log("点击了");
emit('update:name', '新名字')
}
</script>

状态管理 (Vue3推荐Pinia)

Vuex4用法案例
// main.js中
import { createApp } from 'vue'
import App from './App.vue'
import Store from './store'
const app = createApp(App)
app.use(Store)
// 模块: store/user/index.js
export default {
state: {},
getters: {},
actions: {},
mutations: {},
}
// 模块: store/index.js
import { createStore } from 'vuex'
import user from './user'
const store = createStore({
state: {},
getters: {},
actions: {},
mutations: {},
modules: {
user
}
});
export default store;
// 组件中使用store, 需要使用到状态管理的.vue文件
<script setup>
import { useStore } from 'vuex'
const store = useStore();
</script>

路由的使用

Vue-Router4的使用,主要是route和router的使用
// main.js中
import { createApp } from 'vue'
import App from './App.vue'
import Router from './App.vue'
const app = createApp(App)
app.use(Router)
// router/index.js
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
// routes数组中和V2一样
const routes = [
{ path: '/', redirect: { name: 'login'}}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
});
export default router
// 需要用到路由的.vue文件中
<script setup>
import { useRoute, useRouter } from 'vue-router'
// route对应V2中的this.$route
const route = useRoute();
// router对应V2中this.$router
const router = useRouter();
</script>

🤡 CSS样式穿透

V2在scoped中修改子组件或组件库中的组件样式
可以用样式穿透,不管是Less还是Sass都是用/deep/ .className {}
V3中不支持/deep/写法 ===========> 而是 :deep(.className) {}

<style lang='scss' scoped>
// V2写法
/deep/ .el-form {
...
}
// V3写法
:deep(.el-form) {
// ...
}
</style>

CSS绑定JS变量

<template>
<div class='name'>Wangzz ~~ </div>
</template>
<script setup>
import { ref } from 'vue'
const str = ref("#f00");
</script>
<style scoped lang='scss'>
.name {
background-color: v-bind(str);
}
</style>
posted @   Felix_Openmind  阅读(251)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
*{cursor: url(https://files-cdn.cnblogs.com/files/morango/fish-cursor.ico),auto;}
点击右上角即可分享
微信分享提示