具名组件
当一个组件作为另一个组件的子组件使用时,我们可以通过具名组件简化成一个HTML标签的写法,这样可以极大的简化我们的代码。
具名组件一般会把组件内所有的交互和行为以及模板都封装起来,使用的时候就当成类型的HTML标签使用就很方便了。
定义一个具名组件
组件的名字必须全部为小写,中间包含至少一个横杆,如ui-view。
// es5
drunk.Component.define('my-component', {
template: '<div>This is my component</div>',
// templateUrl: 'tpl/my-component.html',
});
// es6
class MyComponent extends drunk.Component {
init() {
this.template = '<div>This is my component</div>';
// this.templateUrl = 'tpl/my-component.html';
}
}
drunk.Component.register('my-component', MyComponent);
// ts
@drunk.component('my-component')
class MyComponent extends drunk.Component {
template = '<div>This is my component</div>';
// templateUrl = 'tpl/my-component.html';
}
template模板的HTML字符串templateUrl模板文件的url
template的优先级比templateUrl高,创建组件实例时会先检测是否存在template字段,再检测templateUrl,templateUrl会发送XMLHttpRequest请求加载得到HTML字符串,然后和template字段的处理流程一样,先创建成DOM节点,再调用组件实例的$mount方法挂载,然后解析编译等。
使用具名组件
<body>
<my-component></my-component>
</body>
new drunk.Component().$mount(document.body);
渲染为:
<body>
<div>This is my component</div>
</body>
组件的数据和事件
具名组件有自己的作用域,但和repeat指令不一样,它无法直接访问父级的作用域,所以具名组件的使用方法和HTML标签一样,需要通过属性传递数据,注册事件。
// alert-view.js
@drunk.component('ui-alert-view')
class UIAlertView extends drunk.Component {
templateUrl = 'alert-view.html';
visible: boolean = false;
title: string = '';
content: string = '';
onConfirm() {
this.visible = false;
this.$emit('confirm');
}
}
<!-- alert-view.html -->
<style>
.alert-container {
position: fixed;
top: 50%;
left: 50%;
width: 300px;
height: 100px;
transform: translate(-50%, -50%);
text-align: center;
}
</style>
<div class="alert-container">
<p>{{title}}</p>
<p>{{content}}</p>
<button drunk-on="click: onConfirm()>确认</button>
</div>
使用例子:
<body>
<button drunk-on="click: showAlert()">点击显示ui-alert-view</button>
<ui-alert-view title="温馨提示" content="{{alertContent}}" visible="{{alertVisible}}" on-confirm="alertVisible = false">
</ui-alert-view>
</body>
// app.js
var app = new drunk.Component();
app.$mount(document.body);
app.showAlert = function () {
this.alertContent = '一个随机数' + Math.random();
this.alertVisible = true;
};
ui-alert-view的title, content, visible属性都和普通的HTML标签一样可以直接赋值传递到组件内部,如果需要进行数据绑定,可以用双大括号这的插值表达式。ui-alert-view里的button在点击后会把visible状态设置成false,同时触发一个confirm事件,在组件外部想要接收这个事件,可以在<ui-alert-view>标签上添加on-confirm(on-${eventName},这里的eventName为confirm)属性进行事件注册。也可以通过on指令进行注册,如:drunk-on="confirm: alertVisible = false"。
因为HTML属性语法忽略大小写,所以所有驼峰式的组件属性和事件名都要换成带-横杆的写法,如alertVisible要在标签上用时要写成alert-visible,myEvent事件在标签上用时要写成on-my-event。
组件数据的双向绑定
在组件上使用two-way这个属性来声明哪个属性需要进行双向绑定
<ui-alert-view visible="{{alertVisible}}" two-way="visible"></ui-alert-view>
组件内部的visible属性的值变化时,会同步到父级的alertVisible属性。如果有多个属性需要进行双向绑定时,只需要用空格隔开: two-way="prop1 prop2 prop3"。
组件样式的独立作用域
如果需要实现组件的样式有独立的作用域,可以在模板中引入的<style>或<link>标签上加上scoped属性,如:<style scoped>,<link rel="stylesheet" scoped href="...">。drunk会在解析模板的时候检测到这个属性存在时,先对样式规则前添加一个唯一的样式名,使其不会被其他样式影响。
可复用的组件逻辑
原理上组件的所有属性都可以通过在标签上传值去修改,所以当我们的某个组件的逻辑不变而只是在UI上有一些变化时,我们可以通过修改组件的template或templateUrl属性去替换模板以达到复用逻辑的效果,当然这个场景并不常用。
<ui-alert-view></ui-alert-view>
<ui-alert-view template-url="new-alert-view.html"></ui-alert-view>