河北网站建设免费推荐,百度云wordpress教程视频,罗湖网站制作多少钱,h5企业网站模板 下载Web前端-Vue2Vue3基础入门到实战项目-Day4 组件的三大组成部分(结构/样式/逻辑)scoped样式冲突data是一个函数 组件通信组件通信语法父传子子传父props详解什么是propsprops检验props与data的区别 非父子(扩展)事件总线 (event bus)provide - inject 案例 - 小黑记事本(组件版)… Web前端-Vue2Vue3基础入门到实战项目-Day4 组件的三大组成部分(结构/样式/逻辑)scoped样式冲突data是一个函数 组件通信组件通信语法父传子子传父props详解什么是propsprops检验props与data的区别 非父子(扩展)事件总线 (event bus)provide - inject 案例 - 小黑记事本(组件版)App.vueTodoHeader.vueTodoMain.vueTodoFooter.vue 进阶语法v-model详解v-model原理表单类组件封装v-model简化代码 sync修饰符ref和$refs$nextTick 来源 组件的三大组成部分(结构/样式/逻辑)
scoped样式冲突
全局样式: 默认的style样式, 会作用于全局局部样式: 加上scoped属性的style样式, 只会作用于当前组件scoped原理: 给当前组件模板的所有元素, 添加一个自定义属性 data-v-hash值: 根据hash值区分不同的组件css选择器后面, 被自动处理, 添加上了属性选择器 div[data-v-hash]
templatediv classbase-oneBaseOne/div
/templatescript
export default {}
/scriptstyle scoped
div {border: 3px solid blue;margin: 30px;
}
/styledata是一个函数
data必须是一个函数 - 保证每个组件实例, 维护独立的一个数据对象每次创建新的组件实例, 都会新执行一次data函数, 得到一个新对象
templatediv classbase-countbutton clickcount---/buttonspan{{ count }}/spanbutton clickcount/button/div
/templatescript
export default {data() {return {count: 100,}},
}
/scriptstyle
.base-count {margin: 20px;
}
/style组件通信
组件通信语法
组件关系和对应的通信方案 父子关系: props, $emit非父子关系: provide, inject或eventbus通用方案: vuex 父子通信方案的核心流程 父传子props: 父中给子添加属性传值子props接收使用 子传父$emit 子$emit发送消息父中给子添加消息监听父中实现处理函数
父传子
templatediv classapp styleborder: 3px solid #000; margin: 10px我是APP组件!-- 1.给组件标签添加属性方式 赋值 --Son :titlemyTitle/Son/div
/templatescript
import Son from ./components/Son.vue
export default {name: App,components: {Son,},data() {return {myTitle: 学前端就来黑马程序员,}},
}
/scriptstyle
/style!-- Son.vue --
templatediv classson styleborder:3px solid #000;margin:10px!-- 3.直接使用props的值 --我是Son组件 {{title}}/div
/templatescript
export default {name: Son-Child,// 2.通过props来接受props: [title]
}
/scriptstyle/style子传父
templatediv classapp styleborder: 3px solid #000; margin: 10px我是APP组件!-- 2. 父组件, 对消息进行监听 --Son :titlemyTitle changeTitlehandleChange/Son/div
/templatescript
import Son from ./components/Son.vue
export default {name: App,components: {Son,},data() {return {myTitle: 学前端就来黑马程序员,}},methods: {// 3. 提供处理函数, 提供逻辑handleChange(newTitle){this.myTitle newTitle}}
}
/scriptstyle
/style!-- Son.vue --
templatediv classson styleborder:3px solid #000;margin:10px我是Son组件 {{title}}button clickchangeFn修改title/button/div
/templatescript
export default {name: Son-Child,props: [title],methods: {changeFn(){// 1. 通过$emit, 向父组件发送消息通知this.$emit(changeTitle, 传智教育)}}
}
/scriptstyle/styleprops详解
什么是props
定义: 组件上注册的一些自定义属性作用: 向子组件传递数据特点: 可以传递任意数量的prop可以传递任意类型的prop
父组件
templatediv classappUserInfo:usernameusername:ageage:isSingleisSingle:carcar:hobbyhobby/UserInfo/div
/templatescript
import UserInfo from ./components/UserInfo.vue
export default {data() {return {username: 小帅,age: 28,isSingle: true,car: {brand: 宝马,},hobby: [篮球, 足球, 羽毛球],}},components: {UserInfo,},
}
/scriptstyle
/style子组件
templatediv classuserinfoh3我是个人信息组件/h3div姓名{{username}} /divdiv年龄{{age}} /divdiv是否单身{{isSingle ? 是 : 否}} /divdiv座驾{{car.brand}} /divdiv兴趣爱好{{hobby.join(, )}} /div/div
/templatescript
export default {props: [username, age, isSingle, car, hobby]
}
/scriptstyle
.userinfo {width: 300px;border: 3px solid #000;padding: 20px;
}
.userinfo div {margin: 20px 10px;
}
/styleprops检验
作用: 为组件的prop指定验证要求, 不符合要求, 控制台会有错误提示语法 类型检验非空检验默认值自定义检验
父组件
templatediv classappBaseProgress :wwidth/BaseProgress/div
/templatescript
import BaseProgress from ./components/BaseProgress.vue
export default {data() {return {width: 23,}},components: {BaseProgress,},
}
/scriptstyle
/style子组件
templatediv classbase-progressdiv classinner :style{ width: w % }span{{ w }}%/span/div/div
/templatescript
export default {// props: [w],// 1.基础写法类型校验// props: {// w: Number // Number String Boolean Array Object// }// 2.完整写法类型、是否必填、默认值、自定义校验props: {w: {type: Number,// required: truedefault: 0,validator (value) {if(value 0 value 100){return true}console.error(传入的prop w, 必须是0-100的数字)return false}}}
}
/scriptstyle scoped
.base-progress {height: 26px;width: 400px;border-radius: 15px;background-color: #272425;border: 3px solid #272425;box-sizing: border-box;margin-bottom: 30px;
}
.inner {position: relative;background: #379bff;border-radius: 15px;height: 25px;box-sizing: border-box;left: -3px;top: -2px;
}
.inner span {position: absolute;right: 0;top: 26px;
}
/styleprops与data的区别
共同点: 都可以给组件提供数据区别: data的数据是自己的 - 随便改prop的数据是外部的 - 不能直接改, 要遵循单向数据流 单向数据流: 父级prop的数据更新, 会向下流动, 影响子组件. 这个数据流动是单向的.
父组件
templatediv classappBaseCount changeCounthandleChange:countcount/BaseCount/div
/templatescript
import BaseCount from ./components/BaseCount.vue
export default {components:{BaseCount},data(){return {count:100}},methods:{handleChange(value){this.count value}}
}
/scriptstyle/style子组件
templatediv classbase-countbutton clickhandleSub-/buttonspan{{ count }}/spanbutton clickhandleAdd/button/div
/templatescript
export default {// 1.自己的数据随便修改 谁的数据 谁负责// data () {// return {// count: 100,// }// },// 2.外部传过来的数据 不能随便修改// 单向数据流: 父组件的prop更新, 会单向向下流动, 影响到子组件.props: {count: Number},methods: {handleAdd(){this.$emit(changeCount, this.count1)},handleSub(){this.$emit(changeCount, this.count-1)}}}
/scriptstyle
.base-count {margin: 20px;
}
/style非父子(扩展)
事件总线 (event bus)
作用: 非父子组件之间, 进行简易消息传递(复杂场景 - vuex)语法: 创建一个都能访问的事件总线(空vue实例) - utils/EventBus.js import Vue from vue
const Bus new Vue()
export default BusA组件(接受方), 监听Bus实例的事件 created() {Bus.$on(sendMsg, (msg) {// console.log(msg)this.msg msg})
}B组件(发送方), 触发Bus实例的事件 Bus.$emit(sendMsg, 今天天气不错适合旅游)provide - inject
作用: 跨层级共享数据语法: 父组件provide提供数据 provide() {return {// 简单类型 是非响应式的color: this.color,// 复杂类型 是响应式的userInfo: this.userInfo,}
}子/孙组件 inject 取值使用 script
export default {inject: [color, userInfo],
}
/script案例 - 小黑记事本(组件版)
核心步骤
拆分基础组件 新建组件 - 拆分存放结构 - 导入注册使用渲染待办任务 提供数据(公共父组件) - 父传子传递list - v-for渲染添加任务 收集数据v-model - 监听事件 - 子传父传递任务 - 父组件unshift删除任务 监听删除id - 子传父传递id - 父组件filter删除底部合计和清空功能 底部合计: 父传子list - 合计展示 清空功能: 监听点击 - 子传父通知父组件 - 父组件清空持久化存储: watch监视数据变化, 持久化到本地
App.vue
template!-- 主体区域 --section idappTodoHeaderVue addhandleAdd/TodoHeaderVueTodoMainVue delhandleDel :listlist/TodoMainVueTodoFooterVue clearhandleClear :listlist/TodoFooterVue/section
/templatescript
import TodoHeaderVue from ./components/TodoHeader.vue
import TodoMainVue from ./components/TodoMain.vue
import TodoFooterVue 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: {TodoHeaderVue,TodoMainVue,TodoFooterVue}
}
/scriptstyle/styleTodoHeader.vue
templatediv!-- 输入框 --header classheaderh1小黑记事本/h1input v-model.trimtodoName keyup.enterhandleAdd placeholder请输入任务 classnew-todo/button clickhandleAdd classadd添加任务/button/header/div
/templatescript
export default {data(){return {todoName: }},methods: {handleAdd(){if(this.todoName.trim() ){alert(任务名称不能为空)return }this.$emit(add, this.todoName)this.todoName }}
}
/scriptstyle
/styleTodoMain.vue
templatediv!-- 列表区域 --section classmainul classtodo-listli classtodo v-for(item, index) in list :keyitem.iddiv classviewspan classindex {{index1}}. /span label {{item.name}} /labelbutton clickhandleDel(item.id) classdestroy/button/div/li/ul/section/div
/templatescript
export default {props: {list: Array},methods: {handleDel(id){this.$emit(del, id)}}
}
/scriptstyle/styleTodoFooter.vue
templatediv!-- 统计和清空 --footer classfooter!-- 统计 --span classtodo-count合 计:strong {{list.length}} /strong/span!-- 清空 --button clickclear classclear-completed清空任务/button/footer/div
/templatescript
export default {props: {list: Array},methods: {clear(){this.$emit(clear)}}
}
/scriptstyle/style进阶语法
v-model详解
v-model原理
原理: v-model本质上是一个语法糖. 例如应用在输入框上, 就是value属性和input事件的合写.作用: 提供数据的双向绑定 数据发生变化, 视图自动变化: value视图发生变化, 数据自动变化: input $event: 用在模板中, 获取事件的形参
div classappinput v-modelmsg1 typetext / br /input :valuemsg2 inputmsg2 $event.target.value typetext
/div表单类组件封装
实现子组件和父组件数据的双向绑定
父传子: 数据 由父组件props传递, v-model拆解绑定数据子传父: 监听输入, 子传父传值给父组件修改
父组件
templatediv classappBaseSelect :selectIdselectId changeselectId $event/BaseSelect/div
/templatescript
import BaseSelect from ./components/BaseSelect.vue
export default {data() {return {selectId: 102,}},components: {BaseSelect,},methods: {}
}
/scriptstyle
/style子组件
templatedivselect :valueselectId changehandleChangeoption value101北京/optionoption value102上海/optionoption value103武汉/optionoption value104广州/optionoption value105深圳/option/select/div
/templatescript
export default {props: {selectId: String},methods: {handleChange(e){this.$emit(change, e.target.value)}}
}
/scriptstyle
/stylev-model简化代码
父组件v-model简化实现子组件和父组件数据双向绑定
子组件: props通过value接收, 事件触发input父组件: v-model绑定数据 (:value input)
父组件
templatediv classappBaseSelect v-modelselectId/BaseSelect/div
/templatescript
import BaseSelect from ./components/BaseSelect.vue
export default {data() {return {selectId: 102,}},components: {BaseSelect,},
}
/scriptstyle
/style子组件
templatedivselect :valuevalue changehandleChangeoption value101北京/optionoption value102上海/optionoption value103武汉/optionoption value104广州/optionoption value105深圳/option/select/div
/templatescript
export default {props: {value: String},methods: {handleChange(e){this.$emit(input, e.target.value)}}
}
/scriptstyle
/stylesync修饰符
作用: 实现子组件与父组件的数据双向绑定, 简化代码特点: prop属性名, 可以自定义, 非固定为value场景: 封装弹框类的基础组件, visible属性 true显示 false隐藏本质: :属性名 update:属性名
父组件
templatediv classappbutton clickisShow true退出按钮/buttonBaseDialog :visible.syncisShow/BaseDialog/div
/templatescript
import BaseDialog from ./components/BaseDialog.vue
export default {data() {return {isShow: false}},methods: {},components: {BaseDialog,},
}
/scriptstyle
/style子组件
templatediv v-showvisible classbase-dialog-wrapdiv classbase-dialogdiv classtitleh3温馨提示/h3button clickclose classclosex/button/divdiv classcontentp你确认要退出本系统么/p/divdiv classfooterbutton确认/buttonbutton取消/button/div/div/div
/templatescript
export default {props: {visible: Boolean},methods: {close(){this.$emit(update:visible, false)}}
}
/scriptstyle scoped
.base-dialog-wrap {width: 300px;height: 200px;box-shadow: 2px 2px 2px 2px #ccc;position: fixed;left: 50%;top: 50%;transform: translate(-50%, -50%);padding: 0 10px;
}
.base-dialog .title {display: flex;justify-content: space-between;align-items: center;border-bottom: 2px solid #000;
}
.base-dialog .content {margin-top: 38px;
}
.base-dialog .title .close {width: 20px;height: 20px;cursor: pointer;line-height: 10px;
}
.footer {display: flex;justify-content: flex-end;margin-top: 26px;
}
.footer button {width: 80px;height: 40px;
}
.footer button:nth-child(1) {margin-right: 10px;cursor: pointer;
}
/styleref和$refs
作用: 通过ref和$refs可以获取dom元素和组件实例使用: 目标组件 - 添加ref属性 div reftest/div通过this.$refs.ref属性值获取目标组件 this.$refs.test获取domdiv refmychart classbase-chart-box子组件/divconst myChart echarts.init(this.$refs.mychart)获取组件 父组件templatediv classappBaseForm refbaseFrom/BaseFormbutton clickhandleGet获取数据/buttonbutton clickhandleReset重置数据/button/div/templatescript
import BaseForm from ./components/BaseForm.vue
export default {components: {BaseForm,},methods: {handleGet(){console.log(this.$refs.baseFrom.getValues())},handleReset(){this.$refs.baseFrom.resetValues()}}
}
/scriptstyle
/style子组件templatediv classappdiv账号: input v-modelusername typetext/divdiv密码: input v-modelpassword typetext/div/div
/templatescript
export default {data() {return {username: admin,password: 123456,}},methods: {getValues() {return {username: this.username,password: this.password}},resetValues() {this.username this.password console.log(重置表单数据成功);},}
}
/scriptstyle scoped
.app {border: 2px solid #ccc;padding: 10px;
}
.app div{margin: 10px 0;
}
.app div button{margin-right: 8px;
}
/style$nextTick
Vue是异步更新DOM的$nextTick: 在DOM更新完成之后做某件事
templatediv classappdiv v-ifisShowEditinput typetext v-modeleditValue refinp /button确认/button/divdiv v-elsespan{{ title }}/spanbutton clickhandleEdit编辑/button/div/div
/templatescript
export default {data() {return {title: 大标题,isShowEdit: false,editValue: ,}},methods: {handleEdit(){// 1. 显示输入框 (异步dom更新)this.isShowEdit true// 2. 让输入框显示焦点// console.log(this.$refs.inp) // undefinedthis.$nextTick((){this.$refs.inp.focus()})}},
}
/scriptstyle
/style来源
黑马程序员. Vue2Vue3基础入门到实战项目