文章目录
- 前言
- 一、关于reactive数据直接赋值破坏响应式结构
- 二、关于获取当前路由地址的两个注意点
- 1.router.currentRoute 相当于 $route
- 2.router.currentRoute是ref响应式数据 要拿值的话需要.value,或者用unref转
- 三、关于父组件传递props异步数据到子组件遇到的问题
- 1.子组件使用watch监听
- 2.子组件使用computed计算属性返回
- 3.父组件使用v-if判断,等获取到数据后再渲染子组件
- 四、关于通过ref获取组件实例调用子组件方法遇到的一些问题
- 1.父组件watch判断已经获取到子组件ref实例后再操作
- 2.nextTick方法,在DOM更新后调用
- 总结
前言
对于新手而言,底子不足,积累有限,用个技术只知其然,不知其所以然,羡慕大佬理解底层原理,一看就能锁定问题,还能举一反三,但成长的路总是迂回曲折的,记忆靠不住就只能费手喽~
一、关于reactive数据直接赋值破坏响应式结构
在使用reactive定义复杂结构的响应式数据时,当我们将响应式对象的属性赋值或解构至本地变量时,或是将该属性传入一个函数时,会失去响应性,推荐的写法是:
<script setup>
import {reactive,onMounted,toRefs} from 'vue'
const state=reactive({
arr:[]
})
const { arr } = toRefs(state) // 将属性从state构出来 方便读取
onMounted(()=>{
state.arr=[1,2,3]
})
</script>
<template>
<div>用在模板渲染:{{ arr }} </div>
</template>
<style>
</style>
同理,在使用provide,inject组件通讯的时候,需要把整个响应式对象一起传过去,举例:
父组件代码
<template>
<div>
<p>{{ list }}</p>
<p>姓名:{{ user.name }}</p>
<p>年龄:{{ user.age }}</p>
</div>
<Version></Version>
</template>
<script setup>
import { reactive, toRefs, onMounted, provide, ref } from 'vue';
import Version from './Version.vue';
const isUpdate = ref(false)
const state = reactive({
list: [],
user: {},
})
const { list, user } = toRefs(state)
onMounted(() => {
state.list = [1, 2, 3],
state.user = { name: '小小梦想家', age: 18 }
isUpdate.value = true
})
provide('userInfo',state.user) // 直接传reactive里的某个属性
provide('userDetail',state) // 把整个reactive对象传过去
provide('isUpdate_a',isUpdate)
provide('isUpdate_b',isUpdate.value)
</script>
<style scoped lang="less"></style>
子组件代码
<template>
<div>
<h2>reactive</h2>
<p>只传递reactive对象的单个属性,破坏了响应性 :{{ userInfo }}</p>
<p> 传递整个reactive对象,通过读取对象属性的方式获取需要的数据 :{{ userDetail.user }}</p>
<h2>ref</h2>
<p>破坏了响应性,只获取到的初始值:{{ isUpdate_b }}</p>
<p>能获取到的最新值:{{ isUpdate_a }}</p>
</div>
</template>
<script setup>
import { inject } from 'vue';
const userInfo = inject('userInfo')
const userDetail = inject('userDetail')
const isUpdate_a = inject('isUpdate_a')
const isUpdate_b = inject('isUpdate_b')
</script>
<style scoped lang="less"></style>
页面效果
二、关于获取当前路由地址的两个注意点
1.router.currentRoute 相当于 $route
但是$route.path 或者 $route.fullPath只能在.vue文件中使用 ,js模块中要使用 router.currentRoute
2.router.currentRoute是ref响应式数据 要拿值的话需要.value,或者用unref转
代码如下(示例) :
<template>
<p>$route获取当前路由地址:{{ $route.path }}</p>
<p>router.currentRoute:{{ currentRoute_false }}</p>
<p>router.currentRoute.value:{{ currentRoute_true }}</p>
</template>
<script setup>
import { useRouter } from 'vue-router';
const router = useRouter();
const currentRoute_false = router.currentRoute.fullPath //没有.value
const currentRoute_true = router.currentRoute.value.fullPath
</script>
<style scoped lang='less'>
</style>
三、关于父组件传递props异步数据到子组件遇到的问题
vue3中,使用props传递异步数据的时候 子组件存在拿不到数据的情况,照理这个问题vue2应该也是存在的,但确实之前写2项目的时候并没有出现过类似的问题 大概是2里面用工厂函数返回默认值是可以等待异步数据的?
先记录一下我在3里面尝试过的几种方案吧;
1.子组件使用watch监听
import { ref, watch } from 'vue';
export default {
name: 'Watch',
props: {
list: {
type: Array,
default: () => [],
},
},
setup(props) {
const list = ref([]);
watch(
() => props.list,
(val) => {
list.value = val;
}
);
return {
list,
};
},
};
2.子组件使用computed计算属性返回
<script>
import { computed } from 'vue';
export default {
name: 'Computed',
props: {
list: {
type: Array,
default: () => [],
},
},
setup(props) {
const list = computed(() => props.list);
return {
list,
};
},
};
</script>
3.父组件使用v-if判断,等获取到数据后再渲染子组件
<template>
<div id="app">
<child :dataList="dataList" v-if="isGetData"></child>
</div>
</template>
<script setup>
import child from './views/child'
import { ref, onMounted } from 'vue'
const isGetData = ref(false) //初始为false,就不会被渲染对应的子组件
const dataList = ref([])
onMounted(() => {
// 用定时器模拟发请求异步获取后端接口的数据
setTimeout(() => {
dataList.value = [1, 2, 3]
// 拿到数据以后,再把isGetData置为true,这样的话,组件就会被渲染,数据也就能被传递过去了
isGetData.value = true
}, 200)
})
</script>
四、关于通过ref获取组件实例调用子组件方法遇到的一些问题
在父组件中用ref实例直接去调用子组件暴露的方法,有些情况下会报错,提示找不到该方法。原因是此时子组件还没挂载好,目前尝试过的可行方案有
1.父组件watch判断已经获取到子组件ref实例后再操作
watch(
// 监听获取到echartRef实例 且取得父组件传递的必要数据后再调用初始化图表的方法
[echartRef, () => props.chartData],
([el, data]) => {
if (!el || (data.xData && data.xData.length === 0)) return;
initChart();
},
{ immediate: true, deep: true }
);
2.nextTick方法,在DOM更新后调用
const handleClick = () => {
// 如果直接使用,子组件的方法,会获取不到这个方法,还没有挂载好,
// commentRef.value?.getCommentData()
// 延迟使用
nextTick(() => {
commentRef.value?.getData()
})
总结
小问题还是有很多 ,一时间也想不全了,后面想到再补充吧~ 现学现用总算把第一个vue3项目完成了,没有同事强烈推荐的惊喜,就觉得用个啥都要import挺麻烦的,.value也挺讨厌~有的时候一下没反应过来,找半天……不过整体还是不错的,值得学习,尤其setup语法糖下,简直不要太爽。。