Unit 2 uni-app入门

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 组件,例如:viewtextimage等,这些组件是用于在页面中进行资源展示以及与用户交互的。

在这里插入图片描述

【强调】:

  • template 中有且仅有一个根 view,所有的内容都要写在这个根 view 下。
  • 组件公共属性:template 中的所有组件都有共同的公共属性。其中 class 属性就是其中用来指定组件样式的属性。
  • image组件:在 vue 中用于显示图片。
  • text组件:用于在 view 中显示文字。不建议在 view 中直接编写文字内容,而应该放在 text 组件中显示。
  • { { 变量名 }}:这个是 vue 的模板语法,等同于把定义在 data() 部分的变量的值直接显示在这里。
2.2.2 script

script 节点中有一个export default { }结构,是页面的主要逻辑代码。包括几部分:

在这里插入图片描述

  • datatemplate 模板中需要使用的数据。具体另见
  • 页面生命周期:如页面加载、隐藏、关闭,具体另见
  • methods 方法:这里是用户自定义的方法,如按钮点击后的响应、屏幕滚动响应等。

【重点】:

视图与逻辑中的数据绑定,详见下图指引。

在这里插入图片描述

  • 上图中第 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 数据都包含两个数据项 titledate
  • 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: '用户名:[email protected],密码是: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。
  • titleuni-card 的标题属性,通过添加冒号前缀,与 datamemos 的数据项进行了绑定。
  • memosdata 中的 json 数组型数据,数组元素下标通过方括号表述。
  • extrauni-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.getStorageuni.getStorageSync
  • 添加缓存数据的方法是 uni.setStorageuni.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 是悬浮按钮在页面中的水平位置,有 leftright 两个值。
  • vertical 是悬浮按钮在页面中的垂直位置,有 bottomtop 两个值。
  • 以上代码请写在 index 页面中 v-ifv-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-itemname 属性值用于同 data 中定义的 rules 数据中的校验项对应,上述代码中 name="title",表示该表单项的输入内容要同 datarules.title 定义的规则一致。
    • uni-forms-item 默认创建时会带有 label 属性,该属性用于在表单项前显示提示文字,如果不需要,可删掉该属性。
  • uni-easyinput 组件的 v-model 属性用于和 data 中定义的具体数据项进行双向绑定。
  • uni-forms 绑定的数据和校验规则写在 data 中 。
    • data 中定义的 memoItem 是一个 json 格式的数据,包含了备忘录信息所需要的具体字段:titlecontentaddTime
    • data 中定义的 rules 是针对 form 的校验规则,与 uni-formsrules 绑定。
      • rules 是一个 json 数据,每个数据项对应一个 uni-forms-itemname 属性值。
      • 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 的 exportimport 机制,如果要在 vue 文件中 import 一个 js 文件中的方法,首先需要将这个方法在 js 文件中作为 module 进行 export

更多的有关 exportimport 的内容请参考 阮一峰的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 的一个数组元素创建到缓存中。
      • catch() 中的代码表示执行 validate() 方法后出错时执行。
  • 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 页面被加载时,暂存从缓存中拿到的 keymemos 的备忘录数组数据。

(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

editMemodeleteMemo 自定义函数中,都调用了一个 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.navigateTouni.redirectTo 都可以实现从当前页面跳转到 url 指定的页面,但 uni.navigateTo 不会关闭当前页面,而是将其放入“页面栈”中,用户可以通过导航栏的 “<” 按钮返回。而这里显然使用 uni.redirectTo 更合理。

3.3 案例源码

UniMemo 项目的完整源码已经部署到码云中,可以自行下载查看并学习。

猜你喜欢

转载自blog.csdn.net/ursamjnor/article/details/132809280