《Vue.js实战》第七章.组件

本文详细介绍了Vue.js中组件的使用方法,包括组件注册、props数据传递、组件通信、slot内容分发等核心概念,以及递归组件、动态组件、异步组件等高级用法,帮助开发者更好地理解和运用Vue.js组件。

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

7.1 组件作用:
提高代码复用性,使项目易于维护

7.1 组件的使用

7.1.1 组件注册-全局注册
全局注册后,任何vue的实例都可以使用该组件.
Vue.component('my-component',{

})

my-component就是自定义组件的名称,推荐使用小写加减号的方式来命名.
要在父元素中使用组件,必须在父元素实例初始化之前注册组件

Vue.component('my-component', {
  template: '<div>这是my-component的内容!!</div>'
})
var app = new Vue({
  el: '#app',
  data: {

  }
})
=================================================
<div id="app">
  <my-component></my-component>
</div>
7.1.2 组价注册-局部注册
var Child = {
 template: '<div>这里是组件内容!!</div>'
}
var app = new Vue({
  el: '#app',
  data: {

  },
  components: {
    'my-component': Child
  }
})
==============================================
<div id="app">
  <my-component></my-component>
</div>

7.2 使用props传递数据

7.2.1 props的基本用法

组件不仅仅是对模板的内容进行复用,更重要的是要进行模板之间的通信

正向传递数据

父组件的模板包含子组件,父组件要想子组件正向的传递数据或参数,
子组件解收到后根据参数的不同来渲染不同的内容或执行操作.

props值的分类

1.数组
2.对象

props命名规则:在使用DOM模板时:使用CamelCase(驼峰命名)的props名称要使用kebab-case:

例:

<div id="app">
		<my-component warning-text="提示信息!"></my-component>
</div>
========================================================================
<script>
	Vue.component('my-component',{
		props:['warningText'],
		template:'<div>{{warningText}}</div>'
	})
	var app = new Vue({
		el:'#app'
	})
</script>

props作为需要被转变的原始值传入,在这种情况下使用计算属性.

例:

Vue.component('my-component',{
	props:['width'],
	template:'<div :style="style">组件内容</div>',
	computed:{
		style:function(){
			return {
				width:this.width+'px'
			}
		}
	}
})
7.2.2 prop数据的验证
例:	Vue.component('my-component',{
		props:{
			//必须是数字
			propA:Number,
			//必须是数字或字符串
			propB:[String,Number],
			//布尔值,如果没有定义,默认值是true
			propC:{
				type:Boolean,
				default:true
			},
			//数字,并且必须是必传
			propD:{
				type:Number,
				required:true
			},
			//如果是数组或对象,默认值必须是一个而函数来返回
			propE:{
				type:Array,
				default:function(){
					return []
				}
			},
			//自定义一个验证函数
			propF:{
				validator:function(value){
					return value>10
				}
			}
			
		},
		template:'<div>{{propA}}:{{propD}}</div>'
	})

验证的type类型

  • String
  • Number
  • Boolean
  • Object
  • Array
  • Function

7.3 组件通信

* 7.3.1 父子组件通信
**自定义事件**

	<div id="app">
		<p>总数:{{total}}</p>
		<my-component @increase="handleGetTotal" @reduce="handleGetTotal"></my-component>
	</div>
	======================================================================================
	Vue.component('my-component',{
		template:`
		<div>
			<button @click="handleIncrease">+1</button>
			<button @click="handleReduce">-1</button>
		</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
			}
		}
	})

使用v-model

<div id="app">
		<p>总数:{{total}}</p>
		<my-component v-model="total"></my-component>
	</div>
==========================================================
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
		}
	})

使用v-model自定义双向绑定组件

<div id="app">
		<p>总数:{{total}}</p>
		<my-component v-model="total"></my-component>
		<button type="button" @click="handleReduce">-1</button>
	</div>
==============================================================
Vue.component('my-component',{
		props:['value'],
		template:'<input :value="value" @input="updateValue"></input>',
		methods:{
			updateValue:function(event){
				this.$emit('input',event.target.value)
			}
		}
	})
	var app = new Vue({
		el:'#app',
		data:{
			total:0
		},
		methods:{
			handleReduce:function(){
				this.total--
			}
		}
		
	})

实现一个具有双向数据绑定的v-model组件要满足的要求

 * 接收一个value属性
 * 有新的value时触发input事件
* 7.3.2 非父子间组件通信(兄弟组件之间通信,跨级组件之间通信)
  • 1.中央事件总线(bus)
  • 2.父链
**定义:** 

在子组件中,使用this.$parent可以直接访问该组件的父实例或组件,父组件也可以通过this.$children访问他所有的子组件,而且可以递归或向下无线访问,知道根实例或最内层组件

**例:**  

Vue.component('my-component',{
		template:'<button @click="handleChange">通过父链修改父组件数据</b1utton>',
		methods:{
			handleChange:function(){
				this.$parent.message="来自子组件的数据"
			}
		}			
  })
  var app = new Vue({
    el:'#app',
    data:{
      message:''
    }
})
  • 3.子组件索引
>> **示例**    

  <div id="app">
    <button @click="handleRef">通过ref获取子组件实例</button>
    <my-component ref="comA"></my-component>
  </div>
  ===========================================================
  Vue.component('my-component',{
		template:'<div>子组件</div>',
		data:function(){
			return{
				message:'自组件内容'
			}
		}
	})
	
	var app = new Vue({
		el:'#app',
		methods:{
			handleRef:function(){
			//通过ref来获取指定ref实例
			var msg = this.$refs.comA.message
			console.log(msg)
		}}
	})

7.4 使用slot分发内容

7.4.1 什么是slot

可以在组件中插入内容
组件的3个API来源:props传递数据、event出发事件、slot分发内容
内容分发:当需要组件混合使用时,混合父组件的内容与子组件的模板时,就会用到slot

7.4.2 什么是编译作用域
7.4.3 作用域的用法
* 单个slot

示例

<div id="app">
		<child-component>
			<p>分发的内容</p>
		</child-component>
	</div>

======================================

Vue.component('child-component',{
		template:`
		<div>
			<slot>子组件默认显示的内容</slot>
		</div>
		`
	})
	var  app = new Vue({
		el:'#app'
	})
* 具名插槽

示例

<div id="app">
		<child-component>
			<p slot="header">我是头部</p>
			<p>默认插槽</p>
			<p slot="footer">我是尾部插槽</p>
		</child-component>
	</div>

================================================

Vue.component('child-component',{
		template:`
		<div>
			<div class="header">
				<slot name="header"></slot>
			</div>
			<div>
				<slot></slot>
			</div>
			<div class="footer">
				<slot name="footer"></slot>
			</div>
		</div>
		`
		
	})
	var app =  new Vue({
		el:'#app'
	})
7.4.4 作用域插槽

示例

<div id="app">
    <child-component>
      <template scope="props">
        <p>来自父组件的内容</p>
        <p>{{props.msg}}</p>
      </template>
    </child-component>
</div>

==========================================================

Vue.component('child-component',{
		template:`<div>
					<slot msg="来自子组件的内容"></slot>
				  </div>`
	})
	var app = new Vue({
		el:'#app'
	})

示例2

<div id="app">
		<my-list :books="books">
			<template slot="book" slot-scope="props">					
				<li>{{props.bookName}}</li>
			</template>
		</my-list>
		<ul>
			<li v-for="book in books">{{book.name}}</li>
		</ul>
	</div>

==========================================================

Vue.component('my-list',{
		props:{
			books:{
				type:Array,
				default:function(){
					return []
				}
			}
		},
		template:
		`
		<ul>
			<slot name="book" v-for="book in books" :book-name="book.name"></slot>
		</ul>
		`
	})
	var app = new Vue({
		el:'#app',
		data:{
			books:[
				{name:'《Vue.js实战》'},
				{name:'《JavaScript语言精粹》'},
				{name:'《JavaScript高级程序设计》'}
			]
		}
	})
7.4.5 访问slot

被分发的内容使用$slot来访问

<div id="app">
		<my-component>
			<h2 slot="header">标题</h2>
			<p>主体内容</p>
			<p>更多主体内容</p>
			<div slot="footer">底部信息</div>
		</my-component>

	</div>

==========================================================================

Vue.component('my-component',{
		template:
		`
		<div class="container">
			<div class="header">
				<slot name="header"></slot>
			</div>
			<div class = "main">
				<slot></slot>
			</div>
			<div class = "footer">
				<slot name = "footer"></slot>
			</div>
		</div>
		`,			
		mounted:function(){
			var header = this.$slots.header
			var main = this.$slots.default
			var footer = this.$slots.footer
			console.log(main)
			console.log(header)
			console.log(footer)
			console.log(footer[0].elm.innerHTML)
		}			
	})
	var app = new Vue({
		el:'#app',
		
	})

7.5 组件的高级用法

7.5.1 递归组件 (组件可以在它的模板内递归的调用自己)

示例

<div id="app">
		<child-component :count="1"></child-component>
	</div>

===================================================================

Vue.component('child-component',{
		name:'child-component',
		props:{
			count:{
				type:Number,
				default:1
			}
		},
		template:
		`
		<div class="child">
			<child-component :count="count+1" v-if="count<3"></child-component>
		</div>
		`
	})
	var app = new Vue({
		el:'#app',
		data:{
			
		}
	})

使用场景:级联菜单,树形控件

7.5.2 内联模板

示例

<div id="app">
		<child-component inline-template>
			<div>
				<h2>在父组件中定义子组件的模板</h2>
				<p>{{m}}</p>
				<p>{{msg}}</p>
			</div>
		</child-component>			
	</div>

====================================================================

Vue.component('child-component',{
		data:function(){
			return{
				msg:'在子组件中声明的数据'					
			}
		}
	})
	var app = new Vue({
		el:'#app',
		data:{
			m:'在父组件中声明的数据'
		}
	})

子组件和父组件中声明的数据都可以渲染,个人环境中只能渲染子组件的数据而不能渲染父组件的数据

7.5.3 动态组件

使用<component>元素来动态的挂载不同的组件

示例

<div id="app">
		<component :is="currentView"></component>
		<button @click="handleChangeView('A')">切换到A</button>
		<button @click="handleChangeView('B')">切换到B</button>
		<button @click="handleChangeView('C')">切换到C</button>
	</div>

==========================================================================================

var app = new Vue({
		el:'#app',
		components:{
			comA:{
				template:'<div>组件A</div>'
			},
			comB:{
				template:'<div>组件B</div>'
			},
			comC:{
				template:'<div>组件C</div>'
			}
		},
		data:{
			currentView:'comA'
		},
		methods:{
			handleChangeView:function(component){
				this.currentView='com'+component
				
			}
		}
	})
7.5.4 异步组件

vue观察到数据变化时并不是直接更新DOM,而是开启一个队列,并缓冲在同一事件循环中发生的所有数据改变.在缓冲时会去除重复的数据,从而避免不必要的计算和DOM操作,然后在下一个事件循环tick中,Vue刷新队列并执行实际(已经去重)工作,

示例

<div id="app">
		<child-component></child-component>
	</div>

=======================================================================

Vue.component('child-component',function(resolve,reject){
		window.setTimeout(function(){
			resolve({
				template:'<div>我是异步加载的</div>'
			})
		},2000)
	})
	var app = new Vue({
		el:'#app'
	})

7.6 其他

7.6.1 $nextTick

需求场景

有一个div默认为用v-if将其隐藏,当点击按钮时,将v-if的值修改为true显示div,同时获取div中的文本内容

模板代码

<div id="app">
		<div id="test" v-if="showDiv">这是一段文本</div>
		<button @click="getText">获取文本</button>
	</div>

错误js代码

var app = new Vue({
		el:'#app',
		data:{
			showDiv:false
		},
		methods:{
			getText:function(){
				this.showDiv=true
				var text = document.getElementById('test').innerHTML
				console.log(text)       
			}
		}			
	})

正确JS代码

var app = new Vue({
		el:'#app',
		data:{
			showDiv:false
		},
		methods:{
			getText:function(){
				this.showDiv=true				
				this.$nextTick(function(){
					var text = document.getElementById('test').innerHTML
					console.log(text)
				})
			}
		}			
	})
7.6.2 x-tamplates

示例

<div id="app">
		<my-component></my-component>
		<script type="text/x-template" id="my-component">
			<div>这是组件的内容</div>
		</script>
	</div>

===========================================================================

Vue.component('my-component',{
		template:'#my-component'
	})
	var app = new Vue({
		el:'#app',
		
	})
7.6.3 手动挂载实例

示例

<div id="mount-div"></div>

========================================

var MyComponent = Vue.extend({
		template:'<div>Hello:{{name}}</div>',
		data:function(){
			return{
				name:'Aresn'
			}
		}
	});
	
	new MyComponent().$mount('#mount-div')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姑苏_IT

创作不易,谢你打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值