【Vue学习笔记】三、vue组件与生命周期

本文详细介绍了Vue组件的创建、父子关系、使用步骤、全局注册、props属性、样式冲突解决方案、组件实例对象、生命周期函数及其分类、数据共享方法以及ref引用操作。重点讨论了props的使用,包括创建、结合v-bind使用、props的只读性、默认值、类型限制以及必填项。此外,还阐述了如何处理组件间的样式冲突和数据交互,以及在不同生命周期阶段使用this.$nextTick的场景。

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

三、vue组件与生命周期

1)vue组件

vue中规定:组件的后缀名是.vueApp.vue本质上就是一个组件

每个.vue组件都由3部分组成:

  • template -> 组件的模板结构
  • script -> 组件的JavaScript行为
  • style -> 组件的样式

注意<script>中必须要写一个默认导出export default{},这是固定写法

.vue中的data不能像之前一样指向对象,组件中的data必须是一个函数

<template>
	<div>
        <h3>这是用户自定义的Test.vue ---- {{ username }}</h3>
    </div>
</template>

<script>
//默认导出,这是固定写法
    export default{
        //data数据源,不能指向对象
       // data:{
       //     username: 'zs'
       // }
        //必须定义为一个函数
        data(){
            //这个return出去的{}中可以定义数据
            return{
                username:'admin'
            }
        }
    }

</script>

<style>
    .test-box{
        background-color: pink;
    }
</style>

methods、watch、computed等写法与之前一致

<script> 
export default{
        data(){
            return{
                username:'admin'
            }
        },
        methods:{
            changeName(){
                this.username = '哇哈哈'
            }
        }
    }
</script> 
2)组件之间的父子关系

image-20220320192015800

3)使用组件的三个步骤
  1. 使用Import语法导入需要的组件
  2. 使用components节点注册组件
  3. 以标签的形式使用刚才注册的组件

image-20220320192416656

通过components注册的是私有子组件

例如:

在组件A的components节点下,注册了组件F,则F只能在组件A中使用

4)注册全局组件

在vue项目的main.js入口文件中,通过Vue.component()方法,可以注册全局组件

//导入需要全局注册的组件
import Count from '@/components/Count.vue'

//参数1:字符串格式,表示组件的“注册名称”
//参数2:需要被全局注册的那个组件
Vue.component('MyCount',Count)
5)组件的props
1.创建props自定义属性

props是组件的自定义属性,在封装通用组件的时候,合理地使用props可以极大的提高组件的复用性

<script>
export default{
    props:['init'],
}
</script>

在使用的注册好的组件标签时以标签属性的形式传参

<MyCount init="9"></MyCount>
2.结合v-bind使用自定义属性

加上:之后就加上了v-bind,此时""里包裹的变成了js语句,单个的9就变成了Number类型

<MyCount :init="9"></MyCount>
3.props是只读的

vue规定:组件中封装的自定义属性是只读的,程序员不能直接修改props的值,否则会直接报错

image-20220320200807892

4.转接props值

如果想要修改props中属性的值,应该让data中的属性来转接这个值

init赋值给count,直接让count: this.init即可

<script>
export default{
    props:['init'],
    data(){
        return{
            count: this.init
        }
    }
}
</script>
5.props的默认值

在声明自定义属性时,可以通过default来定义属性的默认值

<script>
export default{
    props:{
        init:{
            //用default属性定义属性的默认值
            default: 0
        }
    }
}
</script>
6.props的type属性

在声明自定义属性时,可以通过type来定义属性的值类型

<script>
export default{
    props:{
        init:{
            default: 0,
            //init值的类型必须是Number数字
            type: Number
        }
    }
}
</script>
7.props的required必填项

required属性为true表示该props属性为必填项,如果不传就会报错

<script>
export default{
    props:{
        init:{
            default: 0,
            type: Number,
            //必填项校验
            required: true,
        }
    }
}
</script>
6)组件之间的样式冲突问题
1.冲突的原因

默认情况下,写在.vue中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题

样式冲突的根本原因:

  1. 单页面程序中,所有组件的DOM结构,都是基于唯一的index.html页面进行呈现的
  2. 每个组件中的样式,都会影响整个index.html页面中的DOM元素
2.冲突的解决方法

<style>标签中加上scoped属性即可解决

<style lang="less" scoped>
    .test-box{
        background-color: pink;
    }
</style>

原理是在组件中的每个标签里加上一个不同的自定义属性data-v-xxx,通过自定义属性选择器[data-v-xxx]选择到这个属性

3.使用deep修改子组件中的样式
<style lang="less" scoped>
    .test-box{
        background-color: pink;
    }
    /deep/ h5{
        color: pink;
    }
</style>

这样操作会把h5[data-v-xxx]变为[data-v-xxx] h5,变成了一个后代选择器

当使用第三方组件库的时候,如果有修改组件默认样式的需求,需要用到/deep/(因为不能直接修改组件库的源码)

7)vue组件的实例对象

创建点.vue组件相当于创建了一个构造函数,在以标签的形式使用的时候就相当于new了一个组件实例,每一个组件就相当于一个Vue实例

8)生命周期
1.生命周期&生命周期函数

生命周期(Life Cycle)是指一个组件从创建 -> 运行 -> 销毁的整个阶段,强调的是一个时间段

生命周期函数:是由vue框架提供的内置函数,会伴随组件的生命周期,自动按次序执行

生命周期函数与props/data/methods等同级,以函数的形式创建

<script>
	export default{
        data:{
        },
        beforeCreated(){ //创建了beforeCreated生命周期函数
		
        }
    }
</script>
2.组件生命周期函数的分类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DUz4AJIe-1647945088148)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220321145908355.png)]

按照这个顺序依次执行函数其中create代表创建,mount代表渲染到页面上,update代表组件更新,Destroy代表销毁

Vue 实例生命周期
3.beforeCreate和created的特点
image-20220321150857622

beforeCreate阶段,组件的props/data/methods都处于不可用的状态,这个生命周期不重要

created阶段,组件的props/data/methods已创建好可以使用,但是模板结构尚未生成

注意:在created阶段,可以使用Ajax请求数据来初始化参数,非常常用!

4.beforeMount和mounted
image-20220321152520477

beforeMount之前,先寻找要要生成结构的区域(’#app’),然后根据数据和模板在这个区域中生成html结构,这个阶段同样可以发起Ajax请求,但是在created阶段发起更好,所以这个阶段也不重要

image-20220321152923600

如果要操作当前实例的DOM,最早可以在mounted阶段操作

5.beforeUpdate和updated
image-20220321153230031

在数据发生变化之后会执行beforeUpdate阶段,然后再将更新的数据渲染到组件的DOM结构里,这个阶段会在页面刚打开的时候触发一次

更新数据渲染完毕后触发updated

当数据发生变化之后,为了能够操作到最新的DOM结构,代码必须写在created阶段

6.beforeDestroy和destroyed

这两个阶段不常用

使用v-if可以实现组件的销毁

image-20220321153908600
9)组件之间的数据共享
1.组件之间的关系

在项目开发中,组件之间最常见的关系分为如下两种:

  • 父子关系
  • 兄弟关系

如果两个组件离得比较远,则当作兄弟关系处理(即使是后代)

2.父组件向子组件传递数据

使用自定义属性

//父组件
<Son :msg="message" :user="userinfo"></Son>
<script>
data(){
	return{
	message: 'hello vue.js',
	userinfo: { name: 'zs', age: 20}
	}
}
</script>
//父组件
<template>
	<div>
        <h5>Son组件</h5>
        <p>父组件传递过来的msg指是:{{ msg }}</p>
        <p>父组件传递过来的user指是:{{ user }}</p>
    </div>
</template>

<script>
props: ['msg', 'user']
</script>

传递复杂对象是传递一个引用,使用user.name可以直接修改到父组件中的user.name,一般不要这么操作,而应该去设定一个新变量来接收

3.子组件向父组件传递数据
  1. 先定义一个变量来接收子组件传递过来的值
  2. 子组件向父组件共享数据使用自定义事件

$emit(事件,参数)代表触发一个事件,父组件中按照触发事件同样的方法去接收这个

//子组件

<script>
export default {
    data(){ return{count: 0}},
    methods: {
        add(){
            this.count++;
            //修改数据时,通过$emit()触发自定义事件
            this.$emit('numchange',this.count);
        },
    },
}
</script>
//父组件
<Son @numchange="getNewCount"></Son>

<script>
export default {
    data(){ return{countFromSon: 0}},
    methods: {
        getNewCount(val){
            this.countFromSon = val
        },
    },
}
</script>
4.兄弟组件之间的数据共享

在vue2.x中,兄弟组件之间数据共享的方案是EventBus

image-20220321162602991

  • 创建eventBus.js模块,并向外共享一个Vue的实例对象
  • 在数据发送方,调用bus.$emit('事件名称', 要发送的数据)来发送数据
  • 在数据接收方,调用bus.$on('事件名称', 事件处理函数)来接收数据

接收方写在created阶段中,是一个固定写法

10)ref引用
1.ref操作DOM
  • 在需要操作的标签上命名一个属性ref="xxx"
  • 通过this.$refs.xxx来操作DOM
<div>
    <h1 ref="myh1">一个标签</h1>
</div>

<script>
	export default{
        methods:{
            showThis(){
                this.$refs.myh1.style.color = "red"
            }
        }
    }
</script>
2.ref操作组件

ref除了可以操作DOM,也可以用来操作组件

<template>
	<div>
        <Left ref="comLeft"></Left> //给子组件绑定了ref名称
    </div>
</template>

<script>
	methods:{
        onReset(){
            this.$refs.comLeft.resetCount() //可以用refs来调用Left组件里的resetCount()方法
            this.$refs.comLeft.count = 0 //也可以直接操作值
        }
    }
</script>
3.this.$nextTick

如果想把代码的执行延后到页面重新渲染完毕之后,需要用到this.$nextTick(callback)方法

<script>
	methods:{
        showInput(){
            this.inputVisible = true
            //此时把布尔值改变了,但是因为生命周期,页面还没有来得及渲染,下面的语句找不到这个文本框
            console.log(this.$refs.iptRef)
            //使用$nextTick方法执行就不会报错
            this.$nextTick(() => {
                console.log(this.$refs.iptRef)
            })
        }
    }
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值