在Amaple单页应用中,一个页面其实存在两种模块化单位,分别是
模块 (am.Module类),它是以web单页应用跳转更新为最小单位所拆分的独立块;
组件 (am.Component类),它的定位是拥有特定功能的封装块,就像由一堆代码封装成的具有特定功能的函数一样,一个组件也有独立的视图、状态数据对象、组件行为以及生命周期。常用的组件有Dialog、Bubble、Navigator和Menubar等。
在模块中定义并使用一个简单的组件衍生类使用am.class类构造器继承am.Component类定义一个组件,而继承am.Component创建的类被称为 组件衍生类 ,你可以这样定义一个组件衍生类:
// 在am.class函数的参数中指定该组件衍生类的类名,它返回指定名称的组件衍生类
// 类名须遵循首字母大写的驼峰式命名规范,如"BubbleDemo",否则将会报错。但接收变量名没有限制
var BubbleDemo = am.class ( "BubbleDemo" ).extends ( am.Component ) ( {
// 在init函数返回该组件的状态数据对象
init : function () {
return {
bubbleText: "this is a component bubble"
};
},
// 组件中必须定义render函数,在该函数中指定组件的template模板和样式
render : function () {
this.template ( "{{ bubbleText }}" )
.style ( {
span: { background: "red", fontSize: 20, padding: "10px 16px" }
// !注意:当元素选择器为符合变量命名规则时可不用引号,如上面选择span元素时。当选择器不符合变量名规则时需使用引号,如:
// ".class-name": { fontSize: 15 }
// "span #id": { margin-top: 24 }
} );
// this.template ( templateHTML )函数中传入html字符串来定义该组件的视图
// this.style ( styleObj )函数为该组件的视图定义样式,这些样式也只作用于组件视图
// 需注意的是该函数传入一个对象,对象属性名为css选择器语法,值为css样式对象,样式名也是使用驼峰式表示,样式值为量值时可直接写为数字
}
} );
在一个模块中使用 组件衍生类 渲染组件视图也是非常简单的,首先在am.startRouter函数中配置组件加载的baseURL:
am.startRouter ( { baseURL : { // ... // 为组件文件设置base路径,所有的组件文件请求路径都将基于“/component”目录,不设置时默认“/” component: "/component" }, // ... } );
然后在需要使用的模块或组件中通过import函数引入,并在中通过自动以标签名来使用组件
组件生命周期
与模块生命周期阶段数一样,一个组件从创建到卸载也分为5个阶段的生命周期,具体如下:
init:组件初始化时触发,它返回组件模板解析与挂载所使用的状态数据。init函数内可调用this.propsType函数进行props参数验证。
props相关知识将在本章节的后面部分介绍
render:渲染组件视图时触发,该生命周期函数内可分别调用this.template函数定义视图标签的字符串,和this.style函数为组件视图添加样式
mounted:解析并挂载状态数据到组件视图后触发,你可以在此函数中处理一些视图解析完成后的操作,如为此组件请求网络数据并更新到模板等
updated:当组件在页面中的位置改变时触发,在组件上使用:for指令时将会渲染多个组件,此时改变:for指令所绑定的状态数组时将可能改变组件的位置
unmount:组件卸载时触发,有两种情况将会卸载组件:
①. 通过:for指令渲染多个组件视图后,调用绑定的状态数组的变异函数都可能在页面上卸载一个或多个组件;
②. 当一个模块或组件被卸载时,该模块或组件中的组件也将会卸载。
我们已经知道组件是一个拥有特定功能的封装块,所以它会有自己特定的 组件行为 ,如Dialog组件有打开和关闭行为,轮播图组件有翻页行为等。你可以这样定义 组件行为 :
var Dialog = am.class ( "Dialog" ).extends ( am.Component ) ( { init : function () { return { open: false, text: "" }; }, render : function () { this.template ( [ "# 组件行为的两种使用方法", "{{ text }}", "" ].join ( "" ) ); }, // 添加action成员函数,该函数返回组件行为的函数集合对象,该对象被称为组件行为对象 // action函数的this指针也是指向该组件对象本身 action : function () { var _this = this; return { // 组件行为函数的this指针不会指向任何值 // 通过state.open来控制Dialog视图的隐藏与显示 open: function ( text ) { _this.state.text = text; _this.state.open = true; }, close: function () { _this.state.open = false; } }; } } );
[1]在组件的生命周期函数mounted、update和unmount中可通过this.action使用组件行为对象;
[2]在组件元素上使用:ref指令,调用module.refs函数获取组件引用时将返回该组件的组件行为对象。
嵌套组件组件与组件之间配合使用可以发挥更强大的组件能力,在一个组件的模板中可以嵌套其他组件,你可以这样写:
// ComponentB组件依赖ComponentA组件 // ComponentA组件的编写与普通组件编写相同,这里省略 var CompoenntB = am.class ( "CompoenntB" ).extends ( am.Component ) ( { // 在构造函数中通过this.depComponents来指定该组件的依赖组件数组 constructor : function () { // 和ES6的class关键字定义类一样,在构造函数中需首先调用super()函数,否则将会抛出错误 this.__super (); this.depComponents = [ ComponentA ]; }, init : function () { ... }, render : function () { this.template ( "" ); } } );
当ComponentA和ComponentB组件都编写在多带带的文件中时,你需要在模块中同时引入 组件 及 嵌套组件 ,像这样:
...组件与组件、组件与模块之间的通信
组件作为一个多带带的封装块,它必须与其他组件或模块进行通信,你可以在模块中分发数据到不同组件,也可以在组件中分发数据到嵌套组件中。在组件中可以使用props进行数据的通信,使用subElements进行html模板块分发。
# 使用props传递静态值# 使用props传递动态值
props还支持使用插值表达式的方式传递状态数据,这被称为 动态props 。动态props将创建一个对外部状态数据的代理属性,当在组件内更改了此代理属性时,外部对应的状态数据也将同步更新。如下:
在使用Dialog组件的视图中,将状态属性text传入组件后,组件的this.props.text即为该状态属性的代理属性。
在Dialog组件的代码中,可通过this.props.text获取外部传递的text状态属性。
am.class ( "Dialog" ).extends ( am.Component ) ( { init : function () { return { // 使用text1接收并使用this.props.text的值 text1: this.props.text, // 如果你希望更新外部的text属性后,组件视图中挂载了this.props.text数据的地方也同步更新, // 你可以在组件中创建一个计算属性作为this.props.text的代理,如下创建的text2计算属性: computed: { var _this = this; text2: { get: function () { return _this.props.text; }, set: function ( newVal ) { _this.props.text = newVal; } } // 因为组件内对this.props.text的值更新后,外部的text状态属性也会同步更新,反之也成立 // 这样在组件视图中挂载text2就等于挂载props.text // 此时需注意的是,更改text2的值也将同步更改外部text属性的值 } }; }, // ... } );# props验证
当你希望开放你所编写的组件给其他开发者使用时,你不确定其他开发者传入的props参数是否符合组件内的处理要求,此时你可以为你的组件设置props数据验证,你可以在组件的init函数内调用this.propsType函数进行验证:
am.class ( "Dialog" ).extends ( am.Component ) ( { init : function () { // 每项值的验证都可以设置validate、require和default属性 this.propsType ( { text: { validate: String, // 表示当传入text值时它必须为字符串 require: true, // 表示text参数为必须传入的参数,默认为false default: "Have no message" // 表示不传入text参数时的默认值,默认值不会参与props验证,不指定default时无默认值 // validate的值可以有四种类型的参数,分别为: // ①. 基础数据构造函数,分别有String、Number、Boolean三种基本数据类型构造函数,Function、Object、Array三种引用类型构造函数, // 以及undefined和null,它表示允许传入的数据类型 // ②. 正则表达式,如/^1d{10}$/表示只允许传入一个手机号码 // ③. 函数,它接收此props参数值,必须返回true或false表示是否通过验证,如: // function ( text ) { return text.length > 5 } // ④. 数组,数组内是以上三种值的组合,通过数组内任意一项验证都可以通过,相当于“||”运算符 } // 当text属性验证只要设置validate属性时,可直接如下缩写: // text: String } ); return { text: this.props.text }; }, // ... } );使用subElements分发html片段
如果你想开发一个更加通用的Dialog组件,你应该不希望Dialog的视图布局是固定不变的,而是可以根据不同的需求自定义Dialog视图,因为这样才显得更加灵活多变,组件的subElements就是用来解决这个问题的,它可以使你从组件外部传入html片段与组件视图混合:
然后在组件内通过subElements属性获取外部传递的视图,并插入到组件视图中的任意位置。subElement接收的视图可分为 默认subElements 、 subElements的单数分块 和 subElements的不定数分块 三种形式。
# 默认subElements在组件元素中传入html片段时,组件内将会创建一个默认的subElements局部变量,你可以在组件内的模板中通过{{ subElements.default }}插入此html片段:
am.class ( "Dialog" ).extends ( am.Component ) ( { init : function () { ... }, render : function () { // {{ subElements.default }}将会输出外部传入的“this is external HTML template” this.template ( "{{ subElements.default }}" ); } // ... } );
Dialog组件将会被渲染成:
this is external HTML template
【注意】分发的html片段也可以使用模板指令与组件,此html片段解析时挂载的数据来源是组件外部的状态数据,如下:
# subElements的单数分块
如果你希望开发的Dialog分为头部和内容两部分视图,再混合到组件模板的不同位置,subElements也允许你这样编写html片段:
am.class ( "Dialog" ).extends ( am.Component ) ( { init : function () { ... }, render : function () { // 指定分块的组件子元素名 // 组件子元素名也需遵循首字母大写的驼峰式规则,在组件元素内使用时也是全部小写的中划线式规范 this.subElements ( "Header", "Content" ) .template ( [ "", "" ].join ( "" ) ); //{{ subElements.Header }}", "{{ subElements.Content }}", "、 两个子元素只能作为
此时Dialog组件将会被渲染成:
this is a titlethis is external HTML template
【注意】①. 如没有在this.subElements函数中定义相应的组件子元素时,Amaple只会将它们作为普通dom元素对待。# subElements的不定数分块
②. 除、 外的其他html片段会自动包含在subElements.default中。
subElements的分块分发可能会让你想到很多原生的元素,如 在组件中这样定义不定数分块的subElements: 继续学习下一节:【AmapleJS教程】5. 插件 文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。 转载请注明本文地址:https://www.ucloud.cn/yun/92717.html 摘要:体验优先的单页框架点此查看仓库是专为单页应用而设计的基于页面模块化的框架,它可使开发者快速开发单页应用。使用前置要求此框架的使用者可不需了解构建工具,但必须掌握和的基础知识。
showImg(https://segmentfault.com/img/bV2wO3?w=792&h=303);
Amaple · 体验优先的JavaScript单页框架
Amaple (点此查看Github仓... 摘要:体验优先的单页框架点此查看仓库是专为单页应用而设计的基于页面模块化的框架,它可使开发者快速开发单页应用。使用前置要求此框架的使用者可不需了解构建工具,但必须掌握和的基础知识。
showImg(https://segmentfault.com/img/bV2wO3?w=792&h=303);
Amaple · 体验优先的JavaScript单页框架
Amaple (点此查看Github仓... 摘要:体验优先的单页框架点此查看仓库是专为单页应用而设计的基于页面模块化的框架,它可使开发者快速开发单页应用。使用前置要求此框架的使用者可不需了解构建工具,但必须掌握和的基础知识。
showImg(https://segmentfault.com/img/bV2wO3?w=792&h=303);
Amaple · 体验优先的JavaScript单页框架
Amaple (点此查看Github仓... 摘要:参数为循环遍历时的回调函数,它分别接收遍历项的值遍历下表遍历变量本身三个参数,当回调函数返回时将结束本次循环,而且此时执行结束后也将会返回一个,这在结束多层循环遍历时很有用,开发者可以通过再次推出上层循环。
Amaple 拥有非常强大插件功能,这也是它的突出功能之一,Amaple插件一般表现为功能块(函数)或功能块(包含一系列函数和属性的Object对象),它除了支持Amaple规范... 阅读 1397·2021-10-08 10:04 阅读 710·2021-09-07 09:58 阅读 2893·2019-08-30 15:55 阅读 2382·2019-08-29 17:21 阅读 2109·2019-08-28 18:04 阅读 3058·2019-08-28 17:57 阅读 699·2019-08-26 11:46 阅读 2200·2019-08-23 17:20和、和、
和
等,他们都属于包含与被包含的关系,但你会发现其实 中可以定义一个或多个,在subElements中你也可以定义一个 组件子元素 的不定数分块,如Grid组件(网格)可包含不定个数的GridItem:
am.class ( "Grid" ).extends ( am.Component ) ( {
init : function () { ... },
render : function () {
this.subElements ( { elem: "GridItem", multiple: true } )
.template ( [
"
",
"
"
].join ( "" ) )
.style ( ... );
// 此时局部变量subElements.GridItem为一个包含所有GridItem分块片段的数组,在组件内使用:for指令循环输出,
// 也可以使用数组索引如subElements.GridItem [ 0 ]
// 其实上面定义单数分块的Header的全写是{ elem: "Header", multiple: false },但它可缩写为"Header"
}
// ...
} );
也可回顾上一节:【AmapleJS教程】3. 模板指令与状态数据(state)相关文章
Amaple.js框架详细介绍
Amaple.js框架详细介绍
Amaple.js框架详细介绍
【Amaple教程】5. 插件
发表评论
0条评论
flyer_dev
男|高级讲师
TA的文章
阅读更多
FaceBook 遭遇有史以来全球最大宕机
git仓库合并分支指南-简单易懂
web移动端与Hybird开发知识整理
从零开始学习vue
CSS编码规范
详述css中的百分比值
NPM酷库047:ini,解析INI配置文件
「读懂源码系列3」lodash 是如何实现深拷贝的(上)