Vue组件详解

在进入正文之前我们需要先了解

1.什么是组件化开发

组件化开发 指的是:根据 封装 的思想, 把页面上可重用的 UI 结构封装为组件 ,从而方便项目的开发和维护。

2.什么是Vue组件

组件是Vue中的一个重要概念,是一个可以重复使用的Vue实例,它拥有独一无二的组件名称,它可以扩展HTML元素,以组件名称的方式作为自定义的HTML标签。因为组件是可复用的Vue实例,所以它们与new Vue()接收相同的选项,例如data,computed、watch、methods以及生命周期钩子等。仅有的例外是像el这样根实例特有的选项。

template属性是Vue组件中的一个必需属性,它定义了组件的模板,也就是说组件显示在页面中的内容。

关于模板,有几种写法可以选择:

1.字符串模板,将组件的模板直接写成一个字符串

Vue.component('my-component', {
  template: '<div>Hello, {{ name }}!</div>',
  data: function () {
    return {
      name: 'World'
    }
  }
})

2.<template>标签模板:使用<template>标签包裹模板

Vue.component('my-component', {
  template: `
    <template>
      <div class="container">
        <h1>{{ title }}</h1>
        <p>{{ content }}</p>
      </div>
    </template>
  `,
  data: function () {
    return {
      title: 'Welcome to my website',
      content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ac mauris urna.'
    }
  }
})

3.单文件组件:将组件的模板、数据和方法写在一个.vue文件中,例如:

<template>
  <div class="container">
    <h1>{{ title }}</h1>
    <p>{{ content }}</p>
  </div>
</template>

<script>
export default {
  name: 'MyComponent',
  data () {
    return {
      title: 'Welcome to my website',
      content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ac mauris urna.'
    }
  }
}
</script>

组件的组成部分:每个组件有三个部分组成template Script style

template是组件的基本结构 

script 是组件的JavaScript行为

style 是组建的样式

其中每个组件必须包含template部分其余两项为可选

script中的语句必须被包裹在export default{}中

script节点基本结构如下

 让style支持less语法

只需把lang属性设置为less

注意组建的data属性必须是一个函数需要使用函数来返回一个对象(和vue实例不同):这是为了防止vue多个组件的数据相互污染

在Vue中,组件是可以复用的,我们可以在一个应用程序中使用多个相同类型的组件并且他们之间是相互独立的。如果在定义组件时,我们直接在data属性中定义数据对象,则这些数据会被多个使用该组件的实例共享。这就可能导致,修改其中一个实例的数据时,其他实例中的数据也同样发生了修改,造成不必要的问题。为了避免这种情况,我们需要在定义组件时,将data属性定义成一个函数,每个实例都可以调用该函数返回一个全新的数据对象,从而保证组件实例之间的数据互不干扰。

下面是一个简单的示例,展示在组件中使用对象属性变化时的不同:

Vue.component('my-component', {
  template: '<div>{{ count }}</div>',
  data: function () {
    return {
      count: 0
    }
  }
})

new Vue({
  el: '#app',
  data: {
    showComponent: true
  },
  methods: {
    incrementCount: function () {
      this.$children[0].count += 1
    }
  }
})

组件的注册:组建的注册分为全局注册(全局组件)和私有注册(私有组件)

全局组件注册:

全局组件注册在main.js入口文件中用Vue.component() 方法注册

//1.导入需要被全局注册的组件
import my-Count from '@components/Count.vue'
//参数1.组建的注册名称
//参数2.需要被全局注册的组件
Vue.components('My-Count','my-count)

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

//1.导入需要被注册的组件
import count from '@components/count.vue'
//2.通过组件components属性注册私有属性
export default {
components:{
'count',
}

 在组件A中注册的组件F不能被组件B直接使用。

因为组件F在组件A中被注册组件F被定义为组件A的子组件,使用了组件A的注册方式,而组件B没有注册组件F它不知道组件F的存在故不能使用组件F。想要让组件B使用组件F只需要在组件B的components节点下注册组件F即可。需要注意的是,组件F的相关代码和定义仍然在组件A中,组件C只是通过注册和使用该组件来实现在自身中使用组件F。

在这里给大家稍微扩展一下什么是computed属性

computed属性是一种计算属性,它对于Vue组件中的数据,可以定义一个值以及依赖的属性,每当依赖属性发生变化时,computed属性会自动更新其值。这使得开发者可以使用复杂的逻辑,计算派生出一些基于依赖属性的数据。

它的用法如下:

Vue.component('my-component', {
  template: '<div>{{ fullName }}</div>',
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    }
  },
  computed: {
    fullName: function() {
      return this.firstName + ' ' + this.lastName
    }
  }
})

计算属性的一些注意点

1.计算属性是基于一个或多个其他依赖属性计算出来的,因此计算属性也就相应地依赖这些属性。当这些依赖发生改变时,计算属性才会重新进行求值。

2.计算属性应该有一个返回值,用来表示计算结果。不要在计算属性中修改数据对象的值,这会反复触发计算属性,造成性能损失,甚至产生循环依赖的问题。

3.在Vue组件中定义计算属性时,可以使用缓存选项进行优化,将计算结果进行缓存,以避免在依赖未发生改变的情况下重复调用计算属性。缓存的默认行为是基于依赖项的,请注意调整缓存的选项来适应不同情况。

下面给出一个使用computed属性进行缓存的示例,以便更好地说明这些概念。

Vue.component('my-component', {
  template: '<div>{{ reversedMessage }}</div>',
  data() {
    return {
      message: 'Hello Vue.js!'
    }
  },
  computed: {
    reversedMessage: {
      cache: false,
      get: function() {
        console.log('computed')
        return this.message.split('').reverse().join('')
      }
    }
  }
})

在上面的代码中,我们定义了一个属性reversedMessage,来计算message字符串的反转,并且定义了一个缓存选项cache:false,表示计算属性不要缓存计算结果。这样一来,当message发生改变时,每次重新调用reversedMessage都会输出"computed"到控制台,并重新计算该属性的值,以保证它的返回值一定是最新的。

请注意,当我们不需要每次重新计算计算属性的值时,应该将该行为关闭,通过开启缓存选项来提高应用程序的性能表现。开启缓存后,计算结果将被缓存,只有在依赖发生改变时或手动清理缓存时才会重新求值。

组件的props属性

props属性:

props 是组件的 自定义属性 ,在 封装通用组件 的时候,合理地使用 props 可以极大的 提高组件的复用性
它的语法格式如下:
export default {
//组件的自定义属性
props:['自定义属性A','自定义属性B','自定义属性C'],
//组建的私有数据
data:function (){
return
}

}

props属性是指从父组件向子组件传递数据的属性,它可以是任何类型的JavaScript值,包括对象、数组、字符串、布尔值等等。

export default{
props:[{
init:{
//指定父组件向子组件传输数据的类型
type:'',
//指定父组件向子组件传输的默认值
default:'',
//通过require属性将属性设置为必填项,强制用户输入
require:'',
//设置数据的验证规则这种方式可以指定每个props数据的类型以及默认值,以控制子组件的接受数据情况。如果传递进来的数据类型不为指定类型且不为null或undefined,则会在控制台中输出警告。
validator:vaule.length<100
}]
}

关于props属性有几个注意点需要注意

  1. props中定义的数据是单向数据流,只能由父组件向子组件传递,子组件无法直接修改props中的数据。

  2. props是不可变的,子组件中不能对它们进行修改,否则会在控制台中输出错误提示

  3. 如果传递给子组件的props数据类型和需求不同,可以在子组件中定义一个新的data属性,并使用props中的数据进行初始化和计算

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

导致组件之间样式冲突的根本原因是:
① 单页面应用程序中,所有组件的 DOM 结构,都是基于 唯一的 index.html 页面 进行呈现的
② 每个组件中的样式,都会 影响整个 index.html 页面 中的 DOM 元素
解决组件冲突的方法有以下三种
1.CSS命名空间
给每个组件添加一个唯一的className或者ID(命名空间),用以区分不同的组件。例如:
<template>
  <div class="my-component__container">
    ...
  </div>
</template>

<style scoped>
.my-component__container {
  /* 组件样式 */
}
</style>

2.作用域样式

给组建的style添加scope属性这样就限制改样式只适用于当前组件

<template>
  <div class="my-component">
    ...
  </div>
</template>

<style scoped>
.my-component {
  /* 组件样式 */
}
</style>

3.CSS modules

CSS Modules是一种CSS方案,可以避免全局CSS样式冲突问题,同时也提供更好的组件化。使用CSS Modules,组件的样式通过局部作用域的方式实现,可以防止命名冲突并且只作用于当前组件,不会污染全局作用域。

<template>
  <div :class="$style.container">
    ...
  </div>
</template>

<style module>
.container {
  /* 组件样式 */
}
</style>

上面的代码中,使用了:class="$style.container"这样的语法来实现组件样式的局部作用域和引用

导致组件之间样式冲突的根本原因是:

即每个组件中的样式,都会影响整个index.html页面中的DOM元素。

在Vue单页面应用程序中,所有组件的DOM结构都是基于index.html页面进行呈现的。由于样式规则依赖于选择器的DOM结构,因此如果两个组件使用相同的CSS类或ID,那么它们将会分享相同的样式规则,并可能导致样式冲突。

当多个组件共享相同的CSS类或ID时,它们的样式规则将会合并,从而产生一些不可预期的结果。这种情况下的样式冲突通常表现为某个组件的样式并没有按照期望的方式进行呈现,而是被一些其他的不相关的样式覆盖了。

如果给当前组件的 style 节点添加了 scoped 属性,则 当前组件的样式对其子组件是不生效的 。如果想让某些样
式对子组件生效,可以使用 /deep/ 操作符
<style lang=less scope>
.title{
color:blue //不加deep属性生成的选择器格式为.title[data]
}
/deep/ .title{
color:blue //加上deep属性生成的选择器为[data] .title
}
}

(不过 /deep/ 已被废弃,深度作用选择器是它的替代选择)

使用深度作用选择器,只需要在有作用域的样式中嵌套 >>> 操作符即可。例如:

<template>
<parent class="parent">
<chlid class="child>
</child>
</parent>
<style lang=less scoped>
.parent >>> .child{
color:blue//父组件样式
}

注意,深度选择器不能太过深,因为父子组件之间的关系是不确定的,因此使用太深的选择器可能会导致样式不可预测。

另外,如果你使用了 CSS Modules,则可以通过给子组件添加相同的模块名称,来让子组件也继承父组件的作用域样式。具体用法可以查阅相关文档。

Vue组件的实例

在 Vue 应用程序中,组件是构成 UI 界面的基本单元,每个组件都拥有自己的状态与行为。组件实例是 Vue 最基本的构建块之一,我们可以通过组件实例来访问和操作组件的数据与方法。

Vue 会为每个组件创建一个组件实例,在实例化过程中会执行以下步骤:

  1. 初始化数据。Vue 会从组件定义中读取 data 对象,将其与依赖的组件绑定,并为每一个属性设置响应式更新(即当数据发生变化时,对视图进行自动更新)。

  2. 编译模板。Vue 使用模板编译器将 template 编译成渲染函数,并为每个组件实例生成一个虚拟 DOM 树。

  3. 挂载组件。Vue 将组件实例的虚拟 DOM 树挂载到页面上。此时,组件实例可以被访问和操作。

组件实例是一个独立的对象,每个组件实例都有独立的作用域和状态。组件实例中的状态和行为都可以通过组件访问到。例如,在组件实例中,你可以访问到组件的属性、方法和生命周期钩子等。

组件实例还可以通过父子组件之间的通信来进行交互。在 Vue 中,父组件可以通过 props 向子组件传递数据和事件,并通过子组件实例上的 $emit 方法向自身的父组件触发事件。

总之,Vue 组件实例是一个非常重要的概念,在 Vue 应用程序中扮演着至关重要的角色,了解组件实例的生命周期和使用方法,可以更好地构建和管理 Vue 应用程序。

注意:你可以把Vue组件实例理解为构造函数,用的时候才会创建一个组件实例

Vue组建的生命周期

组件的生命周期是指组件从实例化->运行->销毁的过程,自动调用一系列的钩子函数,在不同的阶段,这些钩子函数帮助我们在不同的阶段实现不同的业务逻辑。

创建实例时期的钩子函数:在组件实例化和挂载到DOM时使用

运行时期钩子函数:在组件被激活时使用

组建的创建阶段包含:beforeCreate、created、beforeMount 和 mounted 四个钩子函数

更新阶段:包括 beforeUpdate 和 updated 两个钩子函数。

销毁阶段:包括 beforeDestroy 和 destroyed 两个钩子函数。

beforeCreate:这个生命周期钩子在 Vue 实例被创建之初被调用,可以在此时进行一些初始化的工作,例如向组件实例中注入一些插件、初始化数据等。注意:在 beforeCreate 阶段,组件的数据、方法、计算属性等都还没有被初始化。

created:这个生命周期钩子在 Vue 实例创建完成之后被调用,此时组建实例已经完成了数据的初始化,可以进行一些更加复杂的数据处理和异步请求等操作。

beforeMount:这个生命周期钩子在组件即将被挂载到页面上之前被调用,此时组件的 template 被编译成渲染函数,但是还没有被调用渲染,可以在此时进行一些 DOM 相关的操作。

Mounted:这个生命周期钩子在组件被首次挂载到页面上后被调用,此时组件已经完成了 DOM 的渲染,可以进行一些依赖于 DOM 的操作,比如使用 jQuery 相关的操作、操作地图组件等。(已经加载完成)。

beforeUpdate:这个生命周期钩子在组件更新之前被调用,此时组件已经重新渲染,并且数据已经被更新,但是尚未应用到页面上,可以在此时进行一些更新前的准备工作。

updated:这个生命周期钩子在组件更新完成后被调用,此时组件已经呈现在页面上了,可以进行一些依赖于 DOM 元素的操作,比如使用 this.$refs 方法获取组件中的 DOM 元素,更新动画效果等。

activated(keep-alive 独有):这个生命周期钩子在组件被激活时被调用(包括被缓存的组件)。

deactivated(keep-alive 独有):这个生命周期钩子在组件被停用时被调用(包括被缓存的组件)

beforeDestroy:这个生命周期钩子在组件被销毁之前被调用,此时组件实例仍然存在,可以进行一些资源清理的操作,比如取消定时器、取消订阅事件等。

destroyed:在组件被销毁后调用此时组件实例已经被完全销毁,并且不能再通过组件实例进行访问。

当我们在 Vue 中频繁地创建和销毁组件时,就会导致我们的应用程序性能下降,在这种情况下,可以使用 keep-alive 将组件缓存起来,以减少组件频繁创建和销毁的开销,提高应用程序的性能。

keep-alive 是 Vue 内置的一个组件,它的作用是将其包含的组件缓存起来,设置它的 include 属性可以指定哪些组件需要被缓存,设置 exclude 属性可以指定哪些组件不需要被缓存。

keep-alive 组件包裹起来的子组件有两种状态:

激活状态:当组件被激活时,它会从缓存中恢复,调用 activated 钩子函数;

停用状态:当组件被停用时,它会被缓存起来,不再渲染,调用 deactivated 钩子函数。

下面是一个使用 keep-alive 的例子

<template>
  <keep-alive>
    <router-view></router-view>
  </keep-alive>
</template>

在这个例子中,我们将 keep-alive 包含在 Vue Router 的 router-view 中,这样,路由切换时,keep-alive 就会缓存起来当前的路由组件,而不是销毁它,下次再访问该路由时,就会从缓存中恢复该路由组件。

需要注意的是,使用 keep-alive 得到的性能提升是有限的,如果组件的内存占用过大,还是需要手动销毁组件,释放内存。另外,由于 keep-alive 的组件会保留状态,所以在使用时需要确定好对应的生命周期函数。

组件的数据共享

父子之间的数据共享(父->子,子->父)

兄弟之间数据共享

父组件向子组件共享数据需要用到自定义属性示例代码如下

//父组件
<template>
<div>
<son :user="user"></son>
</div>
</template>
<script>
import son from '@/components/son.vue'
export default{
data(){
return{
user:'张三'
}
},
components:{
son
}
}
//子组件
<template>
<div>

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue 3 提供了多种组件通信的方法,包括 Props、事件、Provide/Inject、$attrs/$listeners、Ref、Custom Events 等。下面我会逐一详细介绍这些方法。 1. Props:通过向子组件传递属性值来实现父子组件之间的通信。父组件可以通过 props 属性将数据传递给子组件,并在子组件中使用。子组件通过 props 接收父组件传递的数据,并进行相应的处理。 2. 事件:父组件可以通过自定义事件的方式向子组件传递数据。子组件通过 $emit 方法触发事件,并将数据作为参数传递给父组件。父组件通过在子组件上监听自定义事件,并在事件处理函数中接收子组件传递的数据。 3. Provide/Inject:父组件可以通过 provide 方法提供数据,然后在子组件中通过 inject 方法注入数据。这种方式可以实现跨层级的组件通信,但是不推荐在大型项目中过度使用。 4. $attrs/$listeners:$attrs 用于获取父组件传递给子组件的非 prop 属性,$listeners 用于获取父组件传递给子组件的事件。这两个属性可以使得子组件可以接收父组件的所有属性和事件,从而简化了父子组件之间的通信。 5. Ref:Ref 是一个特殊的对象,可以被用于在组件之间共享可变的状态。通过 ref 函数创建一个 ref 对象,并将其传递给子组件。子组件可以通过 .value 来访问和修改 ref 对象的值。 6. Custom Events:在 Vue 3 中,自定义事件可以通过创建一个新的事件实例,并使用 $on 和 $emit 方法进行监听和触发。这种方法可以实现更灵活的组件通信方式。 以上就是一些 Vue 3 中常用的组件通信方法。根据具体的场景和需求,选择合适的方法来实现组件之间的通信。希望能对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值