# 组件

WARNING

自定义组件在 D2A 上不太支持,请注意使用

# 自定义组件

开发页面时开发者必须用到 Native 组件,如:textdiv,这些组件是由 Native 底层渲染出来的;如果开发一个复杂的页面,开发者把所有的 UI 部分写在一个文件的 <template>,那代码的可维护性将会很低,并且模块之间容易产生不必要的耦合关系

为了更好的组织逻辑与代码,可以把页面按照功能拆成多个模块,每个模块负责其中的一个功能部分,最后页面将这些模块引入管理起来,传递业务与配置数据完成代码分离,那么这就是自定义组件的意义

自定义组件是一个开发者编写的组件,使用起来和 Native 一样,最终按照组件的 <template>来渲染;同时开发起来又和页面一样,拥有 ViewModel 实现对数据、事件、方法的管理

这么来看,页面也是一种特殊的自定义组件,无需引入即可使用,同时服务于整个页面

  • 示例如下:
<template>
	<div>
		<text>自定义组件:</text>
		<text>{{ say }}</text>
		<text>{{ obj.name }}</text>
	</div>
</template>

<script>
	// 子组件
	export default {
		data: {
			say: 'hello',
			obj: {
				name: 'quickApp'
			}
		},
		onInit() {
			console.log('我是子组件');
		}
	};
</script>

# 组件引入

<import name="child" src="./child.ux"></import>

<template>
	<div>
		<text>引入组件:</text>
		<child></child>
	</div>
</template>

# 父子组件通信

父组件向子组件传递数据,通过在子组件的props属性中声明对外暴露的属性名称,然后在组件引用标签上声明传递的父组件数据。

注意:当前暂不支持 props 的中划线转驼峰

<!-- 子组件 -->
<template>
	<div class="child-demo">
		<text>子组件:</text>
		<text>{{ say }}</text>
		<text>{{ obj.name }}</text>
	</div>
</template>
<script>
	export default {
		props: ['say', 'obj'],
		onInit() {
			console.info(`外部传递的数据:`, this.say, this.obj);
		}
	};
</script>
<!-- 父组件 -->
<import name="child" src="./child.ux"></import>
<template>
	<div class="parent-demo">
		<child say="{{say}}" obj="{{obj}}"></child>
	</div>
</template>
<script>
	export default {
		data: {
			say: 'hello',
			obj: {
				name: 'child-demo'
			}
		}
	};
</script>

子组件对父组件通信,子组件通过$emit()触发在节点上绑定的自定义事件来执行父组件的方法

<!-- 父组件 -->
<import name="child" src="./child.ux"></import>
<template>
	<div class="parent-demo">
		<child say="{{say}}" obj="{{obj}}" @change-name="handleChange"></child>
	</div>
</template>
<script>
	export default {
		data: {
			say: 'hello',
			obj: {
				name: 'child-demo'
			}
		},
		handleChange(data) {
			this.obj = {
				name: data.name // World
			};
		}
	};
</script>
<!-- 子组件 -->
<template>
	<div class="child-demo">
		<text>子组件:</text>
		<text>{{ say }}</text>
		<text @click="setName">{{ obj.name }}</text>
	</div>
</template>
<script>
	export default {
		props: ['say', 'obj'],
		onInit() {
			console.info(`外部传递的数据:`, this.say, this.obj);
		},
		setName() {
			this.$emit('changeName', {
				name: 'World'
			});
		}
	};
</script>

# 兄弟/跨级组件通信

传统的兄弟组件通信、跨父子组件通信、不同页面通信,这里提供一种思路实现: 在 app.ux 中暴露出一个 eventbus 提供发布订阅能力,在其他页面或组件中使用。

class EventBus {
	constructor() {
		this.callbacks = {};
	}
	$on(name, callback) {
		this.callbacks[name] = this.callbacks[name] || [];
		this.callbacks[name].push(callback);
	}
	$emit(name, data) {
		this.callbacks[name].forEach(fn => fn(data));
	}
}

export default {
	eventbus: new EventBus()
};

A 页面向 B 页面通信:

// A 页面
this.$app.$def.eventbus.$emit('message', {
	name: 'Jay',
	age: 18
});

// B 页面
this.$app.$def.eventbus.$on('message', data => {
	console.log(data);
});