【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数据: 本质是由父组件提供的数据,子组件拿到这个数据之后,只能获取,不能直接修改,遵循单向数据流原则,想要修改,需要用到子传父的方法。
相关推荐
长风清留扬16 分钟前
小程序毕业设计-音乐播放器+源码(可播放)下载即用
javascript·小程序·毕业设计·课程设计·毕设·音乐播放器
web1478621072330 分钟前
C# .Net Web 路由相关配置
前端·c#·.net
m0_7482478030 分钟前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
飞的肖34 分钟前
前端使用 Element Plus架构vue3.0实现图片拖拉拽,后等比压缩,上传到Spring Boot后端
前端·spring boot·架构
青灯文案141 分钟前
前端 HTTP 请求由 Nginx 反向代理和 API 网关到后端服务的流程
前端·nginx·http
m0_748254881 小时前
DataX3.0+DataX-Web部署分布式可视化ETL系统
前端·分布式·etl
ZJ_.1 小时前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
GIS开发特训营1 小时前
Vue零基础教程|从前端框架到GIS开发系列课程(七)响应式系统介绍
前端·vue.js·前端框架·gis开发·webgis·三维gis
Cachel wood1 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
学代码的小前端1 小时前
0基础学前端-----CSS DAY9
前端·css