Vue 组件

2755 字
14 分钟
Vue 组件

组件的定义#

组件的出现是为了拆分 Vue 实例的代码量,能够让我们以不同的组件来划分不同的功能模板,将来需要什么样的功能,只需要调用对应的组件就可以了

组件化与模块化的区别

  • 模块化是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一
  • 组件化是从 UI 界面的角度进行划分的,前端的组件化是为了方便 UI 组件的重用

组件基本使用#

组件的注意事项:

  • **每个组件必须只有一个根元素,**可以将模板的内容包裹在一个父元素内来解决这个问题
  • 组件中可以有自己的 data 数据,使用方式同 Vue 实例中一样,但是组件的 data 只能是一个方法,而且必须要返回一个包含了数据的对象,因为需要每个组件之间相互独立,如果不是一个函数,那么每个组件就会影响其他的组件 如果要想同时影响其他数据,可以创建一个外部的镀锡,每次 data 返回这个对象

组件名#

在创建一个组件时,我们始终需要给该组件一个名字用作标识,组件名的有多种写法

  • 短横线命名法,使用短横线命名法来命名组件在使用的时候也是直接将引用的组件名作为标签名来使用

  • **驼峰命名法,**使用驼峰命名法命名的组件在引用这个组件时可以通过两种命名的方式来引用

    **注意:**当用作标签时只能使用短横线命名法,所以最好都使用短横线命名法来命名

创建组件#

  • 方式1:先创建一个组件构造器,然后由组件构造器创建组件,如:var myCom =Vue.extend(option)
  • 方式2:使用Vue.component()直接创建组件。Vue.component('componentName',option) , option相当于创建vue对象传入的配置对象
  • 方式3:把组件的 name 属性作为注册后组件的名称
//方式1 创建hello组件
const hello = Vue.extend({
template:`
<div>
<h2>你好啊!{{name}}</h2>
</div>
`,
data(){
return {
name:'Tom'
}
}
})
// 方式2
Vue.component('hello', {
template:`
<div>
<h2>你好啊!{{name}}</h2>
</div>
`,
data(){
return {
name:'Tom'
}
}
})
//方式3
<template>
<div>
<h2>你好啊!{{name}}</h2>
</div>
</template>
<script>
export default {
name: 'hello',
data(){
return {
name:'Tom'
}
}
</script>

注册组件#

全局组件注册#

在<script>标签中直接使用 Vue.component(componentName, component) 方法

<script>
//全局注册组件 hello
Vue.component('school', school)
</script>

局部组件注册#

在需要使用的页面中,创建的vue 实例中,component项中注册

<script>
//创建vm
new Vue({
el: '#root',
data: {
msg:'你好啊!'
},
//注册组件(局部注册)
components: {
hello: hello,
// ES6简写形式
// hello,
}
})
</script>

区别#

  • 被全局注册的组件,可以在全局任何一个组件内使用
  • 被局部注册的组件,只能在当前注册的范围内使用

应用场景

  • 如果某些组件在开发期间的使用频率很高,推荐进行全局注册
  • 如果某些组件只在特定的情况下会被用到,推荐进行局部注册

使用组件#

在页面注册组件后,使用 <组件名/> 或 <组件名><组件名/> 的方式

关于组件名#

一个单词组成:

  • 第一种写法(首字母小写):school
  • 第二种写法(首字母大写):School

多个单词组成:

  • 第一种写法(kebab-case命名):my-school
  • 第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)

备注:

(1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。

(2).可以使用name配置项指定组件在开发者工具中呈现的名字。

关于组件标签#

第一种写法:<school></school>

第二种写法:<school/>

备注:不用使用脚手架时,<school/>会导致后续组件不能渲染。

VueComponent#

  • hello组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend()生成的。
  • 我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建hello组件的实例对象,即Vue帮我们执行的:new VueComponent(options)。
  • 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!(这个VueComponent可不是实例对象)
  • 关于this指向:
    • 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
    • new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
  • VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。Vue的实例对象,以后简称vm。

一个重要的内置关系#

  • 一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
  • 为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。

vue_组件_一个重要的内置关系
vue_组件_一个重要的内置关系

Props#

  1. 功能:让组件接收外部传过来的数据

  2. 传递数据:<Demo name="xxx"/>

  3. 接收数据:

    1. 第一种方式(只接收):props:['name']

    2. 第二种方式(限制类型):props:{name:String}

    3. 第三种方式(限制类型、限制必要性、指定默认值):

      props:{
      name:{
      type:String, //类型
      required:true, //必要性
      default:'老王' //默认值
      }
      }

    备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

子组件是无法直接使用父组件的 data 中的数据的,需要通过 props 属性才能够使用父组件传入过来的值

向子组件传入数据#

在父组件的引用中填入属性名与对应的属性值,然后在子组件的 props 值填入与引用子组件的属性名一致的属性名,就可以在子组件中引用父组件的数据了,就如访问 data 中的值一样

父组件 App.vue

<template>
<div id="app">
// 向子组件传入 {name:'haha', age:this.age}
<School name="haha" :age="this.age"></School>
</div>
</template>
<script>
import School from './components/School.vue'
export default {
name: 'App',
data() {
return {
age: 360,
}
},
components: {
School,
},
}
</script>

子组件 School.vue

<template>
<div class="demo">
<h2>学校名称:{{ name }}</h2>
<h2>学校年龄:{{ age }}</h2>
<h2>学校地址:{{ address }}</h2>
</div>
</template>
<script>
export default {
name: 'School',
// 最简单的写法:props: ['name', 'age']
props: {
name: {
type: String,
required: true, // 必须要传的
},
age: {
type: Number,
required: true,
},
},
data() {
return {
address: '北京昌平',
}
},
}
</script>

注意:

  • 一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop,但是为了方便可以传入一个对象,调用对象的属性来使用传入的数据
  • 组件中的所有 props 中的数据都是通过父组件传递给子组件的,**不要试图去修改 props 中传入的数据,**一般都是只读的,如果修改 Vue 会抛出报错信息
  • 可以通过 v-bind 动态传递给 prop 一个值
  • 子组件的 data 数据并不是通过父组件传递过来的,而是子组件自身私有的,比如子组件通过 Ajax 请求回来的数据都可以放在 data 身上,子组件的 data 上的数据都是可读可写的

Prop 的大小写#

HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当使用 DOM 中的模板时,驼峰命名法的 prop 名需要使用其等价的短横线分隔命名

<blog-post post-title="hello!"></blog-post>
<script>
Vue.component('blog-post', {
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>',
})
</script>

Prop 类型#

如果希望传入的 prop 都有指令的值类型,可以用对象的方式来,可以以对象形式列出 prop,这些属性的名称和值分别是 prop 各自的名称和类型。除此之外,还可以用于配置其他高级选项

//数组形式
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
//对象形式
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
}
// 简单语法
Vue.component('props-demo-simple', {
props: ['size', 'myMessage'],
})
// 对象语法,提供校验
Vue.component('props-demo-advanced', {
props: {
// 检测类型
height: Number,
// 检测类型 + 其他验证
age: {
type: Number,
default: 0, //设置默认值
required: true, //是否必须
validator: function (value) {
//对值进行验证
return value >= 0
},
},
},
})

动态传递 Prop#

可以通过 v-bind 的方式动态传递一个变量值给一个 prop,通过 name="xxx"的方式,会将 xxx 解析为字符串,因此应用 v-bind方式传入一个 js 表达式

  • 传入一个数字
<!-- 即便 `42` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:likes="42"></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:likes="post.likes"></blog-post>
  • 传入一个布尔值
<!-- 包含该 prop 没有值的情况在内,都意味着 `true`。-->
<blog-post is-published></blog-post>
<!-- 即便 `false` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:is-published="false"></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:is-published="post.isPublished"></blog-post>
  • 传入一个数组
<!-- 即便数组是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:comment-ids="post.commentIds"></blog-post>
  • 传入一个对象
<!-- 即便对象是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post
v-bind:author="{
name: 'Veronica',
company: 'Veridian Dynamics'
}"
></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:author="post.author"></blog-post>
  • 传入一个对象的所有属性

如果想要将一个对象的所有属性都作为 prop 传入,你可以使用不带参数的 v-bind(取代 v-bind:prop-name)

post: {
id: 1,
title: 'My Journey with Vue'
}
<blog-post v-bind="post"></blog-post>
<!--与下面的方法等价-->
<blog-post v-bind:id="post.id" v-bind:title="post.title"></blog-post>

$ref 属性#

  • 被用来给元素或子组件注册引用信息(id的替代者),通过这个引用的 ID,父组件可以直接通过this.$refs访问这个组件或子元素
  • 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
  • 使用方式:
    • 打标识:<h1 ref="xxx"></h1>或 <School ref="xxx"></School>
    • 获取:this.$refs.xxx
<div id="app">
<div>
<input type="button" value="获取元素内容" @click="getElement" />
<!-- 使用 ref 获取元素 -->
<h1 ref="myh1">这是一个大大的H1</h1>
<hr />
<!-- 使用 ref 获取子组件 -->
<my-com ref="mycom"></my-com>
</div>
</div>
<script>
Vue.component('my-com', {
template: '<h5>这是一个子组件</h5>',
data() {
return {
name: '子组件',
}
},
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {
getElement() {
// 通过 this.$refs 来获取元素
console.log(this.$refs.myh1.innerText) // 这是一个大大的H1
// 通过 this.$refs 来获取组件
console.log(this.$refs.mycom.name) // 子组件
},
},
})
</script>

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Vue 组件
https://sukksa.github.io/posts/vue-zu-jian/
作者
Sukksa
发布于
2022-10-06
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Sukksa
记录前端学习与日常
公告
博客刚刚上线,内容还在慢慢补齐。欢迎随便逛逛~
分类
标签
最新动态
站点统计
文章
69
分类
16
标签
17
总字数
178,517
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
GitHub Actions
博客版本
Firefly v6.16.8
文章许可
CC BY-NC-SA 4.0
文章目录