1 uni-app 介绍
1.1 什么是uni-app
uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到 Android、iOS、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
uni-app官网 提供了一个快速体验的页面,编写了一套代码并部署到15个平台,可以到 这里 获取二维码并扫码体验。
1.2 uni-app 的由来
以下内容摘抄自 uni-app 官网介绍页面 “uni-app的由来”
uni,读
you ni
,是统一的意思。很多人以为小程序是微信先推出的,其实,DCloud才是这个行业的开创者。
DCloud于2012年开始研发小程序技术,优化webview的功能和性能,并加入W3C和HTML5中国产业联盟,推出了HBuilder开发工具,为后续产业化做准备。
2015年,DCloud正式商用了自己的小程序,产品名为“流应用”,它不是
B/S
模式的轻应用,而是能接近原生功能、性能的App,并且即点即用,第一次使用时可以做到边下载边使用。为将该技术发扬光大,DCloud将技术标准捐献给工信部旗下的HTML5中国产业联盟,并推进各家流量巨头接入该标准,开展小程序业务。
1.3 如何学习
1.3.1 学前须知
uni-app 是基于 Vue.js
的一个前端开发框架:
学习 uni-app 的基本要求是:已经掌握了HTML、CSS3和JavaScript 的编程。
由于 uni-app 完全继承了 vue 的语法,所以本学期学习的所有页面功能代码,其编程思想都是基于 vue 以及原生 JavaScript 的。
1.3.2 入门文档
uni-app 官网提供了一篇 “白话uni-app” 的文档帮助具有一定 H5 的基础,但是不熟悉 vue 和小程序的开发者来入门 uni-app。
【阅读须知】:
这篇文档很长,但不难。从这篇文档里可以看到一条比较清晰的 uni-app 学习路线,请不要期望只阅读一遍就能全部掌握,对于初学者来说,这篇文档不仅仅是一篇入门文档,它还是一篇很好的工具文档,在入门学习阶段,这篇文档被查阅的几率很高。
1.3.3 参考资源
以上两个学习网站推荐大家做为“字典类”资源来使用。
另外,在学习的过程中,编写代码运行后还会遇到一些“错误”,这些信息都会出现在 HX 的调试窗口。当出现调试错误后,可以通过仔细阅读错误提示信息找到问题所在,然后进行纠正即可。当出现阅读不理解,不知如何纠正时,可以将出错信息复制到搜索引擎的窗口,并附带上一些发生错误的具体信息,可以在网络上搜到可行的解决方案。
1.3.4 关于uni-app项目模板
在 HX 中提供了很多 uni-app 的项目模板,其中:
- 默认模板:是 uni-app 最简单的模板,不包含扩展组件,适合创建自定义功能的项目。
- Hello uni-app 模板:是演示 uni-app 框架的组件、接口使用情况的模板,官网上体验的二维码扫描后看到的界面功能就是这个模板创建的。
- uni-ui 模板:是包含所有 uni-app 内置组件和扩展组件的模板,基于该模板创建的项目,可以自由使用所有的组件而无需安装和配置。由于这个模板里包含了所有的组件,所以容量比较大,不利于日常代码的版本管理,建议在实际项目的生产阶段不选择该模板。
【说明】:
使用默认模板创建项目后,还要根据实际开发需要从插件市场添加所需的组件,所以请务必保证已经注册了 DCloud 的账号,并在HX使用过程中处于登录状态。
2、从默认模板开始学习uni-app
2.1 了解uni-app项目的目录结构
在 HX 中新建一个 uni-app 的默认模板项目,命名为“Unit2-2.1”,建立好之后在 HX 的项目管理器窗口中看到如下图所示的项目目录结构:
2.1.1 pages目录
是项目运行后用以和用户进行交互的页面,所有的页面布局以及功能逻辑都是写在这里。
2.1.2 index.vue文件
是一个 vue 文件,因为 vue 是单页面文件,所有的布局、样式和逻辑都写在一个页面文件里。为了保证 uni-app 项目转换成微信小程序时能够顺利实现,需要给 pages 目录下的每一个 vue 页面文件创建一个同名的目录。这也是为什么 index.vue
文件需要保存在 index 目录下的原因。
2.1.3 static目录
这里存放的是项目中需要用到的外界静态资源,例如图片、视频、音频、其他js文件等。为了保证资源浏览方便,最好在 static 目录下创建资源的分类目录,并按类别保存所需的静态资源。例如在 static 目录下建立 images 文件夹用来存放图片,videos 文件夹存放视频…
2.1.4 manifest.json 文件
这是当前项目的配置文件,之前所学习的配置微信小程序的 AppID 就是在这里操作,除此以外,这里还可以配置 uni-app 项目的AppID,这个 ID 值用来在 DCloud 云平台中对项目进行唯一标识。其他更多的配置在涉及到具体需求时再进行描述。
2.1.5 pages.json 文件
这里是对 pages 目录下的每一个 vue 文件进行配置的总管文件,这个文件还承担了 uni-app 项目运行时,首先从哪个 page 开始进入。所有 page 的配置都是 json 格式的数据,作为 json 数组中的一个元素存放在“pages”
项中。
2.1.6 其他
项目中的其他文件是很重要的,但是本次内容暂时不涉及学习,请不要任意修改内容,防止代码无法运行。
2.2 从index.vue入手学习页面结构
在项目管理器窗口中双击 “index.vue” 页面文件,在 HX 的编辑器窗口中可以看到 index.vue 文件的源码内容。
一个 vue 文件包含三个部分:template、script、style。
2.2.1 template
template
节点用于写 tag 组件,例如:view
、text
、image
等,这些组件是用于在页面中进行资源展示以及与用户交互的。
【强调】:
template
中有且仅有一个根view
,所有的内容都要写在这个根view
下。- 组件公共属性:template 中的所有组件都有共同的公共属性。其中
class
属性就是其中用来指定组件样式的属性。 - image组件:在 vue 中用于显示图片。
- text组件:用于在
view
中显示文字。不建议在view
中直接编写文字内容,而应该放在 text 组件中显示。 - {{ 变量名 }}:这个是 vue 的模板语法,等同于把定义在
data()
部分的变量的值直接显示在这里。
2.2.2 script
在 script
节点中有一个export default { }
结构,是页面的主要逻辑代码。包括几部分:
【重点】:
视图与逻辑中的数据绑定,详见下图指引。
- 上图中第 3 行的
src
属性前增加了冒号“:”,属性值是在data
中定义的变量imgSrc
,依然要求写到双引号中,这种属于数据绑定。 - 在
data
中增加新的变量时,记得用逗号“,”做间隔。
2.2.3 style
style
的语法与 Web 的 CSS 语法一致,在这里编写具体样式,然后在 template
节点内的组件中进行应用。
3 案例-单机版备忘录
3.1 功能分析
备忘录在很多手机都属于自带软件,一般备忘录程序都包含三个页面:列表页、详情页和添加页。
- 列表页:主要是按照时间倒序罗列备忘录的标题和添加时间。除此之外,还有一个增加新的备忘录的指示按钮,点击后可以进入添加备忘录的页面。
- 详情页:显示备忘录的具体内容,包括标题、内容、添加时间等。在这个页面上可以浏览内容,也可以进行备忘录内容的修改和删除。
- 添加页:这个页面上会有一些输入框,供用户输入备忘录的标题和内容等信息,还要提供一个“保存”或者“添加”按钮,用以将当前新增加的备忘录信息保存,并可以在列表页中看到新增的备忘录标题。
【总结】:
通过以上分析,制作备忘录需要使用大量 uni-ui 扩展组件,为了方便开发,将通过创建 uni-ui 模板项目来实施。
3.2 开发步骤
3.2.1 创建 UniMemo 项目
在 HX 中创建 uni-app 的 uni-ui 模板的项目 UniMemo,将其保存在无中文的文件路径下。
相比通过默认模板创建的项目来说,uni-ui 模板多了一个 “uni_modules” 目录,展开该目录可以看到很多用 “uni-” 开头的目录,这些就是 uni-ui 的扩展组件包,只有这里有的组件,在页面开发中才可以直接使用,否则需要去插件市场进行安装后才可以使用。
3.2.2 将 index 页面作为列表页进行设计
(1)为列表项准备数据
作为列表页,展示的是备忘录的标题和添加日期,并且是按照日期倒序排列,所以在 script
节点的 data
中增加用于显示列表信息的 json 数组 memos
,具体见如下代码:
<script>
export default {
data() {
return {
memos:[
{
title: 'DCloud账号密码',
date: '2023-9-5'
},
{
title: '移动应用开发上课要求',
date: '2023-9-4'
},
{
title: '考研讲座信息',
date: '2023-9-3'
},
{
title: '教资考试注意事项',
date: '2023-9-2'
}
]
}
},
methods: {
}
}
</script>
【说明】:
memos
是一个 json 数组,数据项是 json 数据,每一个 json 数据都包含两个数据项title
和date
。memos
中的数据项在组织时,是按照date
的值倒序编写的。
(2)在 view 根节点中添加 uni-list 组件
将 template
节点的代码改成如下所示的内容:
<template>
<view class="container">
<uni-list>
<view v-for="(item,index) in memos" :key="index">
<uni-list-item :title="item.title" :note="item.date"></uni-list-item>
</view>
</uni-list>
</view>
</template>
【说明】:
uni-list
标记通过键入 “uList” 唤起 HX 的代码补齐功能。v-for
是列表的循环渲染语法,代码中第 4 行和第 6 行的view
节点仅仅用于执行循环输出第 5 行的代码。uni-list-item
不能脱离uni-list
组件单独使用。
在预览中查看页面运行效果如下图所示:
(3)更改 index 页面的标题
上图的预览效果中,看到 index.vue 页面的顶部标题显示的是 “uni-app”,这是项目创建时自动编写的,通过修改 pages.json 文件中的内容,可以修改页面的标题信息。
3.2.3 创建新的页面
在 3.1 的功能分析中得到,除了列表页之外,备忘录小程序还需要详情页面和添加备忘录页面。
(1)创建详情页面 detail 页面
如下图所示,在 HX 的项目管理器视图中,“右键单击” pages 目录,在弹出的操作菜单中选择“新建页面( P )”。
【注意】:
一定要在 pages 目录上右键单击,否则会出现很多问题。
接下来,在弹出的窗口中请确认跟下图红色矩形框中标识的位置一致后,再点击“创建”按钮。
【说明】:
- 新创建的页面名称只需要写 detail 即可,不需要写 detail.vue 。
- 创建同名目录:必须勾选。这样会在 pages 目录下增加一个与页面文件同名的目录,这样做的目的是为了和小程序开发的目录要求一致。
- 默认模板:初次学习如何编写一个 page,选择这个模板就行。
- 在 pages.json 中注册:必须勾选。在 pages.json 文件中注册页面是为了和小程序开发要求一致。
(2)创建添加备忘录的 add 页面和修改备忘录的 edit 页面。
这两个页面的创建步骤与(1)一致。
(3)pages.json 说明
uni-app 项目中存在多个 page 时,通过在 pages.json 文件中设定首次启动的页面是哪一个。
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "我的备忘录"
}
},
{
"path" : "pages/detail/detail",
"style" :{
"navigationBarTitleText": "备忘录详情",
"enablePullDownRefresh": false
}
},
{
"path" : "pages/add/add",
"style" :{
"navigationBarTitleText": "创建新的备忘录",
"enablePullDownRefresh": false
}
},
{
"path" : "pages/edit/edit",
"style" : {
"navigationBarTitleText": "修改备忘录",
"enablePullDownRefresh": false
}
}
],
...
}
【说明】:
pages
项是一个 json 数组,该数组中的第一个元素是 uni-app 项目的启动页。上述代码中 index 页面是启动页。pages
项中每一个 json 数据的path
项目的值是页面路径,这里主要注意路径中没有“.vue”。- 如果在新建页面时,忘了勾选 “在pages.json中注册” 前的复选框,可以按照这个代码编写格式自行添加。
3.2.4 在index页面建立detail页面的访问途径
index 页面中的每一个列表项应该可以被点击,并且点击之后应该在 detail 页面中看到不同的备忘录详情,具体步骤如下:
(1)在 method 中创建自定义函数 goToDetail。
goToDetail(memoIndex){
uni.navigateTo({
url:'/pages/detail/detail?memoIndex=' + memoIndex
})
}
【说明】:
goToDetail
函数带有一个memoIndex
参数,用于标识当前点击的是列表中的哪一项。- 函数体中用到了 uni-app 的页面路由方法 uni.navigateTo ,用于进行uni-app 项目内的页面跳转。
url
赋值为一个页面地址字符串和index
参数值的连接结果,其中“+”加号是字符串连接运算符。
(2)给 uni-list-item 增加访问链接属性。
<uni-list-item
:title="item.title"
:note="item.date"
@click="goToDetail(index)"
link>
</uni-list-item>
【说明】:
- 上面的代码结构一行一个属性,这种方式便于查看。
@click
属性绑定的是列表项被点击后的响应事件,这里是在methods
中定义的goToDetail
函数。link
属性用于开启点击反馈,并且在列表项右侧显示箭头。
(3)预览效果
以上代码编写完成后,在预览中的效果如下图所示:
3.2.5 编写 detail 页面功能代码
(1)在 detail 页面的 script 节点的 data 中增加 index 和 memos 数据。
<script>
export default {
data() {
return {
index:0,
memos:[
{
title: 'DCloud账号密码',
date: '2023-9-5',
content: '用户名:abcdefg@126.com,密码是:123456'
},
{
title: '移动应用开发上课要求',
date: '2023-9-4',
content: '认真听、认真看、认真练'
},
{
title: '考研讲座信息',
date: '2023-9-3',
content: '9月22日 xx:xx:xx , 尚德楼 XXX 教室,著名考研讲师张*峰,主题是:考研的那些事儿'
},
{
title: '教资考试注意事项',
date: '2023-9-2',
content: '2023年教资考试具体要求如下:XXXXXXXXXXXXXXXXXXXXXXXXXXXX'
}
]
}
},
onLoad:function(option){
if(option.memoIndex != null) {
this.index = option.memoIndex
}else{
console.log("no memoIndex")
}
},
methods: {
}
}
</script>
【说明】:
index
是 detail 页面的变量,默认值是0。memos
数据的内容与 index 页面中的memos
相比,增加了content
数据项。onLoad
是页面生命周期中的监听页面加载时的方法,这个方法里的功能根据具体需要有用户自定义编写。
【重点】:
- 上述代码中,
onLoad
方法监听了在页面加载时是否捕获到memoIndex
这个参数,也就是从 index 页面的列表项中执行点击事件时,用于存放哪个列表项被点击的那个参数。 - uni-app 项目中,所有页面之间通过显式方式传递参数的方法是在页面路径后通过
?
问号挂接需要传递到目标页面的参数,参数按照参数名=参数值
的方式表述,多个参数之间用&
符号连接。 - 目标页面在被加载时,所有从前一个页面传递过来的参数都存放在
option
数据中,option
是一个json数据,通过.
点运算符访问被传递过来的参数名。 - 上述代码第32行中的 “this.index” 中的
this
表示的是当前页面,所有在export default
中定义的data
变量,methods
方法都可以通过this
进行访问。 - 整个
onLoad
方法的作用就是:首先判断页面加载时是否携带了memoIndex
参数,如果携带,那么将当前页面的index
变量的值赋值为memoIndex
参数的值;如果没有携带,那么在控制台打印出错提示。
(2)使用 uni-card 组件显示信息。
<template>
<view>
<uni-card :title="memos[index].title" :extra="memos[index].date">
{{memos[index].content}}
</uni-card>
</view>
</template>
【说明】:
- uni-card 组件的唤起代码是 uCard。
title
是uni-card
的标题属性,通过添加冒号前缀,与data
中memos
的数据项进行了绑定。memos
是data
中的 json 数组型数据,数组元素下标通过方括号表述。extra
是uni-card
的标题额外信息,这里用来显示备忘录的添加日期。uni-card
的主体内容直接写在组件标记对内部即可,如上述代码第 4 行所示。
(3)添加页面标题
在 pages.json 文件中,为 detail 页面添加标题,仿照3.2.2(3)的内容进行代码修改即可。修改页面标题为“备忘录详情”。
(4)预览效果
以上代码编写完成后,预览 index 页面,点击相应的列表项后,可以进入 detail 页面查看具体内容,下图是在 index 页面中点击 “移动应用开发课程要求” 一项后看到的具体内容。
3.2.6 uni-app 的缓存机制
【引子】:
在 index 页面和 detail 页面中都有 memos
数据,这两个数据的内容基本相同(数据冗余),而且这些数据项在代码中都是“写死”的,如果想要添加、修改或删除一个备忘录信息,就需要去修改代码,这显然是与功能设计初衷相违背的。
所以,需要考虑一种数据共享机制,这种机制可以实现在 uni-app 项目中,所有页面都能共享数据项,并对这些数据项进行修改。
而这种机制就是 uni-app 的数据缓存机制。
【说明】:
- uni-app 项目中的数据缓存可以理解为一个“全局文件”。
- 在这个全局文件中,用户可以将自己需要共享的数据以 json 的格式存放在其中。
- 获取缓存数据的方法是
uni.getStorage
和uni.getStorageSync
。 - 添加缓存数据的方法是
uni.setStorage
和uni.setStorageSync
。
3.2.7 在 index 页面中获取缓存数据
【分析】:
在 index 页面显示(onShow
)时,需要判断缓存中是否有备忘录列表数据:
- 如果有,将缓存中的数据项赋值给 index 页面中的变量
memos
; - 如果没有,保持 index 页面中的
memos
变量的值为空,页面显示“空空如也”的提示字样。
(1)使用 onShow 访问缓存数据
data() {
return {
flag: false,
tip:'空空如也',
memos:[]
}
},
onShow:function(){
var that = this
uni.getStorage({
key: 'memos',
success:function(res){
that.memos = res.data
if(that.memos.length == 0){
that.flag = true
}else{
that.flag = false
}
},
fail:function(e){
that.flag = true
}
})
},
【说明】:
data
中定了三个变量:flag
用来操控页面显示的内容,tip
是提示信息,memos
用来存放从缓存中获取的数据值。onShow
方法用于监听页面显示的响应过程,这里使用异步方式访问缓存的数据项memos
:success:function(res){ }
是成功访问到memos
缓存项后的回调函数,用于对页面中的变量memos
赋值。fail:function(e){ }
是未访问到memos
缓存项后的回调函数。
- 因为整个
uni.getStorage
方法是异步回调的,所以要访问页面中的变量必须给当前页面建立一个新的拷贝,如上述代码第 9 行所示。 - 无论是不存在
memos
缓存项,还是虽然存在memos
缓存项,但是该缓存数据中的内容是空的,那么都无法在页面中进行列表显示,因此需要根据这些情况来修改flag
的值,用以控制视图内容的输出。
(2)使用 v-if v-else 控制视图输出
<template>
<view class="container">
<view v-if="flag">
<text>{{ tip }}</text>
</view>
<view v-else>
<uni-list>
<view v-for="(item,index) in memos" :key="index">
<uni-list-item
:title="item.title"
:note="item.date"
@click="goToDetail(index)"
link>
</uni-list-item>
</view>
</uni-list>
</view>
</view>
</template>
【说明】:
- 代码第3、5、6和17行,共同构成了一个
view
的显示与隐藏功能。 - v-if 和 v-else 用于渲染
view
的条件显示:- 当
v-if
的值为“真”时,其包裹的组件被输出显示; - 否则
v-else
包裹的组件内容显示。
- 当
3.2.8 在 index 页面建立 add 页面的访问途径
(1)悬浮按钮
<uni-fab @fabClick="goToAdd()" horizontal="left" vertical="bottom"></uni-fab>
【说明】:
uni-fab
组件的唤起代码是 uFab。@fabClick
是悬浮按钮被点击后的响应动作,这里是调用了在methods
中定义的goToAdd
函数。horizontal
是悬浮按钮在页面中的水平位置,有left
和right
两个值。vertical
是悬浮按钮在页面中的垂直位置,有bottom
和top
两个值。- 以上代码请写在 index 页面中
v-if
、v-else
条件渲染view
组件外。
(2)添加访问函数
goToAdd(){
uni.navigateTo({
url: '/pages/add/add'
})
}
【说明】:
- 以上代码要写在
methods
中,如果有多个自定义的函数,需要用,
逗号间隔,否则会报错。 goToAdd
函数没有任何参数,函数体的内容依然是调用了uni.navigateTo
方法执行页面跳转。
(3)预览效果
以上代码编写完毕后,在预览中看到的效果如下图所示:
3.2.9 编写 add 页面功能代码
add 页面负责提供输入框,供用户填写备忘录的标题、内容,还需要有一个按钮,实现点击后,可以将当前的备忘录信息添加到 uni-app 的数据缓存项 memos
中。
(1)使用 uni-nav-bar 和 uni-icons 设计自定义导航栏
在 add.vue 页面中 view
根节点下输入以下代码
<uni-nav-bar left-icon="list" left-text="备忘录" right-text="完成" @clickRight="addMemo"></uni-nav-bar>
【说明】:
- uni-nav-bar 的唤起代码是 uNavBar。
left-icon
属性设置导航栏左侧图标,图标依赖uni-icons
组件,可用的图标类型参考 uni-icons 示例。left-text
属性设置导航栏左侧文字。right-icon
属性设置导航栏右侧图标,right-text
属性设置导航栏右侧文字,但是这二者不可同时使用。@clickRight
是导航栏右侧图标或文字被点击后的响应事件,这里调用了在methods
中定义的addMemo
函数。- 导航栏的其他属性请参考 uni-nav-bar 组件属性 。
(2)使用 uni-forms 、uni-easyinput 组件设计备忘录添加表单
add.vue 中 template
节点的代码入下:
<template>
<view>
<uni-nav-bar left-icon="list" left-text="备忘录" right-text="完成" @clickRight="addMemo"></uni-nav-bar>
<view class="container">
<uni-forms ref="form" :rules="rules" :model="memoItem">
<uni-forms-item name="title">
<uni-easyinput v-model="memoItem.title" placeholder="标题" />
</uni-forms-item>
<uni-forms-item name="content">
<uni-easyinput type=textarea v-model="memoItem.content" placeholder="内容" />
</uni-forms-item>
</uni-forms>
</view>
</view>
</template>
add.vue 中 data
部分定义的代码如下:
data() {
return {
memoItem: {
title: '',
content: '',
addTime: ''
},
rules: {
title: {
rules: [
{required: true, errorMessage: '标题不能空'},
{minLength: 3, maxLength: 20, errorMessage: '长度在3~20字符之间'}
]
},
content: {
rules: [
{required: true, errorMessage: '还没有填写内容'},
{minLength: 3, maxLength: 200, errorMessage: '长度在3~200字符之间'}
]
}
}
}
},
【说明】
- uni-forms 的唤起代码是 uForms,代码补全后自动创建带有一个
uni-forms-item
组件的uni-form
组件。uni-forms
组件的:model
用于同data
中定义的数据进行绑定后执行校验时对数据进行访问。uni-forms
组件的:rules
属性是必选项,代码中将其与data
中定义的rules
变量绑定,用于对表单中的项目进行校验,只有校验符合data
中定义的rules
变量中的配置时,才允许表单被提交。uni-forms
组件的ref
属性是必选项,用于在进行表单验证时识别具体的表单。
uni-forms-item
不能脱离uni-forms
单独使用,且内部只能包含一个表单类组件。uni-forms-item
的name
属性值用于同data
中定义的rules
数据中的校验项对应,上述代码中name="title"
,表示该表单项的输入内容要同data
中rules.title
定义的规则一致。uni-forms-item
默认创建时会带有label
属性,该属性用于在表单项前显示提示文字,如果不需要,可删掉该属性。
uni-easyinput
组件的v-model
属性用于和data
中定义的具体数据项进行双向绑定。- 与
uni-forms
绑定的数据和校验规则写在data
中 。data
中定义的memoItem
是一个 json 格式的数据,包含了备忘录信息所需要的具体字段:title
,content
,addTime
data
中定义的rules
是针对form
的校验规则,与uni-forms
的rules
绑定。rules
是一个 json 数据,每个数据项对应一个uni-forms-item
的name
属性值。- 以
rules.title.rules
的值为例,每个项目的校验规则都是一个 json 数组,可以包含多个校验项,这里表示title
数据是必须的,并且长度限制在3~20个字符。
(3)为 add 页面编写新建备忘录功能
备忘录信息中有一个 addTime
数据用来记录提交的系统时间,为了方便代码重用,考虑将日期时间的处理函数放在外部 js 文件中,然后在需要的地方 import
。
① 在 static 文件夹中创建 mydate.js 文件,并将以下代码保存在该文件中。
export function timeNow(){
var now = new Date();
var year = now.getFullYear();
var month = now.getMonth() + 1;
month >=1 && month <=9 ? (month = "0" + month) : "";
var day = now.getDate() < 10 ? ("0" + now.getDate()) : now.getDate();
var hour = now.getHours() < 10 ? ("0" + now.getHours()) : now.getHours();
var minute = now.getMinutes() < 10 ? ("0" + now.getMinutes()) : now.getMinutes();
var second = now.getSeconds() <10 ? ("0" + now.getSeconds()) : now.getSeconds();
var value = year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second;
return value;
}
【说明】:
这里采用了 ES6 的 module 的 export
和 import
机制,如果要在 vue 文件中 import
一个 js 文件中的方法,首先需要将这个方法在 js 文件中作为 module 进行 export
。
更多的有关 export
和 import
的内容请参考 阮一峰的ES6入门-Module语法。
② 修改 add.vue 的 script
节点的代码如下:
<script>
import {timeNow} from '@/static/mydate.js'; // 引入外部 js 文件中的function
export default {
data() {
return {
... //这里代码在本节(2)中已给出,不再展示
}
},
methods: {
showAndBack(){ // 用于屏幕提示2秒后自动消失并返回上一个页面
uni.showToast({
icon:"success",
title: "添加成功",
duration:2000
});
setTimeout(function(){
uni.navigateBack()
}, 2000);
},
addMemo(){
var that = this //为当前页面创建拷贝,方便在回调中使用
this.$refs.form.validate().then((res)=>{//这里是表单校验成功后的操作
that.memoItem.addTime = timeNow() // 访问外部函数 timeNow 给 addTime 赋值
//以下是先从缓存中访问 memos,根据访问情况执行后续操作
uni.getStorage({
key:'memos',
success:function(res){ //成功从缓存中获取了数据
var mlist = res.data
mlist.splice(0, 0, that.memoItem); // 插入到最前,实现倒序
uni.setStorage({ // 以下把修改后的数据再存放回缓存中
key:'memos',
data: mlist,
success() {
that.showAndBack()
},
fail:function(e){
console.log(e)
}
})
},
fail() {// 缓存中不存在数据,本次新建属于首次在缓存中创建数据
var mlist = [that.memoItem]
uni.setStorage({
key: 'memos',
data: mlist,
success() {
that.showAndBack()
},
fail:function(e){
console.log(e)
}
})
}
})
})
.catch((err)=>{//这里是表单校验失败后的操作
console.log("form invalidate")
})
}
}
}
</script>
【说明】:
- 第 2 行使用
import
方式引入了在 static 文件夹下的 mydate.js 文件,因为 mydate.js 文件中将timeNow
函数进行了输出,这里直接将timeNow
函数名写在{}
大括号内进行引入,方便后续代码使用。 - 第 21 ~ 60 行是
addMemo
函数的整个定义,这个函数从结构上看分成两部分:- var that = this
- this.$refs.form.validate().then().catch()
- 这是一个 JS 中的 Promise,其中
then()
中的代码是当前面的validate()
方法执行后得到期望值时再执行。 - 代码中第 24 ~ 56 行是
then()
中执行的回调代码,首先从缓存中访问memos
数据:- 如果找到了(代码第 28 ~ 41 行),就把
memoItem
的值追加到memos
数组的最前面。(缓存中的数据只能读和重写,不能直接在缓存中修改,所以当通过uni.getStorage
的方式获取memos
后,需要先放到变量mlist
中,把memoItem
添加到mlist
后,再把mlist
作为要缓存的数据,通过uni.setStroage
的方式覆盖掉原来的memos
的值) - 如果在缓存中未访问到
memos
数据(代码第 42 ~ 54 行),那么表示当前整个备忘录是空的,因此直接把memoItem
数据作为memos
的一个数组元素创建到缓存中。
- 如果找到了(代码第 28 ~ 41 行),就把
catch()
中的代码表示执行validate()
方法后出错时执行。
- 这是一个 JS 中的 Promise,其中
showAndBack()
函数用于在屏幕上显示一个提示信息,并在2秒后自动消失,页面自动返回到 index 中。- 这里调用的
uni.showToast
,这是一种页面交互方式,用于在页面上展示提示信息,并在指定的时间之内消失。 - setTimeout() 方法是 js 原生库中针对 window 的方法,这里的 window 表示的是运行小程序的窗体,它用于在指定的毫秒后调用函数或表达式。代码中第 17 ~ 19 行表示 2 秒后执行
uni.navigateBack
方法。
- 这里调用的
(4)在微信开发者工具中运行效果
【说明】:
上面图片是从 index 页面进入,点击底部悬浮按钮后进入 add 页面进行添加备忘录,成功后返回 index 页面,并在列表上点击后看到的 detail 页面上显示的具体内容。
3.2.10 改写 detail 页面
detail 页面用于显示某个具体的备忘录信息,这个具体的值是从缓存数据 memos
中获取的,因此在 detail 页面的 onLoad
事件中应当执行缓存数据的获取操作,然后根据传入的参数 memoIndex
的值来访问具体的数组元素,并把元素的值渲染在视图中。
<template>
<view>
<uni-card :title="memoItem.title" :extra="memoItem.addTime">
{{memoItem.content}}
</uni-card>
</view>
</template>
<script>
export default {
data() {
return {
index: 0,
memoItem: {
title: '',
content: '',
addTime: ''
}
}
},
onLoad:function(option){
var that = this
if(option.memoIndex != null) {
this.index = option.memoIndex
uni.getStorage({
key: 'memos',
success:function(res){
that.memoItem = res.data[that.index]
},
fail:function(e){
console.log(e)
}
})
}else{
console.log("no memoIndex")
}
},
methods: {
}
}
</script>
【说明】:
在 data
中创建与备忘录数据元素相同的 json 格式的数据变量 memoItem
,用以接收从缓存中获取的数据。
3.2.11 编写 edit 页面功能
edit 页面从组件布局上讲与 add 页面一致,都提供了两个 uni-easyinput
组件和“完成”按钮。
不同的是,add 页面在初始进入时,分别用来填写备忘录标题和内容的两个 uni-easyinput
组件的内容是空的;而 edit 页面上在 uni-easyinput
组件中显示的是需要修改的备忘录的标题和内容。
(1)edit 页面的 template
<template>
<view>
<uni-nav-bar left-icon="trash" right-text="完成" @clickLeft="deleteMemo" @clickRight="editMemo"></uni-nav-bar>
<view class="container">
<uni-forms ref="form" :rules="rules" :model="memoItem">
<uni-forms-item name="title">
<uni-easyinput v-model="memoItem.title" placeholder="标题" />
</uni-forms-item>
<uni-forms-item name="content">
<uni-easyinput type=textarea v-model="memoItem.content" placeholder="内容" />
</uni-forms-item>
</uni-forms>
<text>上次编辑时间:{{memoItem.addTime}}</text>
</view>
</view>
</template>
【说明】:
将本节的代码与 3.2.9(2)中提供的代码对比来学习:
uni-forms
组件内的代码完全一致。uni-nav-bar
组件部分,edit 页面将left-icon
的图标换成了 “trash”(垃圾桶),并且为自定义导航栏左侧的点击事件绑定了响应函数deleteMemo
。- edit 页面还在
uni-forms
组件外面添加了提示“上次编辑时间”的text
组件,用以显示当前备忘录上一次被“添加/修改”的时间。
(2)edit 页面的 data 设计
data() {
return {
index: 0,
memos:[],
memoItem: {
title: '',
content: '',
addTime: ''
},
rules: {
title: {
rules: [
{required: true, errorMessage: '标题不能空'},
{minLength: 3, maxLength: 20, errorMessage: '长度在3~20字符之间'}
]
},
content: {
rules: [
{required: true, errorMessage: '还没有填写内容'},
{minLength: 3, maxLength: 200, errorMessage: '长度在3~200字符之间'}
]
}
}
}
},
【说明】:
-
将本节代码与 3.2.9(2)中提供的
data
部分的代码作对比,可以看出这里增加两个变量: -
index
变量用于接收页面传参,标识被修改的备忘录是缓存中的第几条数据。 -
memos
变量是json数组,初始化时数组元素个数为0。当 edit 页面被加载时,暂存从缓存中拿到的key
为memos
的备忘录数组数据。
(3)edit 页面被加载时的动作
edit 页面的进入顺序是:index 页面 → detail 页面 → edit 页面。
从 detail 页面进入 edit 页面时,同样需要将当前备忘录的索引值作为参数传递。
edit 页面被加载时首先通过访问缓存,根据传递的参数拿到具体的备忘录信息,然后对视图进行渲染。
onLoad:function(option){
var that = this
if(option.memoIndex != null) {
this.index = option.memoIndex
uni.getStorage({
key: 'memos',
success:function(res){
that.memos = res.data
that.memoItem = res.data[that.index]
},
fail:function(e){
console.log(e)
}
})
}else{
console.log("no memoIndex")
}
},
【说明】:
- 代码第 3 行通过
if
语句,判断页面加载时是否携带了memoIndex
参数,如果存在,那么执行第 4 ~ 14 行的代码;否则执行第 16 行的控制台打印代码。 - 代码第 4 行将页面参数
memoIndex
的值存放在页面变量index
中,用于备忘录信息修改或者删除时,方便从备忘录数组数据中定位。 - 代码第 8 行,将缓存中获取的
memos
数据值存放在了页面的变量that.memos
中(为了区分缓存数据memos
和页面变量memos
,这里用that.memos
表示页面变量),这样做的目的是如果用户进行了修改或者删除操作,只需要在that.memos
中处理后再调用uni.setStorage
进行缓存的改写即可。 - 代码第 9 行将缓存中当前备忘录的信息存放在页面变量
memoItem
中,这里的值会直接在视图上进行渲染。
(4)对备忘录进行修改
editMemo(){
var that = this //为当前页面创建拷贝,方便在回调中使用
this.$refs.form.validate().then((res)=>{//这里是表单校验成功后的操作
that.memoItem.addTime = timeNow()
that.memos.splice(that.index, 1); // 删掉原索引位置的备忘录数据项
that.memos.splice(that.index, 0, that.memoItem); // 在被删掉的位置插入新的备忘录数据项
uni.setStorage({
key: 'memos',
data: that.memos,
success() {
that.backList()
}
})
})
.catch((err)=>{//这里是表单校验失败后的操作
console.log("form invalidate")
})
}
【说明】:
- 代码中第 5 行执行的是从数组中某个位置删除一个元素,第 6 行表示在数组中某个位置插入一个元素。这里用到的是 JavaScript 的
splice
方法。这个方法在 add 页面中创建新的备忘录时用到过,更多用法详见这里。
(6)删除某条备忘录
deleteMemo(){
var that = this
uni.showModal({ // 显示模态框询问
content: '确定要删除吗?',
success:function(res){
if(res.confirm){ // 用户点击确定按钮
that.memos.splice(that.index, 1);
uni.setStorage({
key: 'memos',
data: that.memos,
success() {
that.backList()
}
})
}
}
})
}
【说明】:
- 代码第 3 行开始,使用了
uni.showModal
,这是 uni-app 的页面交互 API 中的“显示模态框”。这种组件在小程序应用中也十分常见,通常用于在用户执行一些比较危险的操作时(例如删除某条记录等),提示用户是否确认操作。 - 模态框默认情况下会提供两个按钮,一个“确认”,一个“取消”,开发时可以根据需要选择只显示其中一个。
- 如果用户点击了“确认”按钮,那么会在返回的
res
中,confirm
数据项的值为true
- 如果用户点击了“取消”按钮,那么会在返回的
res
中,cancel
数据项的值为true
- 只需要通过判断
res.confirm
以及res.cancel
的值是否为真,就可以得到用户点击的是哪个按钮。
- 如果用户点击了“确认”按钮,那么会在返回的
- 代码第 6 ~15 行表示如果用户确认执行删除操作,那么将从数组中把该条备忘录数据删掉,然后再将缓存中的数据改写。
(7) uni.redirectTo
在 editMemo
和 deleteMemo
自定义函数中,都调用了一个 backList
自定义函数。代码是:
backList(){
uni.showToast({
icon:"success",
title: "操作成功",
duration:2000
});
setTimeout(function(){
uni.redirectTo({
url:'/pages/index/index'
})
}, 2000);
}
【说明】:
backList
自定义函数功能与 3.2.9(3)②中给出的 add 页面的showAndBack
自定义函数功能基本上相同。不同之处在于这里当2秒钟倒计时结束后,执行的是uni.redirectTo
方法,用以将当前页面关闭掉,并强制调转到url
所指定的页面。- 用户是从 detail 页面进入的 edit 页面,不管对备忘录信息进行了修改还是删除,这些操作完成后,用户应该期望的是返回到备忘录的列表页,而不是上一个页面。
- 虽然
uni.navigateTo
和uni.redirectTo
都可以实现从当前页面跳转到url
指定的页面,但uni.navigateTo
不会关闭当前页面,而是将其放入“页面栈”中,用户可以通过导航栏的 “<” 按钮返回。而这里显然使用uni.redirectTo
更合理。
3.3 案例源码
UniMemo 项目的完整源码已经部署到码云中,可以自行下载查看并学习。