Vue学习四:组件的三大组成部分、组件通信和进阶语法

一、组件的三大组成部分

<template>

里面只能有一个根元素

<style>

全局样式(默认):影响所有组件
局部样式: scoped 下样式,只作用于当前组件

<script>

el根实例独有, data是一个函数,其他配置项一致

二、scoped设置局部样式

默认情况:写在组件中的样式会全局生效→因此很容易造成多个组件之间的样式冲突问题。
1.全局样式:默认组件中的样式会作用到全局
2.局部样式:可以给组件加上scoped属性,可以让样式只作用于当前组件
scoped原理?
1.当前组件内标签都被添加data-v-hash值的属性
2. css选择器都被添加[data-v-hash值]的属性选择器
最终效果:必须是当前组件的元素,才会有这个自定义属性,才会被这个样式作用到

三、data函数

一个组件的data选项必须是一个函数。→保证每个组件实例,维护独立的一份数据对象。
每次创建新的组件实例,都会新执行一次data函数,得到一个新对象。

组件内提供数据的是data函数,每个组件实例都会开辟新的一个空间存储这个数据,组件实例之间互不影响,也就是说data数据作用域只在组件实例范围内。

四、组件通信

组件关系:父子关系使用props&$emit

父传子props:
①父中给子添加属性传值②子props接收③使用
子传父$emit:
①子$emit发送消息②父中给子添加消息监听③父中实现处理函数

案例如下:父组件中有个数据myTitle传给子组件,子组件将数据接受并展示到页面上;子组件上加个按钮,按钮加个点击事件,点了以后会将通知和一个myTitle的新值传给父组件,父组件监听到通知后将myTitle更新。因为使用v-bind动态传递数据,父组件中数据更新,单向数据流,子组件接受的数据也更新并展示。

父组件代码

复制代码
<template>
    <div class="App">
        父组件
        <AlongHeader :title="myTitle" :hobby="hobby" @newTitle="newTitleFn"></AlongHeader>
    </div>
</template>

<script>
    import AlongHeader from './components/AlongHeader.vue'
    export default{
        components:{
            AlongHeader,
        },
        data(){
            return {
                myTitle:'阿龙学前端',
                hobby:['','','rap','篮球']
            }
        },
        methods:{
            newTitleFn(newValue){
                this.myTitle = newValue
            }
        }
    }
</script>

<style>
    .App{
        border: 2px solid black;
        margin: 10px;
    }
</style>
View Code
复制代码

子组件代码

复制代码
<template>
    <div class="AlongHeader">
        子组件 {{title}}
        <button @click="changeTitle"></button>
        <p>{{hobby[0]}}、{{hobby[1]}}、{{hobby[2]}}、{{hobby[3]}}</p>
    </div>
</template><script>
    export default{
        props:['title','hobby'],
        methods:{
            changeTitle(){
                this.$emit('newTitle','好好学习')
            }
        }
    }
</script>

<style scoped>
    .AlongHeader{
        border: 1px solid black;
        margin: 10px;
    }
</style>
View Code
复制代码

prop

Prop定义:组件上注册的一些 自定义属性(结合v-bind成为动态属性)
Prop作用:向子组件传递数据
特点:
●可以传递任意数量的prop
●可以传递任意类型的prop

props校验

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

语法

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

prop & data.单向数据流
共同点:都可以给组件提供数据。
区别:
●data 的数据是自己的→随便改
●prop 的数据是外部的→不能直接改, 要遵循单向数据流
单向数据流:父级prop的数据更新,会向下流动,影响子组件。这个数据流动是单向的。

组件关系非父子-event bus事件总线

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

1.创建一个都能访问到的事件总线(空Vue实例)→utils/EventBus.js
2. A组件(接收方),监听Bus实例的事件
3. B组件(发送方),触发Bus实例的事件

案例代码:A和B为父组件中的两个并列组件,没有父子关系。A组件为发送方,B组件为接受方,要求点击A组件的发送按钮,B组件能接受到“下雨了,快收衣服”这条消息。

创建一个js文件,里面创建一个空的vue实例,然后将实例导出,充当事件总线。

import Vue from 'vue'
const Bus = new Vue()
export default Bus
View Code

A组件中按钮添加点击事件,点击事件中会使用$emit函数向刚创建的vue实例发送消息和发送的数据,这个$emit发送的位置和父子关系不一样(父子关系是this)

复制代码
<template>
    <div class="AlongHeader">
        发送方(A组件)
        <button @click="clickSend">发送消息</button>
    </div>
</template><script>
    import Bus from '../units/EventBus.js'
    export default{
        methods:{
            clickSend(){
                Bus.$emit('Message','下雨了,快收衣服')
            }
        }
    }
</script>

<style scoped>
    .AlongHeader{
        height: 200px;
        width: 200px;
        border: 1px solid black;
        margin: 10px;
    }
</style>
View Code
复制代码

B组件使用created钩子,在创建阶段就开始监听vue,一旦监听到有自己需要的消息就开始执行一系列的操作。

复制代码
<template>
    <div class="AlongMain">
        接收方(B组件)
        <p>{{msg}}</p>
    </div>
</template>

<script>
    import Bus from '../units/EventBus.js'
    export default{
        //监听Bus中的事件,在created数据创建完成的时候就开始监听
        created(){
            Bus.$on('Message',(msg)=>{
                this.msg = msg
            })
        },
        data(){
            return {
                msg:''
            }
        }
    }
</script>

<style>
    .AlongMain{
        height: 200px;
        width: 200px;
        border: 1px solid black;
        margin: 10px;
    }
</style>
View Code
复制代码

四、v-model详解

v-model原理
原理: v-model本质上是一个语法糖。例如应用在输入框上,就是value属性和input事件的合写。
v-model="msg"等价于:value="msg" @input="msg=$event.target.value"
作用:提供数据的双向绑定
①数据变,视图跟着变:value
②视图变,数据跟着变@input
注意: $event 用于在模板中,获取事件的形参

表单类组件封装& v-model简化代码
1.表单类组件封装
①父传子:数据应该是父组件props传递过来的,v-model 拆解绑定数据
②子传父:监听输入,子传父传值给父组件修改

对于父组件中传来的数据,子组件中是不能直接使用v-model关联的,因为数据单向流动,子组件不能直接修改父组件中的数据。

案例如下:父组件向子组件选择框传递一个初始值,子组件中的选择框选择结果也会传递给父组件,然后父组件修改值。当父组件给子组件传递值绑定的动态属性为:value,给动态属性赋值的数据变量名为value,接受消息为@input,子组件传的通知名为input。这样刚好符合了v-model的语法,父组件中可以使用v-model简化代码。但没必要那么可以得去为了v-model而拼凑,只需完成从父组件向子组件传递数据,然后子组件能将视图改变的值传回父组件,然后父组件修改数据,修改好的数据再传到子组件渲染,这样其实就已经完成了父组件数据和子组件视图的双向绑定。

父组件

复制代码
<template>
    <div class="App">
        <AlongHeader :value='value' @input="value=$event"></AlongHeader>
    </div>
</template>

<script>
    import AlongHeader from './components/AlongHeader.vue'
    export default{
        components:{
            AlongHeader,
        },
        data(){
            return {
                value:2
            }
        }
    }
</script>

<style>
    .App{
        height: 500px;
        width: 500px;;
        border: 2px solid black;
        margin: 10px;
    }
</style>
View Code
复制代码

子组件

复制代码
<template>
    <div class="AlongHeader">
        <select :value='value' @change="changeHobby">
            <option value="1"></option>
            <option value="2"></option>
            <option value="3">rap</option>
            <option value="4">篮球</option>
        </select>
    </div>
</template>

<script>
    export default{
        props:['value'],
        methods:{
            changeHobby(e){
                this.$emit('input',e.target.value)
            }
        }
    }
</script>

<style>
    .AlongHeader{
        height: 200px;
        width: 200px;
        border: 1px solid black;
        margin: 10px;
    }
</style>
View Code
复制代码

ref和$refs
作用:利用ref和$refs可以用于获取dom元素,或组件实例
特点:查找范围→当前组件内(更精确稳定)
①获取dom:
1.目标标签-添加ref属性
2.恰当时机,通过this.$refs.xxx,获取目标标签

Vue异步更新、$nextTick

1. Vue是异步更新DOM的
2.想要在DOM更新完成之后做某件事,可以使用$nextTick

案例需求:编辑标题,编辑框自动聚焦1.点击编辑,显示编辑框2.让编辑框,立刻获取焦点。如果单纯地按照上面的步骤来是完成不了的,因为创建dom的速度比获取焦点的速度要慢得多,而vue的dom又是异步的,所以连dom都没有就获取dom焦点肯定是不行的。所以需要将dom完成后要做的事包裹在$nextTick里。

复制代码
<template>
    <div class="App">
        <div v-if="isShow==true">
            <input ref="inp" type="text">
            <button type="button">确认</button>
        </div>
        <div v-else>
            <span>{{title}}</span>
            <button @click="change" type="button">编辑</button>
        </div>
    </div>
</template>

<script>
    export default{
        data(){
            return {
                title:'大标题',
                isShow:false,
            }
        },
        methods:{
            change(){
                this.isShow = true
                this.$nextTick(()=>{
                    this.$refs.inp.focus()
                })
                
            }
        }
    }
</script>

<style>
    .App{
        height: 500px;
        width: 500px;;
        border: 2px solid black;
        margin: 10px;
    }
</style>
View Code
复制代码

 

posted @   数星观月  阅读(267)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示