定义组件

    • properties 定义组件原型链属性和方法

    上例中定义的组件,并不能直接使用,因为没有个template的组件不能实例化,它更像一个抽象类, 可供其他组件继承。

    以继承父组件的方式定义组件:

    1. var SubComponent = Component.extend({
    2. template: '<div>sub-component</div>'
    3. });

    组件有个关键属性defaults,它用来定义组件的默认数据。在组件实例化时,会和传入组件的属性 进行合并Object.assign()赋给组件实例的props属性,作为组件的最终数据。

    defaults支持两种取值类型:Object & Function

    @deprecated

    1. var Component;
    2. Component = Intact.extend({
    3. template: '<div>a = {self.get("a")}</div>',
    4. defaults: {
    5. a: 1
    6. }
    7. });

    如果以Object类型定义defaults,在组件继承时,会自动合并。

    1. var SubComponent;
    2. SubComponent = Component.extend({
    3. template: '<div>a = {self.get("a")}<br />b = {self.get("b")}</div>',
    4. defaults: {
    5. b: 2
    6. }
    7. });

    可以看到,SubComponent组件并没有定义a属性,但是在模板中却取到了a,这是因为继承Component时, 也继承了它的默认数据。

    这种方式在定义组件时非常方便,但如果使用不当,会存在以下问题。

    1. var Component = Intact.extend({
    2. template: '<div>\
    3. <button ev-click={self.add}>+1</button>\
    4. a.a = {self.get("a.a")}\
    5. </div>',
    6. defaults: {
    7. },
    8. add: function() {
    9. this.set('a.a', this.get('a.a') + 1);
    10. });
    1. Intact.extend({
    2. template: template,
    3. _init: function() {
    4. this.Component = Component;
    5. }
    6. });

    其实这一切的根源是由于Intact合并数据时,使用的Object.assign(),而这只是一个浅拷贝函数,对于深层嵌套的引用类型, 仍然拷贝的是引用。在组件继承时,也存在同样的问题。

    所以在你的数据存在引用嵌套时,我们应该使用Function定义defaults,它每次都会返回一份新数据。

    Function类型

    使用Function定义defaults,应该返回一个Object

    1. var Component = Intact.extend({
    2. template: '<div>\
    3. <button ev-click={self.add}>+1</button>\
    4. a.a = {self.get("a.a")}\
    5. </div>',
    6. defaults: function() {
    7. return {
    8. a: {a: 1}
    9. };
    10. },
    11. add: function() {
    12. this.set('a.a', this.get('a.a') + 1);
    13. }
    14. });
    1. var Component = self.Component;
    2. <div>
    3. <Component />
    4. <Component />
    5. </div>
    1. Intact.extend({
    2. template: template,
    3. _init: function() {
    4. }
    5. });

    此时,每个组件的数据是独立的了。

    @since v2.3.0

    组件会在初始化和更新时验证属性合法性,我们只需要通过组件的静态属性propTypes定义数据验证方式即可。 当组件验证失败时,会在打印错误信息,但不会终端程序运行。数据的验证只会在开发环境进行。

    1. String
    2. Number
    3. Boolean
    4. Array
    5. Object
    6. Function
    7. Date
    8. RegExp

    对于自定义构造函数,使用instanceof进行检测,例如Intact.VNode用于检测是否时虚拟dom对象vnode

    1. Component.propTypes = {
    2. vnode: Intact.VNode
    3. };

    枚举类型

    通过数组可以指定枚举类型的数据,甚至可以和构造函数搭配使用,它们之间时”或“的关系

    1. Component.propTypes = {
    2. enum: ['left', 'bottom', 'right', 'top'],
    3. enumWithObject: ['left', 'bottom', 'right', 'top', Object],
    4. }

    对于复杂的验证方法我们可以指定validator函数进行验证,该函数返回布尔值true则验证通过,false 则验证失败,或者返回字符串来作为错误提示信息。

    1. Component.propTypes = {
    2. value: {
    3. validator: function(value) {
    4. if (value > 100 || value < 0) {
    5. return "the value must be between 0 and 100";
    6. }
    7. return true;
    8. }
    9. }
    10. }

    必填属性

    添加required: true即可指定该属性为必填项

    1. Component.propTypes = {
    2. value: {
    3. type: Number,
    4. required: true
    5. }
    6. }

    使用ES6/7 Classstatic语法,可以如下定义

    另一个组件的重要属性便是template,它用来定义组件的模板。它既可以传入模板字符串, 又可以传入模板函数,如果传入模板字符串,会调用Intact.Vdt.compile()方法将之编译成模板函数。 模板语法请参考章节。

    1. Intact.extend({
    2. });