1.4 模块、模板与缓存
1、将文章数据从业务中分离
在根目录下新建一个data文件夹,在该文件夹下建一个data.js文件
![](https://img.haomeiwen.com/i2108792/295c1ddc7b3289a3.png)
1.1 将postList数据剪切到data.js文件中
post.js
var postList = [
{
object: {
date: "Jan 28 2017"
},
title: "小时候的冰棍儿与雪糕",
postImg: "/images/post/post-1.jpg",
avatar: "/images/avatar/avatar-1.png",
content: "冰棍与雪糕绝对不是同一个东西。3到5毛钱的雪糕犹如现在的哈根达斯,而5分1毛的冰棍儿就像现在的老冰棍。时过境迁",
readingNum: 92,
collectionNum: {
array: [108]
},
commentNum: 7
},
{
object: {
date: "Jan 28 2017"
},
title: "世界杯乌龙球",
postImg: "/images/post/post-2.jpg",
avatar: "/images/avatar/avatar-2.png",
content: "冰棍与雪糕绝对不是同一个东西。3到5毛钱的雪糕犹如现在的哈根达斯,而5分1毛的冰棍儿就像现在的老冰棍。时过境迁",
readingNum: 92,
collectionNum: {
array: [108]
},
commentNum: 7
},
{
object: {
date: "Jan 28 2017"
},
title: "端午节,跟随习近平找寻中华民族“精气神”",
postImg: "/images/post/post-3.jpg",
avatar: "/images/avatar/avatar-3.png",
content: "体现一个国家综合实力最核心的、最高层的,还是文化软实力,这事关一个民族精气神的凝聚。”习近平总书记曾在众多场合阐释中华优秀传统文化的价值与力量,深入挖掘中华优秀传统文化的时代内涵,展现对中华优秀传统文化的深刻思考。",
readingNum: 50,
collectionNum: {
array: [1000]
},
commentNum: 8
}
]
2、小程序的模块
2.1 向外部暴露模块接口
data.js
在最下面加上如下代码
module.exports = {
postList: postList
}
2.2 引入模块
post.js
在文件的开头加上如下的代码
var dataObj = require("../../data/data.js")
-
注意点
1)被引用的文件一定要带有扩展名js,这一点不同于页面路径
2)path路径不可以使用绝对路径,否则会报错,应该使用相对路径
image.png
3)在JavaScript文件中声明的变量和函数只在该文件中有效,不同文件中可以声明相同名字的变量和函数,不会相互影响
4)require只是模块化的一种方式,还可以使用ES6的Module来编写模块
3、小程序的模板化
小程序提供了一个称为模板的技术来支持wxml组件的封装,但是这种封装仅仅只是wxml的代码片段,无法将模板的业务逻辑(js)也封装起来。
新建模板文件,以tpl来结尾
![](https://img.haomeiwen.com/i2108792/476ccc10a7ef19a9.png)
3.1 编写文章模板
post-item-tpl.wxml
<template name="postItemTpl">
<view class='post-container'>
<view class='post-author-date'>
<image src='{{item.avatar}}'></image>
<text>{{item.object.date}}</text>
</view>
<text class='post-title'>{{item.title}}</text>
<image class='post-image' src='{{item.postImg}}' mode='aspectFill' />
<text class='post-content'>{{item.content}}</text>
<view class='post-like'>
<image src='/images/icon/wx_app_collect.png'></image>
<text>{{item.readingNum}}</text>
<image src='/images/icon/wx_app_view.png'></image>
<text>{{item.collectionNum.array[0]}}</text>
<image src='/images/icon/wx_app_message.png'></image>
<text>{{item.commentNum}}</text>
</view>
</view>
</template>
模板内容必须包裹在<template></template>标签内,使用name属性指定temolate模板的模板名,这个模板名在引用模板时被使用
3.2 引用并且使用postItemTpl
post.wxml
![](https://img.haomeiwen.com/i2108792/bf7c510d4f6a3813.png)
4、消除template模板对外部变量名的依赖
![](https://img.haomeiwen.com/i2108792/f561811910edaa60.png)
![](https://img.haomeiwen.com/i2108792/9e81ea26063d3d99.png)
![](https://img.haomeiwen.com/i2108792/474d89916d1d73d3.png)
传入的名字不一样,因此列表没有显示
因为template模板没有提供一个定义参数名的地方,没有办法更改从外部传入的item1为item
- 解决方法
1)手动一个个去更改模板的item为item1(不推荐)
2)消除template对于外部变量名的依赖,可以使用扩展运输符"..."展开传入对象变量来消除这个问题
使用扩展运算符展开对象
![](https://img.haomeiwen.com/i2108792/8161b1ee3c009821.png)
去掉{{}}中所有的item
![](https://img.haomeiwen.com/i2108792/dfd702a7937a3098.png)
5、include与import引用模板的区别
小程序还提供了另外一种引入模板的方式:include
5.1 区别点
1)import需要先引入template,然后在使用template;但include不需要预先引入,直接在需要的地方引入模板即可
2)include模式非常简单,就是简单的代码替换,不存在作用域;import存在作用域,可以向data传递变量。注意的是,在C import B, B import A,但是C 不能使用A定义的template
5.2 使用include引用模板的流程
![](https://img.haomeiwen.com/i2108792/d322c2d68e95d82a.png)
![](https://img.haomeiwen.com/i2108792/58085097ebd72071.png)
![](https://img.haomeiwen.com/i2108792/3370cc84b13884ef.png)
![](https://img.haomeiwen.com/i2108792/6bec6d8908ff0b6d.png)
![](https://img.haomeiwen.com/i2108792/48c460ada71f440a.png)
![](https://img.haomeiwen.com/i2108792/921cbf026f7ad0c7.png)
5.3 何时使用include?何时使用import?
如果模板时静态wxml,不涉及数据的传递,可以使用include。如果模板涉及数据绑定,还是建议使用import
6、CSS的模板化
![](https://img.haomeiwen.com/i2108792/5923591ef78d38bc.png)
post.wxss
![](https://img.haomeiwen.com/i2108792/df5b3033b6a37cae.png)
7、令人遗憾的模板化而非组件化
在组件化的编程思维里,一个前端组件必须要同时满足视图层代码的组件化和逻辑层代码的组件化。在小程序里勉强可以实现view的组件化(template模板),但是模板缺不可以实现业务逻辑js代码的组件化
8、使用缓存在本地模拟服务器数据库
小程序提供了一个非常重要的特性------缓存,来支持一些数据库CRUD的特性
8.1 应用程序的生命周期
app.js
App({
/**
* 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
*/
onLaunch: function () {
},
/**
* 当小程序启动,或从后台进入前台显示,会触发 onShow
*/
onShow: function (options) {
},
/**
* 当小程序从前台进入后台,会触发 onHide
*/
onHide: function () {
},
/**
* 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
*/
onError: function (msg) {
}
})
8.2 使用Storage缓存初始化本地数据库
app.js
var dataObj = require("data/data.js")
App({
/**
* 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
*/
onLaunch: function () {
wx.setStorage({
key: 'postList',
data: dataObj.postList,
success:function(res){
console.log("数据缓存成功")
},
fail:function(){
console.log("数据缓存失败")
},
complete:function(){
console.log("数据缓存完成")
}
})
},
})
![](https://img.haomeiwen.com/i2108792/281c06cdaf9d79be.png)
![](https://img.haomeiwen.com/i2108792/a37c7409d29113cc.png)
- 什么是缓存?
缓存让小程序具备了本地存储数据的能力,它有如下几个特点:
1)只要用户不主动清除缓存,则缓存一直存在
2)缓存以key-value键值对的形式存在
3)小程序提供了一系列的API来操作缓存,包括:存储、读取、移除、清除全部和获取缓存信息。每种操作同时都具备同步和异步两个方法。
4)请注意移除和清除的区别。删除某一个key的缓存,请使用wx.removeStorage方法;清除所有的缓存请使用wx.clearStorage方法
5)小程序的缓存永久存在,不存在过期时间概念。如果想清除缓存,则需要主动调用清除缓存的API
6)小程序的本地缓存有容量上限,最大不允许超过10MB
8.2.1 同步设置缓存
开发者可以根据自己的业务和环境选取异步方法,不过要注意的是,异步方法会大大增加代码风险率和调试难度,如果没有必要(通常是处于性能和体验的考虑),优先考虑同步方法
app.js
var dataObj = require("data/data.js")
App({
/**
* 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
*/
onLaunch: function () {
wx.setStorageSync("postList", dataObj.postList)
},
})
8.2.2 优化缓存初始化判断
app.js
App({
/**
* 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
*/
onLaunch: function () {
var storageData = wx.getStorageSync("postList");
if (!storageData){
console.log("缓存不存在,可以加载到缓存中")
var dataObj = require("data/data.js")
wx.clearStorageSync();
wx.setStorageSync("postList", dataObj.postList)
}else{
console.log("缓存存在,不用重新加载")
}
},
})
跑两次程序可以看到控制的输出
![](https://img.haomeiwen.com/i2108792/5ff1b94e83e02904.png)
![](https://img.haomeiwen.com/i2108792/daf6593aa9bb5f3a.png)
8.3 缓存的强制清理及注意事项
![](https://img.haomeiwen.com/i2108792/e1a1a19480c5b721.png)
注意点:在开发阶段,不要做是否有缓存的判断,每次应用程序重启都应该强制更新一次初始化数据,从而保证数据一直是最新状态
9、 编写缓存数据库操作类
使用prototype来编写缓存数据库的操作类
9.1 prototype构建数据操作类
![](https://img.haomeiwen.com/i2108792/64b1ea14229fcac9.png)
DBPost.js
var DBPost = function(){
//所有的文章本地缓存存储键值
this.storageKeyName = "postList";
}
DBPost.prototype = {
//得到全部文章信息
getAllPostData:function(){
var res = wx.getStorageSync(this.storageKeyName);
if(!res){
res = require("../data/data.js").postList;
this.execSetStorageSync(res);
}
return res;
},
//本地缓存 保存/更新
execSetStorageSync:function(data){
wx.setStorageSync(this.storageKeyName,data);
}
};
module.exports = {
DBPost: DBPost
};
10、 使用缓存数据库操作类
10.1 使用DBPost
![](https://img.haomeiwen.com/i2108792/9581d7c1125adb8c.png)
11、 使用ES6改写缓存操作类
使用ES6的新特性Class 、Module来改写缓存操作类
11.1 用ES6改写DBPost
DBPost.js
class DBPost{
constructor(url){
this.storageKeyName = "postList";
}
//得到全部文章信息
getAllPostData() {
var res = wx.getStorageSync(this.storageKeyName);
if (!res) {
res = require("../data/data.js").postList;
this.initPostList(res);
}
return res;
}
//本地缓存 保存/更新
execSetStorageSync(data) {
wx.setStorageSync(this.storageKeyName, data);
}
};
export { DBPost}
11.2 使用ES6版本的DBPost
post.js
import{DBPost} from '../../db/DBPost.js';
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
var dbPost = new DBPost();
this.setData({
postList: dbPost.getAllPostData()
});
},
})
12、完整的data.js数据
data.js
var postList = [{
date: "Jan 28 2017",
title: "小时候的冰棍儿与雪糕",
postImg: "/images/post/post-4.jpg",
avatar: "/images/avatar/avatar-5.png",
content: "冰棍与雪糕绝对不是同一个东西。3到5毛钱的雪糕犹如现在的哈根达斯,而5分1毛的 冰棍儿就像现在的老冰棒。时过境迁,...",
readingNum: 23,
collectionNum: 3,
commentNum: 0,
author: "林白衣",
dateTime: "24小时前",
detail: "冰棍与雪糕绝对不是同一个东西。3到5毛钱的雪糕犹如现在的哈根达斯,而5分1毛的 冰棍儿就像现在的老冰棒。时过境迁,当年的老冰棍也随着童年的记忆消失不见踪影。记得小时候,每当傍晚时分,总有一个老人推着一辆小车,小车的后架上放着一个大大的白色泡沫盒子。老人一边推着车,一边叫喊着:雪糕、冰棍...",
postId: 1,
music: {
url: "http://ws.stream.qqmusic.qq.com/C100001Dc80Z3qPj2Z.m4a?fromtag=38",
title: "罗大佑 恋曲1980",
coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000003cWU1M2qNwxZ.jpg?max_age=2592000",
},
collectionStatus: true,
upStatus: false,
upNum: 11,
comments: []
},
{
date: "Jan 9 2017",
title: "从童年呼啸而过的火车",
postImg: "/images/post/post-5.jpg",
avatar: "/images/avatar/avatar-1.png",
content: "小时候,家的后面有一条铁路。听说从南方北上的火车都必须经过这条铁路。火车大多在晚上经过,但也不定是只有在夜深人静的时候,火车的声音才能从远方传来...",
readingNum: 96,
collectionNum: 7,
commentNum: 4,
author: "林白衣",
dateTime: "24小时前",
detail: "小时候,家的后面有一条铁路。听说从南方北上的火车都必须经过这条铁路。火车大多在晚上经过,可呜呜的汽笛声,往往却被淹没在傍晚小院儿里散步的人群声中。只有在夜深人静的时候,火车的声音才能清晰的从远处飘过来。虽然日日听见火车的汽笛声,可说也奇怪,我竟从来不知道铁路在哪里。在每个夏日午后,我都会有一种去找寻找铁路的冲动,去看看这条铁路究竟是从哪里来,又将通向哪里去",
postId: 2,
music: {
url: "http://ws.stream.qqmusic.qq.com/C100004VybKS2SpZVL.m4a?fromtag=38",
title: "齐秦 原来的我",
coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000003ZvAeK2PgA4Y.jpg?max_age=2592000"
},
collectionStatus: true,
upStatus: true,
upNum: 22,
comments: [
{
username: '青石',
avatar: '/images/avatar/avatar-3.png',
create_time: '1484723344',
content: {
txt: ' 那一年的毕业季,我们挥挥手,来不及说再见,就踏上了远行的火车。',
img: ["/images/comment/train-1.jpg", "/images/comment/train-2.jpg", "/images/comment/train-3.jpg"],
audio: null
}
}, {
username: '水清',
avatar: '/images/avatar/avatar-2.png',
create_time: '1481018319',
content: {
txt: '夏日的蝉鸣与夜晚的火车,时长会在未来无数的日子里不断的在我耳边响起,难以忘怀',
img: [],
audio: null,
}
},
{
username: '赤墨',
avatar: '/images/avatar/avatar-1.png',
create_time: '1484496000',
content: {
txt: '时光的湮染,自然的吞噬,让太多的老火车站也消失得无影无踪',
img: ["/images/comment/train-4.jpg",],
audio: null,
}
},
{
username: '林白',
avatar: '/images/avatar/avatar-4.png',
create_time: '1484582400',
content: {
txt: '',
img: [],
audio: { url: "http://123", timeLen: 8 },
}
}
]
},
{
date: "Jan 29 2017",
title: "记忆里的春节",
postImg: "/images/post/post-1.jpg",
avatar: "/images/avatar/avatar-3.png",
content: "年少时,有几样东西,是春节里必不可少的:烟花、新衣、凉菜、压岁钱、饺子。年分大小年,有的地方是腊月二十三过小年,而有的地方是腊月二十四...",
readingNum: 56,
collectionNum: 6,
commentNum: 0,
author: "林白衣",
dateTime: "24小时前",
detail: "年少时,有几样东西,是春节里必不可少的:烟花、新衣、凉菜、压岁钱、饺子。年分大小年,有的地方是腊月二十三过小年,而有的地方是腊月二十四。童年的春节都是在小县城里度过,那时候的冬天还很冷,池塘的水会结冰,房屋上总是倒挂着一条条的冰棱,菜地里的白菜被厚厚的积雪覆盖着,只露出一小撮白绿相间的菜头,而茎部,竟然像是没有了一般...",
postId: 3,
music: {
url: "http://ws.stream.qqmusic.qq.com/C100003XYcCu3IZKLc.m4a?fromtag=38",
title: "老狼 虎口脱险",
coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000002sNbWp3royJG.jpg?max_age=2592000"
},
collectionStatus: false,
upStatus: false,
upNum: 9,
comments: []
},
{
date: "Sep 22 2016",
title: "换个角度,再来看看微信小程序的开发与发展",
postImg: "/images/post/post-2.jpg",
avatar: "/images/avatar/avatar-2.png",
content: "前段时间看完了雨果奖中短篇获奖小说《北京折叠》。很有意思的是,张小龙最近也要把应用折叠到微信里,这些应用被他称为:小程序...",
readingNum: 0,
collectionNum: 0,
commentNum: 0,
author: "林白衣",
dateTime: "24小时前",
detail: "我们先举个例子来直观感受下小程序和APP有什么不同。大家都用过支付宝,在其内部包含着很多小的服务:手机充值、城市服务、生活缴费、信用卡还款、加油服务,吧啦吧啦一大堆服务。这些细小的、功能单一的服务放在支付宝这个超级App里,你并不觉得有什么问题,而且用起来也很方便。那如果这些小的应用都单独拿出来,成为一个独立的App",
postId: 4,
music: {
url: "http://ws.stream.qqmusic.qq.com/C100003z8cOo0Bs7zP.m4a?fromtag=38",
title: "吴奇隆 祝你一路顺风",
coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000000n6a7p2HIPqU.jpg?max_age=2592000"
},
collectionStatus: false,
upStatus: true,
upNum: 9,
comments: []
},
{
date: "Jan 29 2017",
title: "2017 微信公开课Pro",
postImg: "/images/post/post-3.jpg",
avatar: "/images/avatar/avatar-4.png",
content: "在今天举行的2017微信公开课PRO版上,微信事业群总裁张小龙宣布,微信“小程序”将于1月9日正式上线。",
readingNum: 32,
collectionNum: 2,
commentNum: 0,
author: "林白衣",
dateTime: "24小时前",
detail: "在今天举行的2017微信公开课PRO版上,微信宣布,微信“小程序”将于1月9日正式上线,公布了几乎完整的小程序生态模式:微信里没有小程序入口、没有应用市场,分发模式几乎沿用公众号的模式,去中心化,限制搜索的能力,大多数小程序不能支持模糊搜索,必须输入完整的小程序名称...",
postId: 5,
music: {
url: "http://ws.stream.qqmusic.qq.com/C100004K7D5E2xhv9v.m4a?fromtag=38",
title: "杨千嬅 再见二丁目(live)",
coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000000ptb8p0ZIxDP.jpg?max_age=2592000",
},
collectionStatus: false,
upStatus: false,
upNum: 2,
comments: []
},
]
module.exports = {
postList: postList
}
![](https://img.haomeiwen.com/i2108792/cb60fd6fdc7d3067.png)