首页 前端知识 盘点初次使用vue3遇到的那些小坑

盘点初次使用vue3遇到的那些小坑

2024-10-29 23:10:07 前端知识 前端哥 424 535 我要收藏

文章目录

  • 前言
  • 一、关于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语法糖下,简直不要太爽。。

转载请注明出处或者链接地址:https://www.qianduange.cn//article/19593.html
标签
评论
发布的文章
大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!