vue 的组件

本文详细介绍了Vue.js中的组件系统,包括组件的全局与局部注册、data属性的使用、父子及非父子组件间的通信方式,如props、$emit与$on。此外,还深入探讨了组件的事件监听器watch及其与计算属性的区别,以及插槽的概念、分类和用法,如默认插槽、具名插槽和作用域插槽。最后,简要提及了动态组件和生命周期钩子函数的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

vue 的组件

  1. 组件是可复用的 Vue 实例,且带有一个名字:

  2. 因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。

  3. 组件模板必须只能存在一个根元素

组件的注册

全局注册

Vue.component('自定义的组件名', 组件的配置项)
// 组件的配置项 : template, data, methods, computed , filter .... 等属性

Vue.component('自定义的组件名', {
    template:``
})

组件名

  1. 连字符:都使用小写字母形式: 因为 html对大小写不敏感,会自动转换为小写形式
  2. 驼峰命名:当使用时,如果在HTML中转换为连字符形式, 如果在模板字符串中或者单文件组件中则不受限制

组件中的data属性

组件中的data必须是一个函数; 每个实例可以维护一份被返回对象的独立的拷贝;实例的data属性就都是独立的,不会相互影响 ;也是为了和 vue 实例中的data 进行区分

局部注册

在组件内部使用 components 属性进行局部注册; 以后推荐使用局部注册

new Vue({
  el: '#app',
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})

组件的传值方式

  1. 父子传值(通信)
  2. 子父传值(通信)
  3. 非父子传值(通信)

组件的关系

  1. 父子关系
  2. 非父子关系

组件父子通信

通过 prop属性实现

  1. 传递一个静态的数据:
    在组件标签上自定义一个属性,并赋值
<组件标签名 自定义属性='value'></组件标签名>

在子组件的内部,通过 props 选项进行接受 props:['自定义属性名']; 接受后可以在组件内部使用, 使用的方式和data中的数据一样

Vue.component('自定义的组件名', {
    template:`<div>接受后可以在组件内部使用, 使用的方式和data中的数据一样</div>`
    props:['组件标签上自定义属性名']
})
  1. 传递一个动态的数据: 父子通信
    需要在组件标签上绑定自定义属性,自定属性的值是父组件中的data中的key数据
<组件标签名 v-bind:自定义属性='父组件中data中的key'></组件标签名>

在子组件的内部,通过 props 选项进行接受 props:['自定义属性名']; 接受后可以在组件内部使用, 使用的方式和data中的数据一样

Vue.component('自定义的组件名', {
    template:`<div>接受后可以在组件内部使用, 使用的方式和data中的数据一样</div>`
    props:['组件标签上自定义属性名']
})

组件子父通信

$on() 和 $emit()

子父通信需要通过事件进行传递, 通过 e m i t ( ) 和 emit() 和 emit()on() 实现; $emit()触发一个自定义事件, o n ( ) 监 听 自 定 义 事 件 ∗ ∗ on()监听自定义事件 ** on()on() 和 $emit() 必须属于同一个对象,才能进行监听; $on()通常在created中进行监听**

$emit()用法
//  单纯触发一个自定义事件
vm.$emit('自定义事件名')
//  可以接受第二个参数, 传递数据
vm.$emit('自定义事件名', data)
$on()用法
vm.$on('监听自定义事件', (data) => {
    // 回调函数的参数data就是传递的数据
})
子父通信
  1. 触发事件:在子组件内部定义一个原生事件,通过该原生事件触发一个自定义事件
// 在方法中通过this.$emit() 触发
Vue.component('自定义的组件名', {
    template:`
        <div>
            <button @click='send'>按钮</button>
        </div>
    `,
    methods:{
        send(){
            this.$emit('自定义事件名', data)
        }
    }
})

// 在字符串模板中 直接 通过 $emit()触发
Vue.component('自定义的组件名', {
    template:`
        <div>
            <button @click="$emit('自定义事件名', data)">按钮</button>
        </div>
    `,
})
  1. 监听事件: 在组件标签上 通过 v-on监听自定义事件 v-on:自定义事件名='父组件中的methods中的方法'
    父组件中必须存在对应的方法
// 通过绑定父组件中的方法名
<组件标签名 v-on:自定义事件名='父组件中methods中的方法'></组件标签名>

// 直接在组件标签上进行事件处理  通过 $event 事件对象获取数据
<child v-on:changefontsize='fontSize += $event'></child>
  1. 完整的代码
<div id="app">
    <p :style="{fontSize:fontSize + 'px'}">hello world</p>

    <!-- <child v-on:changefontsize='fontSize += $event'></child> -->
    <child v-on:changefontsize='changeFont'></child>
</div>
<script src="./js/vue.js"></script>
<script>
    Vue.component('child', {
        template:`
            <div>
                <button @click='$emit("changefontsize", 1)'>方法字体 实现方式1</button>
                <button @click='changeFont'>方法字体 实现方式2</button>
            </div>
        `,
        methods:{
            changeFont(){
                // 实现方式2
                this.$emit("changefontsize", 1)
            }
        }
    })    
    const app = new Vue({
        el:'#app',
        data:{
            fontSize:20
        },
        methods:{
            changeFont(data){
                this.fontSize += data;
            }
        }
    })
</script>

vue的插槽

插槽概念

vue提供了一套内容分发机制的API,将 元素作为承载分发内容的出口。 就是插槽

插槽的分类

  1. 默认插槽
  2. 具名插槽
  3. 作用域插槽

默认插槽

<slot>标签用于组件模板内

  1. 定义一个默认插槽
const child = {
    template:`
        <div>
            <slot></slot>
        </div>
    `
}
  1. 内容分发 : 在组件标签内使用
<组件标签> 
    <template>
        分发的内容
    </template>
</组件标签>

具名插槽

<slot> 标签添加一个name属性, 自定义插槽的名字,<slot name='自定义插槽名'></slot>

  1. 定义具名插槽
const child = {
    template:`
        <div>
            <slot></slot>
            <slot name='自定义插槽名'></slot>
        </div>
    `
}
  1. 使用具名插槽
    必须结合 v-slot 指令 绑定插槽, v-slot指令只能用于 template 标签上(vue内置的标签)
<组件标签> 
    <template v-slot:自定义插槽名>
        分发的内容  具名插槽
    </template>

     <template v-slot:default>
        分发的内容 默认插槽
    </template>
</组件标签>

作用域插槽

本质是用来传递数据

  1. 定义一个作用域插槽
// value 就是传递的数据
const child = {
    template:`
        <div>
            <slot 自定义属性名1='value1' 自定义属性名2='value2'></slot>
            <slot name='自定义插槽名' 自定义属性名1='value1' 自定义属性名2='value2'></slot>
        </div>
    `
}
  1. 使用作用域插槽: 接受数据
    接受数据 通过 带表达式的v-slot 指令进行接受, v-slot='自定义名字', 可以用任何你喜欢的名字进行接受, 接受的结果是一个对象集合, 包含了所有的数据
<组件标签> 
    <template v-slot='自定义名字'>
        分发的内容  默认插槽
    </template>

     <template v-slot:自定义插槽名='自定义名字'>
        分发的内容 具名插槽    自定义属性名 对应的是slot标签上的自定义属性名
        {{通过自定义名.自定义属性名}}
    </template>
</组件标签>

插槽的默认值

定义插槽是可以给插槽提供默认值(后备内容); 如果没有提供具体的值,会显示默认值, 如果提供了具体的值,则会替换默认值

const child = {
    template:`
        <div>
            <slot>默认值</slot>
            <slot name='自定义插槽名'></slot>
        </div>
    `
}

v-slot指令的简写

v-slot:自定义插槽名 可以进行简写, v-slot: 整体简写 为 # , #自定义插槽名

组件标签和HTML标签的区别

  1. 标签上属性的区别
    • 组件标签上添加属性(自定义属性)意味着是数据传递,需要在组件模板内 通过 prop 接受
    • html标签上添加属性 就是标签的属性
  2. 绑定事件的区别
    • HTML标签上绑定的事件是原生事件
    • 组件标签上绑定的事件都是自定义事件,需要通过 this.$emit() 进行触发
  3. 标签内添加内容
    • html标签内添加内容就是标签的内容
    • 组件标签内添加内容,如果没有<slot></slot>标签存在,则会被忽略,如果<slot></slot>标签存在,则是进行内容分发

生命周期钩子函数

  1. beforeCreate() : 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
  2. created() : 在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el property 目前尚不可用。
  3. beforeMount() : 在挂载开始之前被调用:相关的 render 函数首次被调用
  4. mounted() :实例被挂载后调用,这时 el 被新创建的 vm. e l 替 换 了 。 如 果 根 实 例 挂 载 到 了 一 个 文 档 内 的 元 素 上 , 当 m o u n t e d 被 调 用 时 v m . el 替换了。如果根实例挂载到了一个文档内的元素上,当 mounted 被调用时 vm. elmountedvm.el 也在文档内。
  5. beforeUpdate() : 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器
  6. updated() :由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
  7. beforeDestroy() : 实例销毁之前调用。在这一步,实例仍然完全可用。
  8. destroyed() :实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。

动态组件

生命周期: 结合 kepp-alive 组件使用:

  1. activated : 被 keep-alive 缓存的组件激活时调用。
  2. deactivated : 被 keep-alive 缓存的组件停用时调用。

动态组件 : component 内置标签 结合 is 属性 实现动态组件

// 绑定静态的组件
<component is='组件名'></component>

//  绑定动态组件
<component v-bind:is='data中的key'></component>

//  针对于动态组件,可以结合 kepp-alive 实现组件的缓存
<keep-alive>
    <component v-bind:is='data中的key'></component>
</keep-alive>

vue的侦听器

vue的侦听器是由watch·属性来实现的

侦听器:侦听的是vue实例中的data中的key

<div id="app">
         <!-- <p>{{slice}}</p> -->
         <p>{{msg}}</p>
         <p>{{count}}</p>
     </div>
  • 当监听到msg当中的数据发生改变时,监听器做出响应
 <script src="./js/vue.js"></script>
     <script>
         const app = new Vue({
             el:"#app",
             data:{
                 msg:'hello vue',
             },
         wantch:{
             // msg接收两个参数:  第一个参数新值(改变后的值), 第二个参数是旧值(改变之前的值),
			msg(newvalue,oldvalue){
			//  监听到对应的数据发生改变,则做出响应的处理
				this.msg="hello word"
				
				}		
			}
         

侦听器的配置项

 <div id="app">
        <p>{{msg}}</p>
        <p>{{school}}</p>
    </div>
    <script src="./js/vue.js"></script>
<script src="./js/vue.js"></script>
    <script>
        const app = new Vue({
            el:"#app",
            data:{
                msg:'hello vue',
                school:{
                    name:'学校',
                    classRoom:{
                        name:'教室1'
                    }
                }
            },
	 

watch:{
                // 1、 propA:(val,old){} 正常监听: 值发生改变则去监听
                msg(newValue, old){
                     this.msg = 'hello world 你好'
                 }//2、propB:"函数名" 函数名对应methods中的方法  把事件处理程序单独独立出来, 存放到methods方法中,在去使用的时候直接用函数名,但是必须添加引号
               msg:"changeMsg",
             //3、propC:{
                    // 通过watch 的options hanlder属性处理逻辑 ; 类似于前两种写法
                    //  handler:function(val, old){}
                }
              msg:{
                     // handler 属性: 就是事件处理程序 , 是一个回调函数: 当数据发生改变时会自动调用执行该回调
                   handler:function(newValue, oldValue){
                         this.msg = 'hello world 你好'
                    }
              //4、立即执行  
              // propD:{
             //    handler:function(val, old){},
             //    immediate: true 
             //}
			msg:{
                handler:function(newValue, oldValue){
                         this.msg = 'hello world 你好'
						  immediate: true 
                    }
           },

			 // 5、响应 针对于对象的响应(对象嵌套多层) {school: '学校', classRoom:{name:'教室1'}}
                // 该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
             //   propE:{
             //       handler:function(val, old){},
             //       deep:true
             //   },
					
				  msg:{
                   handler:function(newValue, oldValue){
                         this.msg = 'hello world 你好'
                         // 该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
                          deep:true 
                    }	


					
					
                 // 6、接收多个事件处理程序
                propF:[
                    'handler1',
                    function fun(){}
                ]
			

     methods:{
                changeMag(val, old){
                	  console.log(val, old);
                	 
                }
    		
    		}

 }

侦听器与计算属性的区别

计算属性:

1.使用场景:当页面中有某些数据依赖其他数据进行变动的时候,可以使用计算属性
计算属性 computed 是基于data中数据进行处理的,data数据变化,他也跟着变化 ; 、
当data中数据没有发生改变时,我们调用computed中函数n次,只会进行缓存(执行一次);

2.用法: 计算属性在调用时需要在模板中渲染,修改计算所依赖元数据

侦听器:

1.使用场景:数据变化时执行异步或开销较大的操作,可以随时修改状态的变化
通过监听data中的数据 进行处理,data数据变化,则执行handler处理程序,对data中的元数据进行处理

2.用法:watch在调用时只需修改元数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值