开发一个JS FA应用
本章节主要介绍如何开发一个JS FA应用。此应用相对于上一节的Hello World应用模板具备更复杂的页面布局、页面样式和页面逻辑。该应用通过media query同时适配了手机和TV,通过点击或者将焦点移动到食物的缩略图来选择不同的食物图片,也可以进行添加到购物车操作,应用效果图如下。
图1 手机应用效果图
图2 TV应用效果图
构建页面布局
开发者在index.hml文件中构建页面布局。在进行代码开发之前,首先要对页面布局进行分析,将页面分解为不同的部分,用容器组件来承载。根据JS FA应用效果图,此页面一共分成三个部分:标题区、展示区和详情区。值得关注的是,展示区和详情区在手机和TV上分别是按列排列和按行排列。
标题区较为简单,由两个按列排列的text组件构成。展示区由包含了四个image组件的swiper组件构成,详情区由image组件和text组件构成,具体构成如下(以手机效果图为例):
图3 展示区和详情区布局
根据布局结构的分析,实现页面基础布局的代码示例如下(其中四个image组件是通过for指令来循环创建):
<!-- index.hml --><div class="container"> <!-- title area --> <div class="title"> <text class="name">Food</text> <text class="sub-title">Choose What You Like</text> </div> <div class="display-style"> <!-- display area --> <swiper id="swiperImage" class="swiper-style"> <image src="{{$item}}" class="image-mode" focusable="true" for="{{imageList}}"></image> </swiper> <!-- product details area --> <div class="container"> <div class="selection-bar-container"> <div class="selection-bar"> <image src="{{$item}}" class="option-mode" onfocus="swipeToIndex({{$idx}})" onclick="swipeToIndex({{$idx}})" for="{{imageList}}"></image> </div> </div> <div class="description-first-paragraph"> <text class="description">{{descriptionFirstParagraph}}</text> </div> <div class="cart"> <text class="{{cartStyle}}" onclick="addCart" onfocus="getFocus" onblur="lostFocus" focusable="true">{{cartText}}</text> </div> </div> </div></div>
说明
swiper组件里展示的图片需要开发者自行添加图片资源,放置到“js > default > common”目录下,common目录需自行创建,详细的目录结构见目录结构。
构建页面样式
index.css文件中通过media query管控手机和TV不同页面样式,具体用法可参考媒体查询。此外,该页面样式还采用了css伪类的写法,当点击时或者焦点移动到image组件上,image组件由半透明变成不透明,以此来实现选中的效果。
.container { flex-direction: column;}/* tv */@media screen and (device-type: tv) { .title { align-items:flex-start; flex-direction: column; padding-left: 60px; padding-right: 160px; margin-top:15px; }
.name { font-size: 20px; }
.sub-title { font-size: 15px; color: #7a787d; margin-top: 10px; }
.swiper-style { height: 300px; width: 350px; indicator-color: #4682b4; indicator-selected-color: #f0e68c; indicator-size: 10px; margin-left: 50px; }
.image-mode { object-fit: contain; }
.selection-bar { flex-direction: row; align-content: center; margin-top: 20px; margin-left: 10px; }
.option-mode { height: 40px; width: 40px; margin-left: 50px; opacity: 0.5; border-radius: 20px; }
.option-mode:focus { opacity: 1; }
.description-first-paragraph { padding-left: 60px; padding-right: 60px; padding-top: 30px; }
.description { color: #7a787d; font-size: 15px; }
.cart { padding-left: 60px; margin-top: 30px; }
.cart-text { font-size: 20px; text-align: center; width: 300px; height: 50px; background-color: #6495ed; color: white; }
.cart-text-focus { font-size: 20px; text-align: center; width: 300px; height: 50px; background-color: #4169e1; color: white; }
.add-cart-text { font-size: 20px; text-align: center; width: 300px; height: 50px; background-color: #ffd700; color: white; }}
/* phone */@media screen and (device-type: phone) { .title { align-items:flex-start; flex-direction: column; padding-left: 60px; padding-right: 160px; padding-top: 20px; }
.name { font-size: 50px; color: #000000; }
.sub-title { font-size: 30px; color: #7a787d; margin-top: 10px; }
.display-style { flex-direction: column; align-items:center; }
.swiper-style { height: 600px; indicator-color: #4682b4; indicator-selected-color: #ffffff; indicator-size: 20px; margin-top: 15px; }
.image-mode { object-fit: contain; }
.selection-bar-container { height: 90px; justify-content: center; }
.selection-bar { height: 90px; width: 500px; margin-top: 30px; justify-content: center; align-items:center; }
.option-mode { object-fit: contain; opacity: 0.5; }
.option-mode:active { opacity: 1; }
.description { color: #7a787d; }
.description-first-paragraph { padding-left: 60px; padding-top: 50px; padding-right: 60px; }
.color-column { flex-direction: row; align-content: center; margin-top: 20px; }
.color-item { height: 50px; width: 50px; margin-left: 50px; padding-left: 10px; }
.cart { justify-content: center; margin-top: 30px; }
.cart-text { font-size: 35px; text-align: center; width: 600px; height: 100px; background-color: #6495ed; color: white; }
.add-cart-text { font-size: 35px; text-align: center; width: 600px; height: 100px; background-color: #ffd700; color: white; }}
构建页面逻辑
开发者在index.js文件中构建页面逻辑,主要实现的是两个逻辑功能:
- 当点击时或者焦点移动到不同的缩略图,swiper滑动到相应的图片;
- 当焦点移动到购物车区时,“Add To Cart”背景颜色从浅蓝变成深蓝,点击后文字变化为“Cart + 1”,背景颜色由深蓝色变成黄色。添加购物车不可重复操作。
逻辑页面代码示例如下:
// index.jsexport default { data: { cartText: 'Add To Cart', cartStyle: 'cart-text', isCartEmpty: true, descriptionFirstParagraph: 'This is a food page containing fresh fruits, snacks and etc. You can pick whatever you like and add it to your cart. Your order will arrive within 48 hours. We guarantee that our food is organic and healthy. Feel free to access our 24h online service for more information about our platform and products.', imageList: ['/common/food_000.JPG', '/common/food_001.JPG', '/common/food_002.JPG', '/common/food_003.JPG'], },
swipeToIndex(index) { this.$element('swiperImage').swipeTo({index: index}); },
addCart() { if (this.isCartEmpty) { this.cartText = 'Cart + 1'; this.cartStyle = 'add-cart-text'; this.isCartEmpty = false; } },
getFocus() { if (this.isCartEmpty) { this.cartStyle = 'cart-text-focus'; } },
lostFocus() { if (this.isCartEmpty) { this.cartStyle = 'cart-text'; } },}
配置设备类型
在config.json的"deviceType"字段中添加手机和TV的设备类型:
{ ... "module": { ... "deviceType": [ "phone", "tv" ], ... }}
效果示例
实现此实例后,效果示例如下图所示。
图4 手机运行效果
图5 TV运行效果
相关实例
开发一个JS FA应用,有以下示例工程可供参考:
JsApp
本示例演示了如何开发一个 JS FA。
JsGallery
本示例为一个仿图库的JS应用,模拟多图片场景,开发者可自行添加或者更换图片资源,构建自己的多图场景。
JsShopping
本示例为一个仿购物类的JS应用,使用了混合的布局,包含图片、视频、文本等资源。