草庐IT

【微信小程序】项目实战—抽签应用

学海无涯yc 2023-04-15 原文
  • 完成学习前面章节的微信小程序开发必备的基础知识,从本章开始就可以进入完整的应用开发了。很多大型的应用主要通过App来实现,微信小程序的定义则主要是工具类的应用,宗旨是做到即用即走。抽签应用完全符合这一特性,所以本章将实现一个抽签类型的小程序。

本章主要涉及的知识点有:

  • UI组件的使用
  • 表单的使用
  • 本地存储

1.项目起步

本节开始设计抽签项目所需要包含的功能。在平时遇到难以决定的事情时,可以使用小程序进行抽签。该抽签应用包括以下功能。

  • 增加抽签项及其内容项
  • 删除抽签项及其内容项
  • 抽签
  • 本地存储
  • 输入校验
  • 用户交互提示

接下来新建一个项目draw作为本章的项目。导入UI框架iView,并在根目录新建文件夹images。项目中所需要用到的图片可以直接从示例代码中获取。目录如图所示。

app.js清空,删除index和logs页面,新建home、mine、edit-item、draw-view页面,最后在app.json、app.wxss中输入以下代码:

// app.json
·..
"tabBar":{
"selectedColor":"#2C8BEF""list": [
{
"selectedIconPath":"images/home2.png","iconPath":"images/home.png","pagePath":"pages/home/home","text":"首页"}{
"selectedIconPath":"images/mine2.png","iconPath":"images/mine.png","pagePath":"pages/mine/mine","text":"我的"
}]
},
·..

// app.wxss page {
background-color: #EFEFEF;

运行效果如图所示。

【代码解析】一个带底部导航栏的首页已经完成。导航栏的内容主要是通过tabBar参数来实现的。

注意:应把app.json中的v2删除,否则UI框架可能会运行出错。

2.项目开发

准备工作完成后,正式进入编码阶段。

2.1首页开发

打开home页面,输入以下代码:

// home.json

"navigationBarTitleText":"首页""usingComponents":
{
"i-button":"/dist/button/index",
"i-cell-group":"/dist/cell-group/i ndex","i-cell":"/dist/cell/index",
    "i-modal":"/dist/modal/index"

}

// home.wxml
<i-button type="primary" bind:click="addItem">添加选项</i-button>

<i-cell-group><i-cell
wx:for="{{listData}}" wx:for-item="item" wx:key="item"
data-item="{{item}}" title="{{item}}" bindtap="draw"
bindlongpress="delete" is-link></i-cell></i-cell-group>

<i-modal title="删除确认" visible="{{ visible }}" actions="{{ actions }}" bind:click="realDelete">
<view>删除后无法恢复哦</view></i-modal>

// home.js
// pages/home/home.js
Page({ data:{
listData:[],
currentItem:'' actions: [{
name:'取消'}name:'删除'color:'#ed3f14', loading:false}
]visible:false}onShow: function () { 
this.setData({
listData:wx.getStorageSync('homeList')})}//加选项 addItem() {
wx.navigateTo({
url:'../edit-item/edit-item',

}//进入抽签页 draw(e){
wx.navigateTo({
url:'../draw-view/draw-view?item='+ e.currentTarget.dataset.item

}//删除子选项弹窗 delete(e){
console.log(e) this.setData({
visible: true,
currentItem: e.currentTarget.dataset.item});

// 删除子选项
realDelete({detail}){
if (detail.index=== 1) {
var newArray=[];
for (const item of this.data.listData){
if (item!=this.data.currentItem){ newArray.push(item);
}
}
this.setData({
listData: newArray
1
wx.setStorageSync('homeList',this.data.listData)
wx.removeStoraqeSync(this.data.currentItem) wx.showToast({
title:'删除成功'1)
    this.setData({
visible: false
!({
})

【代码解析】首先在home.json中导入需要用到的UI组件。在页面结构上,顶部是一个添加选项按钮,并通过wxfor来显示选项,最后的i-modal是弹窗组件,通过visible控制。在页面跳转方面,edit-item是添加选项页,draw-view是抽签页。删除功能通过覆盖homeList的选项来实现,删除成功后,要循环删除子选项。

2.2新增页面开发

由于还没有开发添加选项页,因此放效果图之前需要先开发一个添加选项页面。在edit-item页面中输入以下代码:

// edit-item.json{
"navigationBarTitleText":"选项""usingComponents":{
"i-panel":"/dist/panel/index","i-input":"/dist/input/index","i-button":"/dist/button/index"
/
// edit-item.wxml
<i-panel title="{{title}}">
<i-input
value="{{itemName}!"
placeholder="请输入选项"
bind:change="changeItem"/></i-panel>

<i-button bind:click="submit" type="primary">提交</i-button>

// edit-item.js
// pages/edit-item/edit-item.js Page({
data:{
title:'添加选项'saveKey:'homeList', itemName:''
    }onLoad:function (options){ if (options.item){ this.setData({
title:'添加"'+options.item+'"的子选项', saveKey:options.item})}
}changeItem(e){ this.setData({
itemName: e.detail.detail.value})
}// 提交
submit() {
if (this.data.itemName.length===0) { wx.showToast({
title:'内容过短', icon:'none'})
} else if (this.data.itemName.length >10){ wx.showToast({
title:'内容过长', icon:'none'})
}else {
var items;
var key= this.data.saveKey; if (wx.getStorageSync(key)) {
items=wx.getstorageSync(key); for (const key of items) {
if (key== this.data.itemName){ wx.showToast({ title:'已存在', icon:'none'})
returni

}
}else {
items = [];
items.push(this.data.itemName);
wx.setStorageSync(key,items); wx.showToast({
title:'保存成功'})
setTimeout(() => {
wx.navigateBack()}1000)

}})

添加选项页的运行效果如图一所示。

【代码解析】新增选项页面之后需要与新增子选项复用,所以我们编写代码的时候要兼顾两者。同样先在JSON文件中导入用到的UI组件。表单上只有一个input需要输入,提交的时候判断是否为空、是否过长即可。如果是首页选项,就保存在homeList中,子选项则以首页选项的名字为key保存。添加完成后,首页如下下图所示。

【添加选项页】

【首页效果】

2.3 抽签页面开发

现在首页已经有了选项,并且可以通过新增页来增加。此时可以开发抽签页,列出子选项,用于抽签。打开draw-view页面,输入以下代码:

// draw-view.json

"navigationBarTitleText":"抽签""usingComponents":{
"i-button":"/dist/button/index"
"i-cell-group":"/dist/cell-group/index","i-cell":"/dist/cell/index","i-modal":"/dist/modal/index"

// draw-view.wxml
<i-button type="primary" bind:click="addItem">添加子选项</i-button><i-button type="success" bind:click="draw">抽签</i-button>

<i-cell-group><i-cell
wx:for="{{listData}}" wx:for-item="item" wx:key="item"
data-item="{{item}}" title="{{item}}"
bindlongpress="delete"></i-cell></i-cell-group>

<i-modal title="删除确认"visible="{{ visible }}" actions="{{ actions }}"
bind:click="realDelete">
<view>删除后无法恢复哦</view></i-modal>

// draw-view.js
//pages/draw-view/draw-view.js Page({
data:{
listData:[], lastItem:''
currentItem:'', actions:[{
name:'取消'}name:'删除'color:'#ed3f14', loading:false}
]visible:false}onLoad:function(options){
this.setData({
lastItem: options.item

wx.setNavigationBarTitle({
title: options.item,})}onShow:function() {
this.setData({
listData:wx.getStorageSync(this.data.lastItem)})}//添加子选项 addItem() {
wx.navigateTo({
url:'../edit-item/edit-item?item='+ this.data.lastitem
})}// 抽签 draw(){
if (this.data.listData.length == 0) { wx.showToast({
title:'没有数据', icon:'none'})
} else {
const randomNumber=this.getRandomNumber(0,
this.data.listData.length);
wx.showToast({
title:this.data.listData[randomNumber]})

}// 获取随机数
getRandomNumber(begin,end){
return Math.floor(Math.random() * (end-begin))+ beging}// 删除子选项弹窗 delete(e){
this.setData({
visible: true,
currentItem: e.currentTarget.dataset.item
});
}// 删除子选项
realDelete({detail}) {
if (detail.index=== 1) {
var newArray=[];
for (const item of this.data.listData){
if (item!= this.data.currentItem){
newArray.push(item);
)}
this.setData({
listData: newArray})
wx.setStorageSync(this.data.lastItem,this.data.listData); wx.showToast({
title:'删除成功'})}
this.setData({
visible:false});}
})

添加子选项后,点击“抽签”按钮,运行效果如图所示。

【代码解析】进入页面后,会根据上一个页面传入的选项名来获取存储的子选项数据。点击“抽签”按钮,会通过随机数从现有子选项中抽取一个进行弹窗显示。添加、删除子选项功能与首页的基本相同。

2.4 我的页面开发

通过前面3个页面的开发,主要的抽签流程已经走通了。为了完善这个应用,补充“我的”页面,增加清空、微信登录功能。打开mine页面,输入以下代码:

// mine.json{
"navigationBarTitleText":"我的""usingComponents":{
"i-card":"/dist/card/index"
"i-button":"/dist/button/index"
"i-cell-group":"/dist/cell-group/index""i-cell":"/dist/cell/index","i-modal":"/dist/modal/index"

// mine.wxml
<view class="view-margin">
<i-card
title="{{userInfo.nickName}}"
extra="{{userInfo.country}}"
thumb="{{userInfo.avatarUrl}}">
<!-- <view slot="content">用户名:张三</view> --></i-card>
</view>

<view class="view-margin"><i-cell-group><i-cell
title="清空数据"
bindtap="clearData" is-link></i-cell><i-cell
title="意见反馈"
bindtap="callBack" is-link></i-cell></i-cell-group></view>

<i-button
wx:if="{{userInfo.nickName=='未登录'}}" type="primary"
open-type="getUserInfo"
bind:getuserinfo="login">登录</i-button>

<i-button
wx:if="{{userInfo.nickName!='未登录'}}" type="error"
bind:click="logout">退出登录</i-button>

<i-modal
title="清空确认"
visible="{{ visible }}" bind:ok="delete"
bind:cancel="cancel">
<view>清空后无法恢复哦</view></i-modal>

// mine.wxss.view-margin{
margin-top:16px;}

// mine.js Page({
data:{
userInfo:{
nickName:'未登录', country:'-',
avatarUrl:'https://i.loli.net/2017/08/21/599a521472424.jpg

visible:false

onLoad(options){
if (wx.getStorageSync('userInfo')){ this.setData({
userInfo: wx.getStorageSync('userInfo')
})
}clearData(){
this.setData({ visible:true

}delete() {
const array=wx.getstorageSync('homeList') for (const item of array) {
wx.removeStorageSync(item)}
wx.removeStorageSync('homeList') this.setData({ visible:false

cancel() {
this.setData({ visible:false})}login(e){
if (e.detail.userInfo){
this.setData({
userInfo: e.detail.userInfo})
wx.setStorageSync('userInfo',e.detail.userInfo)} else {
wx.showToast({
title:'登录失败', icon:'none'})
}
}logout() {
wx.removeStorageSync('userInfo'y this.setData({
userInfo:{
nickName:'未登录', country: '-',
avatarUrl:"https://i.loli.net/2017/08/21/599a521472424.ipq
}
})}})

在“我的”页面点击“登录”按钮,会弹出权限申请框,点击允许授予权限后即可登录,运行效果如图所示。

【代码解析】清空数据通过循环homeList里的数据把所有数据移除掉。登录功能在用户,点击允许按钮后,从e.detail.userInfo取出用户的头像、昵称等信息进行展示,并通过wxif控制“显示登录”或“退出登录”按钮。如果需要测试,可以点击微信开发工具中的“清缓存→清除登录状态”,如图所示。

3.小结

本章综合运用前面学到的知识创建了一个易用的工具类应用。虽然该程序的基本功能已经齐全,但是仍有较大的改进空间。建议读者自行添加编辑选项、改变排序等功能来作为练习。为了将各种知识分类展示,本章的内容仅使用了本地存储,没有设计网络请求。下一章我们将做一个带网络请求的完整应用。

有关【微信小程序】项目实战—抽签应用的更多相关文章

  1. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  2. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  3. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  4. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  5. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  6. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  7. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

  8. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  9. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  10. ruby-on-rails - 如何在 Gem 中获取 Rails 应用程序的根目录 - 2

    是否可以在应用程序中包含的gem代码中知道应用程序的Rails文件系统根目录?这是gem来源的示例:moduleMyGemdefself.included(base)putsRails.root#returnnilendendActionController::Base.send:include,MyGem谢谢,抱歉我的英语不好 最佳答案 我发现解决类似问题的解决方案是使用railtie初始化程序包含我的模块。所以,在你的/lib/mygem/railtie.rbmoduleMyGemclassRailtie使用此代码,您的模块将在

随机推荐