前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WeChat 模块、模板与缓存

WeChat 模块、模板与缓存

作者头像
Nian糕
修改2024-03-19 14:07:57
1.2K0
修改2024-03-19 14:07:57
举报
Unsplash
Unsplash

本次的系列博文的知识点讲解和代码,主要是来自于 七月老师 的书籍《微信小程序开发:入门与实践》,由个人总结并编写,关于更多微信小程序开发中的各项技能,以及常见问题的解决方案,还请大家购买书籍进行学习实践,该系列博文的发布已得到七月老师的授权许可

授权许可
授权许可

我们在 WeChat 文章列表页面(二) 中,已经完成了数据的绑定和页面的跳转了,效果图如下所示

文章列表页面
文章列表页面

模块

我们先把所有文章的数据分离到一个单独的 js 文件中,防止污染我们的业务层,在根目录下新建一个文件夹,命名为 data,在 data 文件夹下新建一个 js 文件,命名为 data.js,并将原来复杂对象的数据绑定修改成简单的字符串

代码语言:javascript
复制
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: 0,
      collectionNum: 0,
      commentNum: 0
    },
    {
      date: "Jan 9 2017",
      title: "从童年呼啸而过的火车",
      postImg: "/images/post/post-5.jpg",
      avatar: "/images/avatar/avatar-1.png",
      content: "小时候,家的后面有一条铁路。听说从南方北上的火车都必须经过这条铁路。火车大多在晚上经过,但也不定时只有在夜深人静的时候,火车的声音才能从远方传来...",
      readingNum: 0,
      collectionNum: 0,
      commentNum: 0
    },
    {
      date: "Jan 29 2017",
      title: "记忆里的春节",
      postImg: "/images/post/post-1.jpg",
      avatar: "/images/avatar/avatar-3.png",
      content: "年少时,有几样东西,是春节里必不可少的:烟花、心意、凉茶、压岁钱、饺子。年分大小年,有的地方是腊月二十三过小年,有的地方是腊月二十四...",
      readingNum: 0,
      collectionNum: 0,
      commentNum: 0
    },
  ]

我们提取的数据文件 data.js 可以视作是小程序的一个模块,若是想让其他文件访问这个模块,还需要使用 module.exports 向外部暴露一个接口,在 data.js 文件的最下方添加以下代码:

代码语言:javascript
复制
module.exports = {
    postList:postList
}

定义好模块后,我们还需要在 post.js 中引入 data.js 这个模块

代码语言:javascript
复制
var dataObj = require("../../data/data.js");

Page({
  data: {

  },
  onLoad:function(){
    this.setData({
      postList: dataObj.postList
    })
  }
})

在这里使用 require(path) 引用 js 模块时,要特别注意以下几点:

  • 被引用的文件一定要带有扩展名 js,这一点是不同于页面路径的
  • path 路径不可以使用绝对路径,否则会报错,应使用相对路径
  • 在 JavaScript 文件中声明的变量和函数只在该文件中有效,不同的文件中可以声明相同名字的变量和函数,不会相互影响

最后,记得调整 post.wxml 中 {{}} 的语法,在这里就不再演示了

模板

我们在文章列表里使用了列表渲染,但如果其他页面同样需要显示文章列表该怎么办呢?通常情况下,我们会考虑把一些公共的、经常使用的业务逻辑提取成一个公共函数,当在多个地方需要使用函数时,只需要调用这个函数即可完成相应的业务

而小程序也提供了一个称作模板的技术来支持对 wxml 组件的封装,但这种封装仅仅只是 wxml 的代码片段,并不像 AngularJS 中可以把 HTML、JS 作为一个整体被封装起来

要使用模板,首先需要新建模板文件,在 /pages/post 下新建目录 post-item,作为模板文件目录,并在该目录下新建 2 个文件:post-item-tpl.wxml 和 post-item-tpl.wxss 文件

使用模板是为了简化 post.wxml 中文章的写法,让文章可以成为一个单独的“组件”,供其他多个地方使用,就像是一个简单的 image 组件就可以实现图片的显示功能

接下来,我们把 post.wxml 中 <block> 标签中关于文章的代码剪切到 post-item-tpl.wxml 中,让这段代码成为一个可复用的“组件”

代码语言:javascript
复制
<template name="postItemTpl">
    <view class="post-container">
      <view class="post-author-date">
        <image src="{{item.avatar}}" />
        <text>{{item.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" />
        <text>{{item.collectionNum}}</text>
        <image src="/images/icon/wx_app_view.png" />
        <text>{{item.readingNum}}</text>
        <image src="/images/icon/wx_app_message.png" />
        <text>{{item.commentNum}}</text>
      </view>
    </view>
</template>

template 模板相关的内容必须被包裹在 <template></tenplate> 标签中,使用 name 属性指定 template 模板的模板名,这个模板名将在引用模板时被使用

接下来,我们在 post.wxml 中引用并使用这个 template

代码语言:javascript
复制
<import src="post-item/post-item-tpl.wxml" />
<view>
  <swiper indicator-dots="true" autoplay="true" interval="5000" circular="true">
    <swiper-item>
      <image src="/images/post/post-1@text.jpg" />
    </swiper-item>
    <swiper-item>
      <image src="/images/post/post-2@text.jpg" />
    </swiper-item>
    <swiper-item>
      <image src="/images/post/post-3@text.jpg" />
    </swiper-item>
  </swiper>
  <block wx:for="{{postList}}" wx:for-index="idx" wx:for-item="item">
      <template is="postItemTpl" data="{{item}}" />
  </block>
</view>
运行结果
运行结果

可以看到,文章列表是可以正常地加载显示,在 post.wxml 的顶部使用 <import src="templatPath" /> 来引用模板,对于 templatePath 路径,这里需要注意,去掉 wxml 文章拓展名也是可以的,但官方示例中是带有 .wxml 扩展名的,所以建议开发者戴上模板文件的扩展名

引用模板后,就可以在这个页面中使用这个模板了,在需要模板的位置使用 <template> 标签引入,template 的 is 属性指定要使用哪个模板,通过 template 的 data 属性,可以向 template 传递数据,这里将 wx:for 得到的 item 传入到 template 里,这样就可以在 template 内部使用这个 item 了,这里需要注意的是,向模板里传入数据,同样要使用 {{}} 的数据绑定语法

消除 template 模板对外部变量名的依赖

在上一小节中,我们已经成功地将 wxml 代码做成了模板,同样的,我们也把 post.wxss 中同文章相关的样式作为模板“打包”起来,并在 post.wxss 文件的顶部添加如下代码:

代码语言:javascript
复制
@import "post-item/post-item-tpl.wxss";

我们之前讲过,列表渲染中 wx:for-item 可以指定数组子元素的变量名,那我们现在尝试将 wx:for-item = "item" 改成 wx:for-item = "item1",这将使得 postList 数组子元素的变量名由 item 变成 item1,此时,如果要将数据传入到 postItemTpl 中,则应该设置 data = "{{item1}}"

运行结果
运行结果

我们做完以上变更后,却发现文章数据将消失了,而之前代码可以正常运行是因为我们向 template 传入的变量名 data = "{{item}}",恰好和 template 里面数据绑定的变量名 item 一样,一旦我们更改 item 为 item1 后,template 就找不到这个 item 了

template 模板并不像函数,没有提供一个定义参数名的地方,没有办法更改从外部传入的 item1 为 item,我们当然可以通过将 postItemTpl 这个 template 内部的 item 更改为 item1 来让代码重新正常运行,但这种由定义方要求调用方遵守变量名命名的做法是不太合理的,要解决这个问题,就必须消除 template 对于外部变量名的依赖,可以使用拓展运算符 ... 展开传入对象变量来消除这个问题

代码语言:javascript
复制
<block wx:for="{{postList}}" wx:for-index="idx" wx:for-item="item">
    <template is="postItemTpl" data="{{...item}}" />
</block>

接着去掉 post-item-tpl.wxml 文件中 {{}} 里所有的 item,保存运行,文章列表就可以正常显示了,{{...item}} 可以将 item 这个对象展开,展开之后再传入到 template 里,就可以保证 template 不再依赖 item 这个变量名

include 引用模板

小程序还提供了另一种引入模板的方式:include,include 在使用上同 import 有以下区别:

  • import 需要先引入 template,然后再使用 template;但 include 不需要预先引入,直接在需要的地方引入模板即可
  • include 模式非常简单,就是简单的代码替换,不存在作用域,也不能像 import 一样使用 data 传递变量
代码语言:javascript
复制
<block wx:for="{{postList}}" wx:for-index="idx" wx:for-item="item">
    <include src="post-item/post-item-tpl.wxml" />
</block>

以上代码将 block 标签中的 template 更换成了 <include>,include 同样使用 src 属性指向模板文件,需要注意的是,include 无法引入包含有 template 标签的代码,所以需要把 post-item-tpl.wxml 里的 template 标签删除,只保留文章本身的 wxml 代码,而文章数据部分,还需要再次在 post-item-tpl.wxml 中的 {{}} 加入 item 这个变量名,开发者可自行尝试

除了在使用上有所不同,include 和 import 还存在其他不同之处:import 有作用域的概念,即只会 import 目标文件中定义的 template,而不会 import 目标文件 import 的 template

如:C import B,B import A,在 C 中可以使用 B 定义的 template,在 B 中可以使用 A 定义的 template,但是 C 不能使用 A 定义的template

所以在这里建议大家,如果模板仅仅是静态 wxml,不涉及数据的传递,可以使用 include,但如果模板涉及数据绑定,还是建议使用 import

缓存

之前我们已经将文章相关数据分离到了 data.js 文件中,并在 post.js 文件里通过 require 来加载 data.js 文件,但现在有一个问题,如果我们要修改数据怎么办?修改后的数据,还想共享给其他页面使用,并长期保存这些数据怎么办?

小程序提供了一个缓存的特性,来支持数据的读取、保存和更新,并且这些数据不会因为应用程序重启或者关闭而消失

根据页面生命周期,将初始化数据装载到缓存的最好时期,应该是在小程序启动时,即执行 onLaunch 生命周期函数时,所以我们在 app.js 中加入以下代码:

代码语言:javascript
复制
var dataObj = require("data/data.js")
App({
  onLaunch:function(){
    wx.setStorage({
      key: 'postList',
      data: dataObj.postList,
      success: function(res){
        //success
      },
      fail:function(){
        //fail
      },
      complete:function(){
        //complete
      }
    })
  },
})

在上面代码中,首先通过 require 加载 data.js 文件作为初始化数据,在应用程序生命周期函数 onLaunch 里,使用 wx.setStorage 方法将初始化数据存入到小程序的缓存中

缓存使得小程序具备了本地存储数据的能力,它具有以下几个特点:

  • 只要用户不主动清除缓存,则缓存一直存在
  • 缓存以 key:value 键值对的形式存在,很类似于服务器流行的 memcache 或者 redis 缓存型数据库
  • 小程序提供了一系列 API 用来操作缓存,包括:存储、读取、移除、清除全部或获取缓存信息,每种操作同时都具有同步和异步两个方式
  • 删除某一个 key 的缓存,请使用 wx.removeStorage 方法;而如果想清除所有的缓存请使用 wx.clearStorage 方法
  • 小程序的缓存永久存在,不存在过期时间这个概念,如果想清除缓存,则需要主动调用清除缓存的 API
  • 小程序的本地缓存有容量上限,最大不允许超过 10 MB

wx.setStorage(object) 是一个异步方法,参数 object 包含 key,data 和 success、fail、complete 这 3 个通用方法(几乎所有小程序的异步 API 方法中都包含这 3 个方法),key 用来设置缓存的键,而 data 用来设置缓存的值,可以是 JavaScript 对象或者字符串

我们可以通过 Storage 面板来查看具体的变化

Storage 面板数据情况
Storage 面板数据情况

图中 postList 就是在代码中设置的 key:'postList',后面的 Array 数组就是设置的 data 对象,也就是要初始化的数据,对应的是 data.js 文件的 3 篇文章数据,Storage 面板是查看缓存的重要功能,当开发者遇到与缓存相关的问题时,请一定要到这里来看一看

同步设置缓存

同步方法 wx.setStorageSync 是在异步方法名 wx.setStorage 后加了一个后缀 “Sync”,不仅仅是 setStorage,小程序中几乎所有同步方法的方法名都是在异步方法名后增加了 “Sync”,而同步方法只接收 key 和 data 这 2 个参数,并没有 success、fail、complete 等回调方法

我们这里采取的是同步方法,开发者可以根据自己的业务和环境选取异步方法,但需要注意的是,选取异步方法会大大增加代码风险和调试难度,如果没有必要(通常是处于性能和体验的考虑),建议优先考虑同步方法

代码语言:javascript
复制
App({
  onLaunch:function(){
    var storageData = wx.getStorageSync('postList');
    if(!storageData){
      //如果postList缓存不存在
      var dataObj = require("data/data.js")
      wx.clearStorageSync();
      wx.setStorageSync('postList',dataObj.postList);
    }
  },
})

我们还在这里增加了一个缓存是否存在的判断,wx.setStorageSync(key)这个方法可以获取指定key的缓存内容,如果key的缓存不存在,则说明数据库还没有初始化,那么此时首先使用wx.clearStorageSync()清除所有的缓存数据,接着再重新读取并设置初始化数据

以上代码优化了初始化缓存数据库的方案,只有当缓存数据库不存在时,才通过require加载data.js文件,并初始化数据库,这样可以避免每次启动应用程序都重复初始化数据库

该章节的内容到这里就全部结束了,源码我已经发到了 GitHub WeChat_04 上了,有需要的同学可自行下载

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.06.09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 模块
  • 模板
  • 消除 template 模板对外部变量名的依赖
  • include 引用模板
  • 缓存
  • 同步设置缓存
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档