您现在的位置是:首页 >技术交流 >vue3 项目实践总结网站首页技术交流
vue3 项目实践总结
一、挂载全局变量
1.1 main.js
中挂载
// 引入全局变量
import api from '@/api';
const app = createApp(App);
// 挂载全局变量
app.config.globalProperties.$API = api;
app.use(store)
.use(router)
.use(ElementPlus)
.use(Vant)
.mount('#app');
1.2 组件中获取
-
方法一 推荐使用proxy
1. 使用 ctx ,经过测试后,打包到dist以后,ctx下面的值是拿不到的,即只能在开发环境使用。所以。推荐使用proxy2. proxy, ctx可直接访问全局变量,但无法像
globalProperties
这样查看有哪些数据,只是一个Proxy对象。3. 如果想要通过 proxy, ctx 访问当前组件的变量,需要在onBeforeMount 和 mounted生命周期中,即在组件挂载之后才可访问,否则访问不了;
4. 注意:在vue3中,created相关的生命周期已经被废弃,由setup()代替
import { getCurrentInstance, onMounted } from 'vue'; // 需要调用vue3内置的方法
setup(props, context) {
// 直接解构出 proxy 和 ctx
const { proxy, ctx } = getCurrentInstance();
// 使用方法1 : 如果想要通过 proxy, ctx 访问当前组件的变量,需要在onBeforeMount 和 mounted生命周期中
onMounted(() => {
console.log('----ctx', ctx['当前组件的data变量']);
console.log('----proxy', proxy['当前组件的data变量']);
});
// 使用方法2 :直接调用全局变量,但此时无法访问当前组件的变量
proxy.$API.xxx // 调用具体的方法
}
- 方法二 麻烦但详细
import { getCurrentInstance } from 'vue'; // 需要调用vue3内置的方法
setup(props, context) {
// 这样获取可以获取到所有的全局变量,包含UI组件库获取其他方法注入的。并且可以想象的查看有哪些数据
const { appContext: { config: { globalProperties } } } = getCurrentInstance();
globalProperties.$API.xxx // 调用具体的方法
}
1.3 全局挂载 store 和 router
在第九章中阐述了怎么在页面中去使用store
和router
,但在实际项目开发中,store
和 router
的使用频率是很高的,每个组件(页面)都去这么引入/调用,会显得很麻烦。
1. 挂载到window上
但是你要忍受它的全局污染
2. 挂载到全局上
在我的实际开发中,总会有几个东西会挂载到全局变量上:比如 ajax
或者API
、moment
等,再将 store
和 router
挂载上去,使用成本对于我来说并没有增加多少。
- main.js
const app = createApp(App);
// 将store、router挂载到全局变量上
import { useStore } from "vuex";
import { useRoute } from "vue-router";
app.config.globalProperties.$store = useStore();
app.config.globalProperties.$router = useRoute();
app.use(router).use(store).mount('#app')
- 组件(页面)中
<template>
<span> {{ count }} </span>
<!--
下面这种vue2的旧写法,依旧可用,但是可能编辑器会报警告;
并且$store并不需要在组件中return处理,它是挂载到每个实例上的
-->
<span>{{ $store.state.count }}</span>
</template>
<script>
import { getCurrentInstance, computed, ref } from 'vue';
export default {
name: 'Home',
setup() {
const { proxy } = getCurrentInstance();
// 使用store
const count = computed(() => proxy.$store.state.count);
const handleSkip = () => {
// 使用router
proxy.$router.push('/about');
}
return {
count: ref(count),
handleSkip
}
}
}
</script>
3. 使用Provide & Inject => 不推荐,使用成本较高
注意:使用 Provide & Inject 最好配置 readonly 或者 shallowRef ,限制 孙子组件修改一级组件的数据。避免造成数据混乱。
- app.vue
<script setup>
import { useStore } from "vuex";
import { useRoute } from "vue-router";
import { provide } from "vue";
// 组合式的API provide 没有提供批量方法,只能每个变量写一句
provide("store", useStore());
provide("router", useRoute());
</script>
- 组件(页面)中
<script setup>
import { inject } from "vue";
// 使用 inject 获取到 store 和 router
const store = inject("store");
const router = inject("router");
console.log('=====>>>>', store.state);
console.log('=====>>>>', router);
</script>
注意 : inject()只能放在setup()生命周期里运行,即不能放在别的周期里运行,也不能放在事件周期里运行。
个人理解:只能在同步代码中使用,不能再异步代码中使用,所以,一般先在setup()
周期中取值。
放在 setTimeout 或者 Promise.then() 是不可以的,但是下面这种用法是可以的:
function xx() {
console.log(inject("abc"))
}
xx()
二、封装 getCurrentInstance
在上一章的 挂载全局变量
中有提到:想要获取全局变量,一般都是从getCurrentInstance()
解构出 proxy
或globalProperties
,但是:
- 解构出的 proxy ,包含所有的全局变量,但是 是Proxy对象,不能清楚的在控制台查看
- globalProperties 里面全部的全局变量,并且不是Proxy对象,可以在控制台清楚查看
而每个组件里面都去解构一次 globalProperties
是很繁琐的,所以,我们可以封装一下,实现步骤如下:
- 新建文件 hooks / useCurrentInstance.ts
import { ComponentInternalInstance, getCurrentInstance } from 'vue'
export default function useCurrentInstance() {
// 如果解构出 proxy ,里面也包含所有的全局变量,但是 是Proxy对象,不能清楚的在控制台查看
const { appContext } = getCurrentInstance() as ComponentInternalInstance;
// 这里有全部的全局变量,并且不是Proxy对象,可以在控制台清楚查看
const globalProperties = appContext.config.globalProperties;
return {
globalProperties
}
}
- 组件中使用
// 先引入
import useCurrentInstance from '@/hooks/useCurrentInstance';
// 再使用
export default {
setup() {
const { globalProperties } = useCurrentInstance();
// 这里面的全局变量可以清楚的在控制台去查看
console.log('-------globalProperties', globalProperties)
}
}
注意 :不能再封装文件里面直接调用函数并直接导出全局变量,会报错!!
三、vue3中使用ref
// ------------ 官网实例 ------------
<template>
<div ref="root">This is a root element</div>
</template>
<script>
// 引入ref API
import { ref, onMounted } from 'vue'
export default {
setup() {
const root = ref(null)
onMounted(() => {
// DOM 元素将在初始渲染后分配给 ref
console.log(root.value) // <div>This is a root element</div>
})
return {
root // 暴露出来的变量名必须和template 里面ref的值相同
}
}
}
</script>
// ------------ 实际使用 ------------
<template>
// publish 是一个子组件
<publish ref="pubRef"></publish>
<div @click="handleAddPublish">点击</div>
</template>
<script lang="ts">
// 引入ref API
import { ref } from 'vue'
export default {
setup() {
const root = ref(); // 如果是在 ts 环境下,不能传入null作为参数,否则root.value将提示结果为null, 不能调用子组件的方法;在js环境可以传null
const handleAddPublish = () => {
root.value.init(); // init 是子组件return出来的一个方法
};
return {
handleAddPublish,
pubRef: root // 暴露出来的变量名必须和template 里面ref的值相同
}
}
}
</script>
四、vue3中的nextTick
// nextTick: 将回调推迟到下一个DOM更新周期之后执行,在更改了一些数据以等待DOM更新后立即使用它。
import { nextTick } from 'vue'
setup() {
const changeMessage = newMessage => {
nextTick(()=>{
// to do list...
})
};
return {
changeMessage
}
}
五、详解单文件组件<script setup>
<script setup>
是在单文件组件(SFC)中使用组合式 API 的编译时语法糖。相比于普通的 <script>
语法,它具有更多优势。详情请阅读官方文档
- 基本语法
// 将 setup 属性添加到 script 标签上即可
<script setup>
console.log('hello script setup')
</script>
setup里面的代码会被编译成组件 setup()
函数的内容。这意味着与普通的 <script>
只在组件被首次引入的时候执行一次不同,<script setup>
中的代码会在每次组件实例被创建的时候执行,并且自带 return 功能,所有在里面声明的变量、函数都能在模板中直接使用!
-
使用 props、emit、useContext
vue3中如果想要获取 props、emit、attr等参数,需要从
setup(props, context)
的参数里面获取,但<script setup>
省略了这一步,所以获取方式也需要修改:
<template>
<p>{{type[0]}}</p>
<button @click="emit('setData', Number.parseInt(Math.random() * 10))">添加数据</button>
</template>
<script setup>
import { defineEmit, defineProps } from 'vue' // 这两个方法其实无需导入,他们是<script setup>里的编译器宏,会自动编译
// 获取props => 注意:props不能结构,会失去响应式效果
const props = defineProps({
list: {
type: Array,
default: () => []
}
})
// 获取emit
const emit = defineEmit(['deleteData', 'setData'])
// 获取slots、attrs 等其他组件
const { slots , attrs } = useContext()
</script>
- 自动注册指令与组件
<template>
<!-- 使用指令 -->
<div v-click-outside />
<!-- 使用组件 -->
<MyComponent />
</template>
<script setup>
// 指令导入后即可直接使用, 无需注册
import { directive as clickOutside } from 'v-click-outside';
// 组件导入后也可直接使用, 无需注册
import MyComponent from './MyComponent.vue'
</script>
<script setup>
是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。相比于普通的
文章仅为本人学习过程的一个记录,仅供参考,如有问题,欢迎指出!