Vue.js组件理解

组件使用细节点

解决元素标签位置错误的问题:is 属性

<div id="app">
	<table>
		<tbody>
			<!--tbody里要用一个组件,但不能直接写组件名
				会导致位置错误问题,使用 is 属性将自定义组件row
				与 tr 标签绑定在一起
			-->
			<tr is='row'></tr>
			<tr is='row'></tr>
			<tr is='row'></tr>
		</tbody>
	</table>
	
		<ul>
			<li is='row'></li>
			<li is='row'></li>
			<li is='row'></li>
		</ul>
</div>

<script>
	
	Vue.component('row', {
		template: '<tr><td>this is a row</td></tr>'
	});
	
	var vm = new Vue({
		el: "#app"
	});
	
</script>

组件data函数

在子组件中,data 必须是一个函数,有可能一个子组件会被调用很多次,每个子组件数据不能产生冲突,通过一个函数返回一个对象的目的,就是让每个子组件都拥有独立的数据存储。

Vue.component('row', {
	//在子组件中,data 必须是一个函数
	data: function(){
		return {
			content: 'this is a row'
		}
	},
	template: '<tr><td>{{content}}</td></tr>'
});

ref的使用

<div id="app">
	<counter ref="one" @change="handleChange"></counter>
	<counter ref="two" @change="handleChange"></counter>
	<div>{{total}}</div>
</div>

<script>
	
	Vue.component('counter',{
		template: '<div @click="handleClick">{{number}}</div>',
		data: function(){
			return {
				number: 0
			}
		},
		methods: {
			handleClick: function() {
				this.number ++;
				// $emit() 自定义事件向父组件通信
				this.$emit('change');
			}
		}
	});
	
	var vm = new Vue({
		el: "#app",
		data: {
			total: 0
		},
		methods: {
			handleChange: function() {
				//可以使用自加一方法
				//this.total++;
				//也可以求二者之和
				// 通过 $refs 获取子组件的引用,再获取数据
				this.total = this.$refs.one.number + this.$refs.two.number;
			}
		}
	});

父子组件的数据传递

父组件通过属性的形式向子组件传递数据

Vue 中的单项数据流:父组件可以向子组件传递参数,该参数在父组件可随便修改,子组件绝对不能反过来去修改父组件传递过来的参数,只用不改

<div id="app">
	<!--父往子传递-->
	<!--父组件通过绑定属性的形式向子组件传递数据-->
	<counter :count="3" @inc="handleIncrease"></counter>
	<counter :count="2" @inc="handleIncrease"></counter>
	
	<!--子往父传递-->
	<!--子组件通过事件触发的形式向父组件传递数据-->
	<div>{{total}}</div>
</div>

<script>
	var counter = {
		props: ['count'],
		data: function() {
			return {
				//定义一个number 把获取来的数据克隆一个传进去
				number: this.count
			}
		},
		template: '<div @click="handleClick">{{number}}</div>',
		methods: {
			handleClick: function() {
				this.number += 2;
				//子组件通过点击将事件触发出去
				this.$emit('inc', 2)
			}
		}
	}
	var vm = new Vue({
		el: "#app",
		components: {
			counter: counter
		},
		data: {
			total: 5
		},
		methods: {
			// 父组件执行的函数里可以直接接收到 $emit()的参数
			handleIncrease: function(step) {
				this.total += step;
			}
		}
	});

组件参数校验与非props特性

<div id="app">
	<child :content="123"></child>
</div>

<script>
	
	Vue.component('child',{
		props: {
			//设定子组件接收的content 属性,
			//	要么是数字,要么是字符串
			content: [String, Number]
			/*
			也可以这样写:
			content: {
				//类型
				type: String,
				
				//设定这个属性是必须的
				required: true,
				
				//如果不给default 传数值,默认default
				default: 'default value',
				
				//对传入 content属性 添加校验
				//规定长度必须大于5
				validator: function(value) {
					return (value.length > 5)
				}
			}
			*/
		},
		template: '<div>{{content}}</div>'
	})
	
	var vm = new Vue({
		el: "#app"
	});
	

props 特性:
父组件传递了content 子组件又声明了一个content接收; 二者有一个对应关系。该属性不会在DOM中出现,子组件可直接通过插值表达式调用content内的内容。

非props 特性
父组件传递一个属性,但是子组件并没有props的内容,没有声明,无法获取父组件内容。该属性会在子组件DOM中出现

给组件绑定原生事件

<div id="app">
	<!--
		加native修饰符,监听原生点击事件,
		方法同子组件设置自定义事件向父组件触发
	-->
	<child @click.native='handleClick'></child>
</div>

<script>
	Vue.component('child',{
		template: '<div>child</div>'
	})
	var vm = new Vue({
		el: "#app",
		methods: {
			handleClick: function() {
				alert('click')
			}
		}
	});
</script>

非父子组件间的传值

  1. 借助官方的数据框架 vuex解决
  2. 发布订阅模式 总线机制 Bus 观察者模式
<!--非父子组件传值
	Bus / 总线 / 发布订阅模式 / 观察者模式
-->
<div id="app">
	<!--点击一个,另一个变成相同的-->
	<child content='anqw'></child>
	<child content='joe'></child>
</div>

<script>
	//每一个Vue 实例都会有bus 属性
	Vue.prototype.bus = new Vue()
	
	Vue.component('child',{
		data: function() {
			return {
				//父组件传过来的数据只能用不能改,
				//所以需要拷贝一份
				selfContent: this.content
			}
		},
		props: {
			content: String
		},
		template: '<div @click="handleClick">{{selfContent}}</div>',
		methods: {
			handleClick: function() {
				//实例上挂载的bus ,这个bus 又是Vue 实例,
				//所以会有$emit()方法,同时把内容传进参数
				this.bus.$emit('change',this.selfContent);
			}
		},
		//借助生命周期钩子,被挂载时执行
		//$on 方法监听自定义事件
		mounted: function() {
			//固定this的指向
			var this_ = this;
			this.bus.$on('change', function(msg) {
				this_.selfContent = msg
			})
		}
	})
	var vm = new Vue({
		el: "#app"
	});

在Vue中使用插槽 slot

<div id="app">
	<child>
		<!--插槽-->
		<!--如果不传标签会显示默认内容-->
		<h1>Anqw</h1>
	</child>
</div>

<script>
	Vue.component('child',{
		//slot插槽中显示的是父组件插入的标签
		template: '<div><p>hello</p><slot>默认内容</slot></div>'
	})
	var vm = new Vue({
		el: "#app"
	});
	
</script>

将多个插槽一一对应

<div id="app">
	<body-content>
		<div class="header" slot='header'>header</div>
		<div class="footer" slot='footer'>footer</div>
	</body-content>
</div>

<script>
	Vue.component('body-content',{
		//将插槽一一对应,用slot 与 name 属性绑定
		template: `<div>
						<slot name='header'></slot>
						<div class="content">
							content
						</div>
						<slot name='footer'></slot>
					</div>`
	});
	var vm = new Vue({
		el: "#app"
	});
	
</script>
<!--
	显示结果:
	header
	content
	footer
-->

Vue 中的作用域插槽

<div id="app">
	<child>
		<!--首先父组件内传了一个插槽,
			作用域插槽,必须用 template 标签包裹,
			同时声明从子组件接收的数据都放在props中,
			slot-scope 对应的属性名接收到数据后,
			以li的形式进行展示.
		-->
		<template slot-scope="props">
			<!--由父组件传递循环对应的模板-->
			<li>{{props.item}} - hello</li>
		</template>
	</child>
</div>

<script>
	Vue.component('child',{
		data: function() {
			return {
				list: [1,2,3,4]
			}
		},
		//当子组件做循环,DOM结构需要由外部传递时
		template: `<div>
						<ul>
							<slot 
								v-for="item of list" 
								:item="item">
							</slot>
						</ul>
					</div>`
	});
	var vm = new Vue({
		el: "#app"
	});
	
</script>

动态组件与v-once指令

<div id="app">
	<!--动态组件-->
	<!--会根据 is 中数据的变化去加载不同的组件-->
	<!--<component :is="type"></component>-->
	
	<child-one v-if="type === 'child-one'"></child-one>
	<child-two v-if="type === 'child-two'"></child-two>
	
	<button @click="handleClick">change</button>
	
	<!--当点击button时 两个组件 toggle显示-->
</div>

<script>
	Vue.component('child-one',{
		// v-once 可以把组件暂时放到内存里,
		//	点击之后直接从内存里取出就行,提高了性能
		template: '<div v-once>child-one</div>'
	});
	Vue.component('child-two',{
		template: '<div v-once>child-two</div>'
	});
	var vm = new Vue({
		el: "#app",
		data: {
			type: 'child-one'
		},
		methods: {
			handleClick: function() {
				this.type = (this.type === 'child-one'?
					'child-two': 'child-one');
			}
		}
	});
</script>
posted @ 2018-05-19 09:13  言叶以上  阅读(214)  评论(0编辑  收藏  举报