【Vue】Scoped、组件间通信、Props检验

目录

Scoped

作用

*原理

组件通信

前置知识

什么是组件通信

为什么需要组件通信

如何进行组件通信

如何辨别两个组件的关系

父子组件通信

父传子

子传父

非父子组件通信

祖先传后代

语法

任意两个组件通信

步骤

Props校验

props是什么

作用

语法

组件的ref/reactive数据与props的区别


Scoped

作用

  • 默认情况下,写在任何一个.vue文件中style的样式是全局样式,这样的话,不仅会影响当前组件,也会影响其他组件。
  • 全局样式:会影响每个vue文件,存在样式污染/冲突的问题,style不添加scoped,默认都是全局样式。
  • 局部样式:只针对当前组件中的标签生效,不会影响其他组件的标签,如果想让样式变为局部样式,那么需要给style添加scoped属性。

综上,scoped的作用就是防止不同组件(vue文件)样式污染//冲突。

*原理

当给组件的style添加了scoped属性之后,组件会发生如下变化:

  1. scoped会给当前组件内的所有标签添加一个自定义属性,名为data-v-xxxxxxxx。
  2. scoped会用这个属性选择器[data-v-xxxxxxxx],配合我们编写的选择器形成一个交集选择器。
  3. 每个组件只要添加scoped属性,都会生成唯一的data-v-xxxxxxxx自定义属性。换句话说,每个组件生成的这个属性名都不同,因此形成的交集选择器只能选中当前组内的标签,保证了不会发生样式污染。

如下:表示既是h3又具备data-v-7b1a1c5e属性的

h3[data-v-7b1a1c5e]{

color:blue;

}

组件通信

前置知识

什么是组件通信

一个组件把数据传递给另一个组件。

为什么需要组件通信

开发Vue3的项目是借助了组件化的开发思想,不会把代码写在同一个文件中,而是会拆分一系列组件,进而通过组件的组装,拼装成完整的页面,这里难免需要进行组件间的数据传递,那么就需要组件通信了。

总的来说,可以归结于两点:

  1. 每个组件是一个独立的模块,组件的数据别的模块无法使用。
  2. 别的组件需要用到当前组件的数据,那么就需要组件通信了。

如何进行组件通信

需要辨别两个组件的关系,进而选择不同的通信方案

1、父子组件(掌握):

  • 父传子:props自定义属性
  • 子传父:emit自定义事件

2、非父子组件(了解):

  • 祖先与后代:provide() + inject()
  • 兄弟组件:eventBus(事件总线)
  • 跨组件通信方案:Pinia(状态管理)

如何辨别两个组件的关系

  1. 父子关系:谁被使用,谁就是子组件,当前组件就是父组件

父子组件通信

父组件通过props将数据传递给子组件,子组件通过emit将数据传递给父组件。

父传子

当子组件的数据不固定的时候,也就是子组件的数据不能写死,就需要父传子。

父传子的语法:

  1. 子组件通过defineProps( )接收自己需要的数据,进而使用数据。(子接)
  2. 父组件内,子组件的自定义标签上,通过自定义属性传递数据。(父传)

子组件

这里数组的名字自定义,不是固定的。

html 复制代码
<script setup>
    defineProps(['imgUrl','title','price'])
</script>

父组件

html 复制代码
<script setup>
    import MyGoods from './components/MyGoods.vue'
    //父组件提供的数据
    const goodsObj={
        id:'123456',
        name:'kkk',
        price:150,
        picture:'https://test.com'
    }
</script>
<template>
    <MyGoods :imgUrl="goodsObj.picture"/>
</template>

总结

  1. 子接:defineProps(['数据名称1','数据名称2'])
  2. 父传:自定义属性名="值"

子传父

当子组件需要修改父组件的数据(props接收的数据是只读的,不能修改),就需要使用子传父。

而子传父的的语法是:

  1. 父组件提供修改数据的方法/函数,并在子组件的自定义标签上,绑定自定义事件。
  2. 子组件在恰当的时机,触发/调用父组件修改数据的方法/函数。

子组件

html 复制代码
<template>
    <button @click="onCut">砍价</button>
</template>

<script setup>
    import { ref } from 'vue'
    const props=defineProps(['imgUrl','title','price','idx'])

    //拿到触发自定义事件的函数 emit
    const emit=defineEmits()

    //定义子组件砍价按钮,emit传入父组件给出的修改函数,和需要的参数
    const onCut=()=>{
        emit('ccc',props.idx,1)
    }
</script>

父组件

html 复制代码
<template>
    <MyGoods @ccc="subPrice"/>
</template>

<script setup>
    import MyGoods from './components/MyGoods.vue'
    const subPrice = (i,price) => {
        goodsList.value[i].price -= price
    }
</script>

总结

  1. 父监听/绑定:@自定义事件="父修改数据的函数"
  2. 子触发/通知:emit('自定义事件',传递的参数.....)

非父子组件通信

祖先传后代

作用:实现跨层级数据传递

语法

祖先组件提供数据

provide('数据名称',数据)

示例:

html 复制代码
<script setup>
    import {ref,provide} from 'vue'
    const money=ref(1000)
    provide('money',money)
</script>

后代组件获取数据

const 数据=inject('数据名称')

示例:

html 复制代码
<script setup>
    import {ref,inject} from 'vue'
    const money=inject('money')
</script>

任意两个组件通信

EventBus可以实现任意两个组件通信,但是使用较为麻烦,能不使用,便不使用。

步骤

前提:需要一个中间者(媒婆)

  1. 创建一个中间者模块
  2. 确定消息的发送方,中间者.emit('事件名称',数据)
  3. 确定消息的接收方:中间者.on('事件名称',(数据)=>{ })

中间者采用第三方模块mitt,步骤如下:

1、安装mitt

npm install --save mitt

2、与App.vue同级,创建一个eventBus.js文件,在这创建一个中间人并导出

javascript 复制代码
import mitt from'mitt'

//创建中间人
const meipo=mitt()

//默认导出:目的是给其他组件可以拿到meipo这个中间人
export default meipo

3、发送方

html 复制代码
<template>
<div>
  <button @click="onSend">Send</button>
</div>
</template>

<script setup>
    import {ref} from 'vue'
    import meipo from "../eventBus.js"
    const msg=ref('12345678')
    const onSend=()=>{
      meipo.emit("sendMsg",msg.value)
    }
</script>

4、接收方

html 复制代码
<script setup>
    import {ref} from 'vue'
    import meipo from "../eventBus.js"
    meipo.on('sendMsg',(msg)=>{
      console.log(msg.value)
    })
</script>

Props校验

props是什么

如上面父子组件通信时使用到的,绑定在组件标签上的自定义属性,就是props

html 复制代码
<MyGoods :imgUrl="goodsObj.picture"/>

作用

当我们在进行props传属性值时,可能会出现类型不匹配之类的情况,因此我们需要为prop指定验证要求,不符合要求,控制台就会有错误提示,以此来提高代码的健壮性。

换句话说,子组件接收的是什么样的props,那么父组件在传递的时候也必须按照这个规则来传递,双方都得遵守的一种协议。

语法

1、数组接收法:

defineProps(['imgUrl','title'])

  • 优点:简单、上手快。
  • 缺点:无法对接收的props进行校验,健壮性差。

2、对象接收法(简易写法校验,只校验类型):

defineProps({

title:String

imgUrl:String

})

  • 优点:可以对props做校验,健壮性相对好点。
  • 缺点:写法相对复杂些。

3、完整写法校验

简易写法的校验只能验证数据类型,在某些情况下可能需要要求数据必须传等条件,此时简易写法便不能满足要求。

语法

defineProps({

属性名:{

type:Number, //数据类型约束

default:50, //默认值,与required:true冲突,如果同时出现,required优先级更高

required:true/false //是否必须传值,默认不是必须传值

}

})

但是如果需要校验数据的范围,此时上述的方法便无法满足要求,就需要使用自定义校验函数

defineProps({

属性名:{

type:Number, //数据类型约束

default:50, //默认值,与required:true冲突,如果同时出现,required优先级更高

required:true/false //是否必须传值,默认不是必须传值

validator(value){

//value是实际props传递的值

if(value<0)

{

console.error("!")

return fasle

}

return true

}

}

})

组件的ref/reactive数据与props的区别

相同点

都可以为组件提供数据,进而使用

不同点

  1. ref/reative数据:是组件自己的数据,组件既可以获取,也可以修改
  2. props数据: 本质是由父组件提供的数据,子组件拿到这个数据之后,只能获取,不能直接修改,遵循单向数据流原则,想要修改,需要用到子传父的方法。
相关推荐
Your易元2 小时前
设计模式-状态模式
java·前端·算法·设计模式
网络点点滴4 小时前
将项目推到Github
javascript·github
HaanLen4 小时前
React19源码系列之 Hooks (useState、useReducer、useOptimistic)
服务器·前端
yuanyxh6 小时前
《精通正则表达式》精华摘要
前端·javascript·正则表达式
小飞大王6667 小时前
简单实现HTML在线编辑器
前端·编辑器·html
Jimmy7 小时前
CSS 实现卡牌翻转
前端·css·html
百万蹄蹄向前冲7 小时前
大学期末考,AI定制个性化考试体验
前端·人工智能·面试
向明天乄8 小时前
在 Vue 3 项目中集成高德地图(附 Key 与安全密钥申请全流程)
前端·vue.js·安全
sunshine_程序媛8 小时前
vue3中的watch和watchEffect区别以及demo示例
前端·javascript·vue.js·vue3
电商数据girl8 小时前
【经验分享】浅谈京东商品SKU接口的技术实现原理
java·开发语言·前端·数据库·经验分享·eclipse·json