Vue3.2新功能与父子传值还有你可能遇到的bug:emit is not a function

1,034 阅读2分钟

前言

Vue3新出的setup让它有质的飞跃,vue3用起来也比vue2要爽很多,但是两者之间很多写法是不兼容的,例如父子通信就有很大变化,不仅如此,vue3.0跟vue3.2之间也有一些变化会让你报错

vue3中使用defineProps来接受父组件传过来的prop, 使用defineEmit来给父组件传递信息

父传子

父组件通过prop给子组件传值

定义的子组件myMap,如果你用了v-model:并且传的值是对象或数组,那么子组件可以通过Update :modelValue修改你父组件传入的prop,下面代码传递是String类型值,Update的用法与使用案例在下面的子向父传值中有讲解。

         <myMap
              v-model:lat="form.lat"
              v-model:lon="form.lon"
              ></myMap>

子组件接受

<script setup>

import { defineEmits, defineProps,toRefs } from "vue";
const props = defineProps({
  //子组件接收父组件传递过来的值
  lat: Number||String,
  lon: Number||String,
});
//使用父组件传递过来的值
const { lat,lon } = toRefs(props);

</script>

这里可以看到我直接在script里面写了setup,这和之前的写一个setup函数有什么区别呢?

Vue3.2带来的setup语法糖

用过的人都说好

  1. 我们不需要想之前一样什么都得return了,直接写直接用,他会为我们默认暴露
  2. 我们注册组件时也是,直接import就可以了,不需要在去声明
  3. hooks(自定义函数)用起来也更加丝滑
  4. defineExpose可以帮我们向父组件暴露子组件的属性

方法:

//子组件代码
<script setup>
import { ref } from 'vue'
const a = 1
const b = ref('1')
//主动暴露组件属性
defineExpose({
  a,
  b
})
</script>
//父组件代码
<template>
  <div>父组件</div>
  <Child  ref='childRef' />
  <button @click='getChildData'>通过ref获取子组件的属性 </button>
</template>
<script setup>
import {ref} from 'vue'
import Child from './child.vue'
const childRef= ref()  //注册响应数据  
const getChildData =()=>{
  //子组件接收暴露出来得值
  console.log(childRef.value.a) //1
  console.log(childRef.value.b) //''1 响应式数据
}    
</script>

子组件向父组件传值

正常情况下,我们不能直接修改父组件传的值,但是如果我们让子组件把值传给父,父组件调用一个函数就可以帮我们实现功能

子组件写法

<template>
  <div id="map">
    map
    <div class="getD">
      <el-button @click="updateLatAndLon" type="success" size="small"
        >获取经纬度</el-button
      >
    </div>
  </div>
</template>

<script setup>
import { defineEmits } from "vue";
// 使用defineEmits创建名称,接受一个数组
const emit = defineEmits(["update:latAndLon"]);

const updateLatAndLon = () => {

  console.log(lat,lon);

  let param = {
    lat: "22.11",
    lon: "11.33",
  };
  //传递给父组件
  emit("update:latAndLon", param);
};
</script>

可以看到代码中emit里的update:latAndLon就是上面提到的子组件可以通过Update :modelValue修改你父组件传入的prop,要知道我们的父组件并没有设置show的自定义事件  但是你父组件show的值却更新了 这就是同步更新的好处  不需要你再手动来添加自定义事件

父组件接受与使用

template部分:

           <myMap
              @update:latAndLon="onUpdateLatAndLon"
           ></myMap>

script部分:

   const onUpdateLatAndLon = (latAndLon) => {
      // 更新form中的lat和lon值
      form.lat = latAndLon.lat;
      form.lon = latAndLon.lon;
    },

你可能遇到的bug

原因其实是vue3.2的一次改动,浏览器会跟你报错说它不认识emit

这个问题是因为你vue3的一些依赖包版本过低导致的,所以我们需要更新vue版本,或者升级@vue/compiler-sfc

yarn upgrade vue@3.2.36
# 更新到vue指定版本
yarn upgrade @vue/compiler-sfc@3.2.36

如果你执行了上面的还不管用,可以先删除node——modules和package.lock.json文件,可以用rimraf来帮你删除