今天出门,物业小姐姐打招呼说今天是腊八节,叫吃一碗腊八粥。今天是腊八节呀,记得小时候每到这个时候已是浓浓的年味了了,如今粥入游子愁肠,便化作无数相思泪,香飘十里,犹未解远乡情。
哈喽,大家好,我是鑫阳,今天一起看看Vue组件开发吧!
1、为什么使用组件
组件(Component)是Vue.js最核心的功能,我们在项目开发中,经常碰到很多地方使用相同的页面元素和样式,我们就可以封装成一个组件,目的就是为了提高代码的复用性和可维护性。因为实际的项目需求是多变的,经常改来改去。比如说修改所有页面输入框的验证方法、给你一天时间一个个的去修改,刚修改完了舒缓一口气,又说要改回来好一点,你是不是就想干架了。
vue.js组件就是提高重用性,让代码可复用,有了组件就以上的问题分分钟就搞定了,修改一个地方,其他相同的地方也就都改变了。
我们先来看一组代码:
<Card style="width:350px;">
<p slot="title">与xxx聊天中</p>
<a href="#" slot="extra">
<Icon type="android-close" size="18"></Icon>
</a>
<div style="height:100px;"></div>
<div>
<Row :gutter="16">
<i-col span="17">
<i-input v-model="value" placeholder="请输入"></i-input>
</i-col>
<i-col span="4">
<i-button type="primary" icon="paper-airplane">发送</i-button>
</i-col>
</Row>
</div>
</Card>
这里有我们从没有见过的标签,比如 、 、等,这段代码除了内联样式也没有其他的css代码,但是它能呈现出这样的效果:
这些没见过的自定义标签就是组件,每个标签代表一个组件,这任何使用Vue的地方都可以直接使用,接下来我们一起看看组件的具体用法:
2、组件的用法:
2.1 全局注册组件
`组件需要注册后才能使用,有全局注册和局部注册两种方式,全局注册后,任何Vue实例都可以使用,全局注册具体代码如下
Vue.component('hello-component',{
//选项
})
hello-component就是刚刚定义的组件名称,在父的Vue实例中使用组件,需要在父Vue实例创建前注册组件。具体使用如下:
<div id="app">
<hello-component></hello-component>
</div>
<script>
Vue.component('hello-component',{
//选项
})
//完成组件注册后创建父实例
var app = new Vue({
el: '#app'
})
</script>
此时页面展示是空白的,因为hello-component组件还没有任何的内容,在组件中添加template就可以显示组件的内容了:
Vue.component('hello-component',{
template:'<div>hello Component!</div>'
})
渲染的结果就是:
<div id="app">
<div>hello Component!</div>
</div>
2.2 局部注册组件
全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。在Vue实例中,使用components选项可以局部注册组件,注册后的组件只有在该实例作用域下有效。组件中也可以使用components选项来注册组件,使组件可以嵌套:
<div id="app">
<hello-component></hello-component>
</div>
<script>
var childComponent = {
template: '<div>局部注册组件</div>'
}
var app = new Vue({
el: '#app',
components:{
'hello-component':childComponent
}
})
</script>
或者如果你通过 Babel 和 webpack 使用 ES2015 模块,那么代码看起来更像:
import HelloComponent from './helloComponent.vue'
export default {
components: {
HelloComponent
},
// ...
}
3.使用props传递数据
3.1 props基本用法
组件不仅是把模版的内容进行复用,更重要的是组件间要要进行通信来传递数据或者参数。如果父组件要向子组件传递数据,子组件接收到父组件的数据来渲染呈现,这种父向子组件传递数据叫做正向传递数据过程,通过props来实现。
在子组件中,使用选项props来申明需要从父组件接收的数据,props可以是字符串数组,也可以是对象,我们以数组的用法为例,比如我们要接收父组件的数据message,那么就是这样的:
<div id="app">
<child-component message="来自父组件的数据"></child-component>
</div>
<script>
//全局注册子组件
Vue.component('child-component',{
props: ['message'],
template: '<div>{{ message }}</div>'
})
//挂载父组件Vue实例
var app = new Vue({
el: '#app'
})
</script>
渲染后的结果为:
<div id="app">
<div>来自父组件的数据</div>
</div>
HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:
Vue.component('my-component', {
// 在 JavaScript 中是 camelCase 的
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
<!-- 在 HTML 中是 kebab-case 的 -->
<my-component post-title="hello!"></my-component>
3.2 单向数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
这里有两种常见的试图变更一个 prop 的情形:
- 这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data property 并将这个 prop 用作其初始值:
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
- 这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
注意:在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop
来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。
3.3 数据验证
props数据的传值可以是数据,也可以是对象,当props需要验证时就需要对象的写法:
一般组件需要提供给别人使用,推荐都进行数据验证,例如你知道的这些类型。如果有一个数据类型不对,则 Vue 会在浏览器控制台中警告你。如下示例:
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].includes(value)
}
}
}
})
type 可以是下列原生构造函数中的一个:
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
额外的,type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认。
3.4 组件通信
我们知道,父组件向子组件通信,通过props传递数据就可以了,但是组件关系有父子组件,兄弟组件,祖孙跨级组件,这个组件之间又是怎么通信的呢?
3.4.1 自定义事件
当子组件需要向父组件传递数据时候,就要用到自定义事件,与javascript观察者模式一样,子组件用$emit()
来出发事件,父组件用$on
来监听子组件的事件。
父组件也可以直接在子组件的自定义标签上使用v-on 来监听子组件出发的自定义事件,比如:
<div id="app">
<p>总数: {{ total }}</p>
<my-component
@increase="handleGetTotal"
@reduce="handleGetTotal"
></my-component>
</div>
<script>
Vue.component('my-component',{
template:'\
<div>\
<button @click="handleIncrease">+1</button>\
<button @click="handleReduce">\
</div>',
data:function(){
return {
counter: 0
}
},
methods:{
handleIncrease:function(){
this.counter++;
this.$emit('increase',this.counter);
},
handleReduce:function(){
this.counter--;
this.$emit('reduce',this.counter);
}
}
})
var app = new Vue({
el:'#app',
data:{
total:0
},
methods:{
handleGetTotal:function(total){
this.total = total;
}
}
})
</script>
3.4.2 使用v-model
Vue2.x可以在自定义组件上使用v-model指令:
<div id="app">
<p>总数: {{ total }}</p>
<my-component v-model="total"></my-component>
</div>
<script>
Vue.component('my-component',{
template:'<button @click="handleClick">+1</button>',
data:function(){
return {
counter: 0
}
},
methods:{
handleClick:function(){
this.counter++;
this.$emit('input',this.counter);
}
}
})
var app = new Vue({
el:'#app',
data:{
total:0
}
})
</script>
这次组件的$emit()事件名是特殊的input,在使用组件的父级,并没有在上使用@input= “handler”,而是直接使用了v-model绑定了一个数据total,这也可以成为一个语法糖。
3.4.3 非父子组件通信
非父子组件一般有2种,兄弟组件和跨多级组件。 在Vue2.x中,推荐使用一个空的Vue实例作为中央事件总线(bus),就像一个房产中介一样。看下面的代码:
<div id="app">
{{ message }}
<component-c></component-c>
</div>
<script>
var bus = new Vue();
Vue.component('component-c',{
template:'<button @click="handleEvent">传递事件</button>',
methods:{
handleEvent:function(){
bus.$emit('on-message','来自组件component-c的内容');
}
}
})
var app = new Vue({
el:'#app',
data:{
message:''
},
mounted: function(){
var _this = this;
//在实例初始化时,监听来自bus实例的事件
bus.$on('on-message',function(msg){
_this.message = msg;
})
}
})
</script>
这里创建了一个名为bus的Vue实例,里面没有任何内容,在实例app初始化时监听了bus的事件on-message,在组件component-c中点击按钮会通过bus把 on-message事件发送出去,从而app会接受到来自bus的事件。
同时可以扩展实例bus,给它添加data,methods,computed等选项,在业务中可以将一些共享通用的信息比如用户token,只需初始化时让bus获取一次就可以任何时间任何组件使用了,在单页面富应用(SPA)很使用。
当然了,实际开发项目比较大时,往往多人协作开发,大多选择状态管理比如 vuex,在后面的文章中讲到。
父链
在子组件中,使用this.$parent
可以直接访问该组件的父实例或组件,父组件也可以通过this.$children访问它所有的子组件,而且可以递归向上或向下无限访问,直到根实例或最内层的组件。代码如下:
<div id="app">
{{ message }}
<component-c></component-c>
</div>
<script>
Vue.component('component-c',{
template:'<button @click="handleEvent">通过父链直接修改数据</button>',
methods:{
handleEvent:function(){
//通过父链访问父实例,就可以做任何事情了
this.$parent.message = '来自组件component-c的内容'
}
}
})
var app = new Vue({
el:'#app',
data:{
message:''
}
})
</script>
父子组件不推荐这样操作,因为耦合性太强了,父子组件最好还是使用
props
和$emit
来通信。
子组件索引
当子组件很多时,用this.$children
来遍历子组件实例比较困难,尤其组件是动态渲染的时候,他们的序列不固定。vue提供了子组件索引的方法,用特殊的属性ref
来为子组件指定一个索引名称。代码如下:
<div id="app">
<button @click="handleRef">通过ref获取子组件实例</button>
<component-c ref="comC"></component-c>
</div>
<script>
Vue.component('component-c',{
template:'<div>子组件</div>',
data:function(){
return {
message:'子组件内容'
}
}
})
var app = new Vue({
el:'#app',
methods:{
handleRef:function(){
//通过$refs来访问指定实例
var msg = this.$refs.comC.message;
console.log(msg);
}
}
})
</script>
注意:
$refs
只在组件渲染完成后填充,并且它是非响应式的。它仅仅作为一个直接访问子组件的应急方案,应当避免在模版或计算属性中使用$refs
今天的关于vue组件开发的分享就到这里了,如果您觉得本篇文章对您有帮助,就麻烦一键三连吧,非常感谢!下篇还会聊聊组件更多高级的的用法,bye~bye!
标签:function,Vue,一学,app,component,vue3.0,组件,message From: https://blog.csdn.net/weixin_41765786/article/details/144967097