超详细、超基础 Vue3 开发语法使用总结

前言最近开源了一套后台管理模板-Admin , 是基于 Vue3.2、、Vite4、Pinia、-Plus、(微前端) 技术栈,借此归纳一下Vue3.2的新语法 。一、全局注册(属性/方法) 1、main.ts注册
import { createApp } from "vue";import App from "./App.vue";// 所有业务api接口import api from "@/api";const instance = createApp(App);// 注册全局api方法instance.config.globalProperties.$api = api;
2、.vue文件使用
="ts">import { getCurrentInstance } from 'vue'const {appContext } = getCurrentInstance()const global = appContext.config.globalProperties// 获取所有业务api接口console.log(global.$api)
输出结果如下:
二、获取 this
="ts">import { getCurrentInstance } from 'vue'// proxy 就是当前组件实例,相当于Vue2单文件的this——没有全局的、路由、状态管理之类的const { proxy, appContext } = getCurrentInstance()// 这个 global 就是全局实例(可以获取挂载全局的方法)const global = appContext.config.globalProperties
三、可存在多个根节点
其实本质上 Vue3 每个组件还是一个根节点,因为 DOM 树只能是树状结构的,只是 Vue3 在编译阶段新增了判断,如果当前组件不只一个根元素,就添加一个组件把这个多根组件的给包起来,相当于这个组件还是只有一个根节点,并且 组件是一个不会被渲染出来的内置组件

1
2
3

四、获取 DOM
setup lang="ts">import { ref} from "vue";// 注意:这个变量名和 DOM 上的 ref 属性必须同名,会自动形成绑定const buttonRef= ref(null)// 获取到 DOMconsole.log(buttonRef.value)
五、解除绑定(定时器、监听之类的操作)
="ts">import { onBeforeUnmount, onDeactivated } from 'vue'// 组件卸载前onBeforeUnmount(() => {// 清除定时器clearTimeout(timer)// 清除监听事件window.removeAddEventListener('所监听的事件')})// 退出缓存组件onDeactivated(() => {// 清除定时器clearTimeout(timer)// 清除监听事件window.removeAddEventListener('所监听的事件')})
六、ref 和 使用
超详细、超基础  Vue3 开发语法使用总结

文章插图
通常情况:ref 用于创建一个响应式的基本数据类型(如字符串、数字或布尔值) 。它返回一个包含响应式值的对象 , 在 可以通过 .value 属性访问该值, 中直接使用 。
通常情况: 用于创建一个响应式的对象 。它返回一个新的响应式对象,该对象与原始对象具有相同的属性和值 。
="ts">import { ref, reactive } from "vue"const count = ref(1)// 输出结果:1注意:ref 返回的属性在 template 中直接使用,不需要再.valueconsole.log(count.value)const state= reactive({name: "wocwin",address: "广州市",...})console.log(state.name) // wocwin
七、toRef 和 使用(解决直接解构会丢失响应式)
解决直接解构会丢失响应式:这两共同点就是用来创建响应式的引用的,主要用来取出响应式对象里的属性,或者解构响应式对象 , 解构出来的属性值依然是响应式属性 。
="ts">import { reactive, toRef, toRefs } from "vue"const state= reactive({name: "wocwin",address: "广州市",})// 这样能拿到 name / address,但是会变成普通变量 , 没有响应式效果const { name, address} = state// 取出来一个响应式属性const name = toRef(state, 'name')// 这样解构出来的所有属性都是有响应式的const { name, address} = toRefs(state)
八、watch和 使用
watch 是一个函数,能接收三个参数,参数一是监听的属性 , 参数二是接收新值和老值的回调函数,参数三是配置项
watch 是对传入的一个或多个值进行监听,触发时会返回新值和老值 , 且默认第一次不会执行
是传入一个立即执行函数 , 所以默认第一次就会执行 , 且不需要传入监听内容,会自动收集函数内的数据源作为依赖,当依赖发生变化时会重新执行函数 , 不会返回新值和老值 。
="ts">import { watch, ref, reactive,watchEffect } from "vue"const name = ref("wocwin")const state = reactive({address: "广州市",age: 22,children: []})// 监听 ref 属性watch(name, (newName, oldName) => { ... })// 监听单个属性watch(() => state.address, (newAddress, oldAddress) => { ... })// 监听多个属性,数组放多个值,返回的新值和老值也是数组形式watch([data.age, data.address], ([newAge, newAddress], [oldAge, oldAddress]) => { ...})// 第三个参数是一个对象,为可配置项watch(data.children, (newList, oldList) => { ... }, {// 这两个和 Vue2 一样immediate: true,deep: true,})// 在 watch 回调函数中能接收第三个参数 onInvalidate,为清除副作用的函数 , 首次触发监听的回调函数(handler)不会执行 onInvalidate,之后每次触发默认会先执行 onInvalidatewatch(name, (newName, oldName,onInvalidate) => { console.log("wocwin")onInvalidate(() => {console.log(2222)})})// onInvalidate 的使用场景就是:比如监听的回调函数(handler)里有一些异步操作,当再次触发 watch 的时候可以用它来对前面未完成的异步任务执行取消/重置/初始化等操作 。/***watchEffect*/watchEffect(() => {// 会自动收集这个函数使用到的属性作为依赖,进行监听// 监听的是 state.name 属性,不会监听 stateconsole.log(state.name)})
九、(计算属性——是一个函数)
="ts">import { computed } from "vue"const props = defineProps({modelValue: {type: [String, Number, Array]},})const emits = defineEmits(['update:modelValue'])// 函数写法const isFirst = computed(() => {...})// 对象写法// vue3 v-model简写let childSelectedValue: any = computed({get() {return props.modelValue},set(val) {emits('update:modelValue', val)}})
十、
="ts">import { nextTick} from 'vue'// 方式 一const handleClick = async () => {await nextTick()console.log("wocwin")}// 方式二nextTick(() => {console.log("wocwin")})// 方式三nextTick().then(() => {console.log("wocwin")})
十一、 和 hooks
超详细、超基础  Vue3 开发语法使用总结

文章插图
Vue2 中逻辑的抽离复用一般用 :但是其没有独立命名空间,会和组件内部产生命名冲突
Vue3 中逻辑抽离复用的 hooks 语法,其实就是一个函数 , 可以传参,拿返回值来用 。
1、封装hooks(具体代码查看-Admin)
import { storeToRefs } from "pinia";import { Theme } from "./interface";import { ElMessage } from "element-plus";import { DEFAULT_PRIMARY } from "@/config";import { useGlobalStore } from "@/store/modules/global";import { getLightColor, getDarkColor } from "@/utils/color";import { asideTheme, AsideThemeType } from "@/styles/theme/aside";/*** @description 全局主题 hooks* */export const useTheme = () => {const globalStore = useGlobalStore();const { primary, isDark, isGrey, isWeak, asideInverted, layout } = storeToRefs(globalStore);// 切换暗黑模式 ==> 并带修改主题颜色、侧边栏颜色const switchDark = () => {const body = document.documentElement as HTMLElement;if (isDark.value) body.setAttribute("class", "dark");else body.setAttribute("class", "");changePrimary(primary.value);setAsideTheme();};// 修改主题颜色const changePrimary = (val: string | null) => {if (!val) {val = DEFAULT_PRIMARY;ElMessage({ type: "success", message: `主题颜色已重置为 ${DEFAULT_PRIMARY}` });}// 计算主题颜色变化document.documentElement.style.setProperty("--el-color-primary", val);document.documentElement.style.setProperty("--el-color-primary-dark-2",isDark.value ? `${getLightColor(val, 0.2)}` : `${getDarkColor(val, 0.3)}`);for (let i = 1; i <= 9; i++) {const primaryColor = isDark.value ? `${getDarkColor(val, i / 10)}` : `${getLightColor(val, i / 10)}`;document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, primaryColor);}globalStore.setGlobalState("primary", val);};// 灰色和弱色切换const changeGreyOrWeak = (type: Theme.GreyOrWeakType, value: boolean) => {const body = document.body as HTMLElement;if (!value) return body.removeAttribute("style");const styles: Record = {grey: "filter: grayscale(1)",weak: "filter: invert(80%)"};body.setAttribute("style", styles[type]);const propName = type === "grey" ? "isWeak" : "isGrey";globalStore.setGlobalState(propName, false);};// 设置侧边栏样式 ==> light、inverted、darkconst setAsideTheme = () => {// 默认所有侧边栏为 light 模式let type: AsideThemeType = "light";// transverse 布局下菜单栏为 inverted 模式if (layout.value =http://www.kingceram.com/post/="transverse") type = "inverted";// 侧边栏反转色目前只支持在 vertical 布局模式下生效if (layout.value =http://www.kingceram.com/post/="vertical" && asideInverted.value) type = "inverted";// 侧边栏 dark 模式if (isDark.value) type = "dark";const theme = asideTheme[type!];for (const [key, value] of Object.entries(theme)) {document.documentElement.style.setProperty(key, value);}};// init themeconst initTheme = () => {switchDark();if (isGrey.value) changeGreyOrWeak("grey", true);if (isWeak.value) changeGreyOrWeak("weak", true);};return {initTheme,switchDark,changePrimary,changeGreyOrWeak,setAsideTheme};};
2、具体页面使用