【前端-VUE】Vue3组件组成部分及组件通信(详解)

一、父子间通信

1.父传子:

2.子传父:

3.什么是prop

Prop定义:组件上注册的一些自定义属性

Prop作用:向子组件传递数据

特点

  • 可以传递任意数量的prop
  • 可以传递任意类型的prop

3.1 props校验

思考:组件的prop可以乱传么?

不可以

作用:为组件的prop指定验证要求,不符合要求,控制台就会有错误提示——>帮助开发者,快速发现错误

语法

①类型校验

②非空校验

③默认值

④自定义校验

props:{校验的属性名: 类型 //Number String Boolean Array Object…},

3.2更详细的props校验

props:{校验的属性名:{type:类型, // Number String Boolean …required: true, // 是否必填default: 默认值, // 默认值validator (value){// 自定义校验逻辑return 是否通过校验}}
},

4.prop & data、单向数据流

共同点:都可以给组件提供数据。

区别

  • data的数据是自己的——> 随便改
  • prop的数据是外部的 ——> 不能直接改,要遵循 单向数据流

总结:

谁的数据谁负责

1.data:自己的数据,随便改(谁的数据谁负责)

2.prop传过来的数据(外部的数据)不能直接改

3.单向数据流:父组件的prop更新,会单向向下流动,影响到子组件

4.1综合案例

4.2核心代码

App.vue

<template><!-- 主体区域 --><section id="app"><TodoHeader @add="handleAdd"></TodoHeader><TodoMain @del="handleDel" :list="list"></TodoMain><TodoFooter @clear="handleClear" :list="list"></TodoFooter></section><router-view></router-view>
</template>
<script>
import TodoHeader from './components/TodoHeader.vue';
import TodoMain from './components/TodoMain.vue';
import TodoFooter from './components/TodoFooter.vue';
// 渲染功能:
// 1.提供数据 ——> 提供在公共的父组件 App.Vue
// 2.通过父传子,将数据传递给TodoMain
// 3.利用v-for渲染
// 添加功能
// 1.收集表单数据 v-model
// 2.监听事件(回车+点击 都要进行添加)
// 3.子传父,将任务名称传递给父组件App.vue
// 4.进行添加 unshift(自己的数据自己负责)
// 删除功能:
// 1.监听事件(监听删除的点击)携带 id
// 2.子传父,将删除的id传递给父组件App.vue
// 3.进行删除 filter(自己的数据自己负责)
// 底部合计:父传子传list ——> 渲染
// 清空功能:子传父 通知到父组件 ——> 父组件进行清空操作
// 持久化存储:watch深度监视list的变化 ——> 往本地存储 ——> 一进入页面优先读取本地
export default {data () {return {list: JSON.parse(localStorage.getItem('list')) || [{ id: 1, name: '打篮球' },{ id: 2, name: '看电影' },{ id: 3, name: '逛街' },]}},methods: {handleAdd (todoName) {this.list.unshift({id: +new Date(),name: todoName})},handleDel (id) {this.list = this.list.filter(item => item.id !== id)},handleClear () {this.list = []}},watch: {list: {deep: true,handler (newValue) {localStorage.setItem('list', JSON.stringify(newValue))}}},components: {TodoHeader,TodoMain,TodoFooter}
}
</script>

TodoMain.vue

<template><section class="main"><ul class="todo-list"><li v-for="(item, index) in list" class="todo"><div class="view"><span class="index">{{ index + 1 }}</span><label>{{ item.name }}</label><button @click="handleDel(item.id)" class="destroy"></button></div></li></ul></section>
</template>
<script>
export default {props: {list: Array},methods: {handleDel (id) {this.$emit('del', id)}}
}
</script>

Todoheader.vue

<template><header class="header"><h1>小黑笔记本</h1><input @keyup.enter="handleAdd" v-model="todoName" placeholder="请输入任务" class="new-todo" /><button @click="handleAdd" class="add">添加任务</button></header>
</template>
<script>
export default {data () {return {todoName: ''}},methods: {handleAdd () {// console.log(this.todoName)if (this.todoName.trim() === '') {alert('任务名称不能为空')return}this.$emit('add', this.todoName)this.todoName = ''}}
}
</script>

TodoFooter.vue

<template><!-- 统计和清空 --><footer class="footer"><!-- 统计 --><span class="todo-count">合 计:<strong>{{ list.length }}</strong></span><!-- 清空 --><button @click="clear" class="clear-completed">清空任务</button></footer>
</template>
<script>
export default {props: {list: Array},methods: {clear () {this.$emit('clear')}}
}
</script>

4.3总结

核心步骤:

①拆分基础组件

新建组件——> 拆分存放结构 ——> 导入注册使用

②渲染待办事项

提供数据(公共父组件)——> 父传子传递list ——> v-for渲染

③添加任务

收集数据 v-model ——>监听事件 ——> 子传父传递任务 ——> 父组件unshift

④删除任务

监听删除携带id ——> 子传父传递id ——> 父组件filter删除

⑤底部合计 和 清空功能

底部合计:父传子传递list ——> 合计展示

清空功能:监听点击 ——>子传父通知父组件 ——> 父组件清空

⑥持久化存储

watch监视数据变化,持久化到本地

二、非父子通信

1.非父子通信- event bus 事件总线

作用:非组件之间,进行简易消息传递。(复杂场景——>Vuex)

1.创建一个能够访问到的事件总栈(空Vue实例)——>utils/EventBus.js

improt Vue form 'vue'
const Bus = new Vue()
export default Bus

2.A组件(接收方),监听Bus实例的事件

created (){Bus.$on('sendMsg',(msg)=>{this.msg = msg})
}

3.B组件(发送方),触发Bus实例的事件

Bus.$emit('sendMsg','这是一个消息')

代码:

App.vue

<template><div><BaseA></BaseA><BaseB></BaseB><BaseC></BaseC></div>
</template>
<script>
import BaseA from './components/BaseA.vue'
import BaseB from './components/BaseB.vue'
import BaseC from './components/BaseC.vue'
export default {components: {BaseA,BaseB,BaseC}
}
</script>

 BaseA.vue

<template><div class="baseA">我是A组件(接收方)<p>{{ msg }}</p></div>
</template>
<script>
import Bus from '../utils/EventBus'
export default {created () {// 2.在A组件(接收方),进行监听(订阅消息)Bus.$on('sendMsg', (msg) => {this.msg = msg})},data () {return {msg: ''}}
}
</script>
<style>
.baseA {width: 200px;height: 150px;padding: 10px;margin-top: 10px;border: 3px solid #000;border-radius: 5px;font-size: 20px;
}
</style>

 BaseB.vue

<template><div class="baseB">我是B组件(发布方)<button @click="clickSend">发布通知</button></div>
</template>
<script>
import Bus from '../utils/EventBus'
export default {methods: {clickSend () {// 3.B组件(发件方)触发事件的方式传递参数(发布消息)Bus.$emit('sendMsg', '今日晴天,适合郊游')}}
}
</script>

BaseC.vue

<template><div class="baseC">我是C组件(接收方)<p>{{ msg }}</p></div>
</template>
<script>
import Bus from '../utils/EventBus'
export default {created () {// 2.在C组件(接收方),进行监听(订阅消息)Bus.$on('sendMsg', (msg) => {this.msg = msg})},data () {return {msg: ''}}
}
</script>
<style>
.baseA {width: 200px;height: 150px;padding: 10px;margin-top: 10px;border: 3px solid #000;border-radius: 5px;font-size: 20px;
}
</style>

EventBus.js

// 1.创建一个都能访问到的事件总线(空的Vue实例)
import { createApp } from 'vue';const Bus = createApp({}); // 创建一个空的Vue实例
export default Bus

2.非父子通信(拓展)-provide & inject

provide & inject 作用:跨层级共享数据

1.父组件provide提供数据

export default {provide (){return {//普通类型【非响应式】color: this.color,// 复杂类型【响应式】userInfo: this.userInfo,}}
}

2./孙组件inject取值使用

export default {inject: ['color','userInfo'],created(){console.log(this.color,this.userInfo)}
}

代码:

App.vue

<template><div class="app"><span>我是App组件</span><button @click="change">修改数据</button><SonA></SonA><SonB></SonB></div>
</template>
<script>
import SonA from './components/SonA.vue'
import SonB from './components/SonB.vue'
export default {provide () {return {color: this.color,userInfo: this.userInfo}},data () {return {color: 'pink', // 简单类型(非响应式)userInfo: { // 复杂类型(响应式) - 推荐name: 'zs',age: 18}}},methods: {change () {this.color = 'green'this.userInfo.name = 'ls'}},components: {SonA,SonB}
}
</script>

SonA.vue

<template><div class="SonA">我是SonA组件{{ color }} - {{ userInfo.name }} - {{ userInfo.age }}</div><GrandSon></GrandSon>
</template>
<script>
import GrandSon from './GrandSon.vue';
export default {inject: ['color', 'userInfo'],created () {console.log(this.color, this.userInfo)},components: {GrandSon}
}
</script>

SonB.vue

<template><div class="SonB">我是SonB组件{{ color }} - {{ userInfo.name }} - {{ userInfo.age }}</div>
</template>
<script>
export default {inject: ['color', 'userInfo'],created () {console.log(this.color, this.userInfo)}
}
</script>

GrandSon.vue

<template><div class="GrandSon">我是GrandSon组件{{ color }} - {{ userInfo.name }} - {{ userInfo.age }}</div>
</template>
<script>
export default {inject: ['color', 'userInfo'],created () {console.log(this.color, this.userInfo)}
}
</script>

 

三、v-model原理

1.原理:

v-model本质上是一个语法糖。例如应用在输入框上,就是value属性和input事件的合写。

作用:提供数据的双向绑定

①数据变,视图跟着变 :value

②页面输入改变,数据会自动改变 @input

注意:$event用于模板中,获取时间中的形参

<template><div class="app"><input v-model="msg" type="text">// 等价于<input :value="msg" @input="msg = $event.target.value" type="text"></div>
</template>

2.表单类组件封装&v-model简化代码

2.1表单类组件 封装

①父传子:数据 应该是父组件props传递过来的,v-model拆解 绑定数据

②子传父:监听输入,子传父传值给父组件修改

本质:实现了子组件 和 父组件数据 的双向绑定

2.2 父组件v-model 简化代码,实现 子组件 和父组件数据 双向绑定

①子组件中:props通过value接收,事件触发input

②父组件中:v-model给组件直接绑数据 (:value + @input)

代码:

App.vue

<template><div class="app"><!-- <BaseSelect :cityId="selectId" @changeId="selectId = $event"></BaseSelect> --><BaseSelect v-model="selectId"></BaseSelect></div>
</template>
<script>
import BaseSelect from './components/BaseSelect.vue'
export default {data () {return {selectId: '104'}},components: {BaseSelect}
}
</script>

BaseSelect.vue

<template><div><!-- <select :value="cityId" @change="handleChange"> --><select :value="value" @change="handleChange"><option value="101">北京</option><option value="102">上海</option><option value="103">武汉</option><option value="104">深圳</option><option value="105">广州</option></select></div>
</template>
<script>
export default {props: {// cityId: Stringvalue: String},methods: {handleChange (e) {// console.log(e.target.value)// this.$emit('changeId', e.target.value)this.$emit('input', e.target.value)}}
}
</script>

四、sync修饰符

  • 作用:可以实现 子组件 与 父组件数据 的双向绑定,简化代码
  • 特点:prop属性名,可以自定义,非固定为value
  • 场景:封装弹窗类的基础组件,visible属性 true显示 false隐藏
  • 本质:就是 :属性名 和 @update:属性名 合写

代码:

App.vue

<template><div class="app"><button class="logout" @click="isShow = true">退出按钮</button><!-- :visible.sync => :visible + @update:visible --><BaseDialog :visible.sync="isShow"></BaseDialog></div>
</template>
<script>
import BaseDialog from './components/BaseDialog.vue';
export default {data () {return {isShow: false}},components: {BaseDialog}
}
</script>

BaseDialog.vue

<template><div v-show="visible"><div><div><h3>温馨提示:</h3><button class="close" @click="close"></button></div><div><p>你确定要退出本系统吗?</p></div><div><button @click="close">确认</button><button @click="close">取消</button></div></div></div>
</template>
<script>
export default {props: {visible: Boolean},methods: {close () {this.$emit('update:visible', false)}}
}
</script>

五、ref和$refs

作用利用ref$refs可以用于获取dom(文档对象模型中代表HTML元素的JavaScript对象)元素,或组件实例

特点:查找范围——>当前组件内(更精准稳定)

获取dom

1.目标标签-添加ref属性

<div ref="chartRef">我是渲染表的容器</div>

2.恰当时机,通过this.$refs.xxx,获取目标标签

mounted(){
console.log(this.$refs.chartRef)
},

代码:

App.vue

<template><div class="app"><BaseChart></BaseChart></div>
</template>
<script>
import BaseChart from './components/BaseChart.vue'
export default {data () {return {}},components: {BaseChart}
}
</script>

BaseChart.vue

<template><div ref="mychart" id="base-chart-box" style="width: 600px; height: 400px"></div>
</template>
<script>
// 装包:yarn add echarts
import * as echarts from 'echarts';
export default {mounted () {// const myChart = echarts.init(document.querySelector('.base-chart-box'))const myChart = echarts.init(this.$refs.mychart)// 指定图表的配置项和数据const option = {title: { text: 'My Chart' },xAxis: { data: ["衬衫", "羊毛衫", "裤子", "高跟鞋", "袜子"] },yAxis: {},series: [{ type: 'bar', data: [5, 20, 36, 10, 10] }],}// 使用刚指定的配置项和数据显示图表。myChart.setOption(option)}
}
</script>

效果图:

代码:

App.vue

<template><div class="app"><BaseForm ref="baseForm"></BaseForm><button @click="handleGet">获取数据</button><button @click="handleReset">重置数据</button></div>
</template>
<script>
import BaseForm from './components/BaseForm.vue'
export default {data () {return {}},methods: {handleGet () {console.log(this.$refs.baseForm.getValues())},handleReset () {this.$refs.baseForm.resetValues()}},components: {BaseForm}
}
</script>

BaseForm.vue

<template><form action="">账号:<input type="text" v-model="account" />密码:<input type="password" v-model="password" /></form>
</template>
<script>
export default {data () {return {account: '',password: ''}},methods: {// 方法1:收集表单数据,返回对象getValues () {return {account: this.account,password: this.password}},// 方法2:重置表单resetValues () {this.account = ''this.password = ''}}
}
</script>

六、Vue异步更新、$nextTick

需求:编辑标题,编辑框自动聚焦

1.点击编辑,显示编辑框

2.让编辑框立刻获取焦点

this.isShowEdit = true // 显示输入框
this.$refs.inp.focus() // 获取焦点

问题:“显示之后”,立刻获取焦点是不能成功的!

原因:vue是异步更新DOM(提升性能)

$nextTick:DOM更细后,才会触发执行此方法里的函数体

语法:this.$nextTick(函数体)

this.$nextTick(()=>{
this.$refs.inp.focus()
})

代码:

App.vue

<template><div class="app"><div v-if="isShowEdit"><input ref="inp" v-model="editValue" type="text"><button>确认</button></div><!-- 默认状态 --><div v-else><span>{{ title }}</span><button @click="handleEdit">编辑</button></div></div>
</template>
<script>
export default {data () {return {title: '大标题',editValue: '',isShowEdit: false}},methods: {handleEdit () {// 1.显示输入框 (异步dom更新,获取不到数据)this.isShowEdit = true// 2.让 输入框 获取焦点($nextTick等dom更新完,立刻执行准备的函数体)this.$nextTick(() => {this.$refs.inp.focus()})}}
}
</script>

总结:

1.Vue是异步更新DOM的

2.想要在DOM更新完成之后做某件事,可以使用$nextTick

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/657960.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

母排设计时没有柜体3D数据?来试试SuperPanel的钣金功能!

CAD版SuperPanel软件能够助力用户快速、准确地设计和修改母排&#xff0c;同时快速输出加工图纸和数控加工代码。在壳体外购&#xff0c;没有柜体3D数据的情况下&#xff0c;如何轻松进行母排设计&#xff1f;一起来学习利驰数字母排的钣金功能吧&#xff01; SuperPanel的钣金…

【新课】安装部署系列Ⅲ—Oracle 19c Data Guard部署之两节点RAC部署实战

本课程由云贝教育-刘峰老师出品&#xff0c;感谢关注 课程介绍 Oracle Real Application Clusters (RAC) 是一种跨多个节点分布数据库的企业级解决方案。它使组织能够通过实现容错和负载平衡来提高可用性和可扩展性&#xff0c;同时提高性能。本课程基于当前主流版本Oracle 1…

python 写入csv文件 内容乱码

问题 python 写入csv文件 内容乱码 详细问题 笔者核心代码 import csv # 将数据写入 CSV 文件 csv_file_path "soil_data.csv" header ["经度", "纬度", "土壤类型", "pH值"]with open(csv_file_path, mode"w&q…

【PyTorch实战演练】Fast R-CNN中的RoI(Region of Interest)池化详解

文章目录 0. 前言1. ROI池化的提出背景2. RoI池化的结构与工作原理3. RoI池化的作用及意义4. RoI使用示例 0. 前言 按照国际惯例&#xff0c;首先声明&#xff1a;本文只是我自己学习的理解&#xff0c;虽然参考了他人的宝贵见解及成果&#xff0c;但是内容可能存在不准确的地方…

优化器刺客之limit 1--Order by col limit n 代价预估优化探索

一、现象 order by 排序加了limit后更慢了&#xff1f; test# explain analyze select userid from dba_users where username like %aaaaaaaaaaaaaaaaaa% order by userid ;QUERY PLAN --------------…

ElementUI Form:Radio 单选框

ElementUI安装与使用指南 Radio 单选框 点击下载learnelementuispringboot项目源码 效果图 el-radio.vue 页面效果图 项目里el-radio.vue代码 <script> export default {name: el_radio,data() {return {radio: 1,radio2: 2,radio3: 3,radio4: 上海,radio5: 上海,ra…

12个适合后端程序员的前端框架

前言 今天我们分享12个适合后端程序员的前端框架&#xff0c;本文中的所有前端框架都已经收录到适合后端程序员的前端框架GitHub Issues知识库中&#xff0c;假如大家有更好前端框架推荐欢迎到以下GitHub项目地址留言或者在文末留言&#xff08;注意&#xff1a;排名不分先后&a…

c#鼠标绘制

有用的没用的&#xff0c;用的上的用不上的&#xff0c;能写的不能写的&#xff0c;反正想起来就写了&#xff0c;比如这篇&#xff0c;好像一般也没什么用&#xff0c;emmm&#xff0c;或许&#xff0c;做录制软件的时候可以用一下。 顾名思义&#xff0c;本篇主要就是来实现将…

dvwa,xss反射型lowmedium

xss&#xff0c;反射型&#xff0c;low&&medium low发现xss本地搭建实操 medium作为初学者的我第一次接触比较浅的绕过思路high low 发现xss 本关无过滤 <script>alert(/xss/)</script> //或 <script>confirm(/xss/)</script> //或 <scr…

幻兽帕鲁服务器游戏怎么升级版本?

幻兽帕鲁服务器游戏怎么升级版本&#xff1f;自建幻兽帕鲁服务器进入Palworld游戏提示“您正尝试加入的比赛正在运行不兼容的游戏版本&#xff0c;请尝试升级游戏版本”什么原因&#xff1f;这是由于你的客户端和幻兽帕鲁服务器版本不匹配&#xff0c;如何解决&#xff1f;更新…

故障诊断 | 一文解决,SVM支持向量机的故障诊断(Matlab)

效果一览 文章概述 故障诊断 | 一文解决,SVM支持向量机的故障诊断(Matlab) 支持向量机(Support Vector Machine,SVM)是一种常用的监督学习算法,用于分类和回归分析。SVM的主要目标是找到一个最优的超平面(或者在非线性情况下是一个最优的超曲面),将不同类别的样本分开…

Flutter的安装与环境配置

一、下载安装Futter&#xff1a; 1、Flutter中文文档&#xff1a; 安装和环境配置 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 2、下载 Futter SDK&#xff1a; Flutter中文文档 里面有&#xff0c;下载完成之后找个文件夹解压出来&#xff0c;最好不要将 Flu…

大数据分析|从七个特征理解大数据分析

文献来源&#xff1a;Saggi M K, Jain S. A survey towards an integration of big data analytics to big insights for value-creation[J]. Information Processing & Management, 2018, 54(5): 758-790. 下载链接&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1…

qiankun子应用静态资源404问题有效解决(遇到了http请求静态文件404、css文件引用图片无法显示、svg图片转换成 base64无法显示等问题)

在&#x1f449;&#x1f3fb; qiankun微前端部署&#x1f448;&#x1f3fb;这个部署方式的前提下&#xff0c;遇到的问题并解决问题的过程 >> 问题现象 通过http请求本地的静态json文件404 css中部分引入的图片无法显示 >> 最开始的解决方式 在&#x1f449;…

微信小程序(二十五)条件判断语句与结构隐藏

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.条件判断语句的演示 2.隐藏结构的演示 源码&#xff1a; index.wxml <view><!-- wx:if和wx:else为条件判断语句 --><text wx:if"{{isLogin}}">已登入的用户</text><tex…

【HarmonyOS应用开发】ArkUI 开发框架-基础篇-第一部分(七)

常用基础组件 一、组件介绍 组件&#xff08;Component&#xff09;是界面搭建与显示的最小单位&#xff0c;HarmonyOS ArkUI声明式开发范式为开发者提供了丰富多样的UI组件&#xff0c;我们可以使用这些组件轻松的编写出更加丰富、漂亮的界面。组件根据功能可以分为以下五大类…

Flink中StateBackend(工作状态)与Checkpoint(状态快照)的关系

State Backends 由 Flink 管理的 keyed state 是一种分片的键/值存储&#xff0c;每个 keyed state 的工作副本都保存在负责该键的 taskmanager 本地中。另外&#xff0c;Operator state 也保存在机器节点本地。Flink 定期获取所有状态的快照&#xff0c;并将这些快照复制到持…

Android Studio 安装配置教程 - Windows版

Android Studio下载 安装&#xff1a; 下载&#xff1a; Android Studio Hedgehog | 2023.1.1 | Android Developers (google.cn) 安装&#xff1a; 基本不需要思考跟着走 默认下一步 默认下一步 自定义修改路径&#xff0c;下一步 默认下一步&#xff0c;不勾选 默认下一…

RHCE 综合项目-博客

目录 业务需求 一、准备工作 1、配置静态IP 2、修改主机名及hosts映射 3、开启防火墙 4、时间同步 5、配置免密ssh登录 二、环境搭建 1、Server-web端安装LAMP环境软件 2、Server-NFS-DNS端上传博客软件 3、Server-NFS-DNS端设置NFS共享 三、Server-web设置 1、挂…