目的
为了深入学习微信小程序编程,设计一款简洁的背单词的小程序。
开发前准备
1.页面结构
懒人单词小程序的页面有上下2个区域组成,content和tab。
content区域可以通过左右滑动实现标签页的切换。关于2个标签具体说明:
-
单词学习:显示英语单词书。
-
生词本:显示在单词书里添加的不认识的单词。
tab区域用于显示“单词学习”和“生词本”2个标签的标题。如果当前位于某个标签下,该标签页会显示红色,并且字体也为红色,其他标签页文字和线条显示白色。
2.目录结构
主要文件夹 | 说明 |
---|---|
index | 里面包含index.wxml,js,wxss和disbook.wxml |
study | 单词学习页面的结构、样式和逻辑 |
BookDetail | 生词详情页面的结构、样式和逻辑 |
标签页切换
1.实现标签页的切换
swiper组件是滑块容器视图,用于轮播图,本项目用于标签页的切换。
切换标签页有两种方式,一种是直接滑动content区域,另一种是点击tab区域中的某一个标签对应切换。先为3个tab-item绑定事件,并设置data-item属性。
<view class="tab-item {{tab==0?'active':''}}" bindtap="changeItem" data-item="0">单词学习</view>
<view class="tab-item {{tab==1?'active':''}}" bindtap="changeItem" data-item="1">生词本</view>
上述代码中,data-item的值表示swiper 组件中对应的 swiper-item的索引。
接下来修改content区域,为swiper组件的current属性绑定变量item,如下:
<view class="content">
<swiper current="{{item}}" >
完成后在js文件中,将changeItem中 item的值设为data-item的值,如下:
changeItem: function(e) {
this.setData({
item: e.target.dataset.item,
})
}
使用e.target.dataset.item 会获取当前点击的元素的 data-item 的item 值。
切换标签页后改变当前标签样式,通过判断变量tab 的值来为当前活跃的data-item 增加一个 active 样式,具体代码:
<view class="tab-item {{tab==0?'active':''}}" bindtap="changeItem" data-item="0">单词学习</view>
<view class="tab-item {{tab==1?'active':''}}" bindtap="changeItem" data-item="1">生词本</view>
active样式:
.tab-item.active {
color: #c25b5b;
border-bottom-color: #c25b5b;
}
为了更改tab值,给swiper组件绑定改变事件,如下:
<view class="content">
<swiper current="{{item}}" bindchange="changeTab">
changeTab会在swiper组件发生标签页切换时调用。如下:
data:{
item: 0,
tab: 0,
},
changeTab: function(e) {
this.setData({
tab: e.detail.current
})
}
单词学习
1.单词书页面
view 布局 添加类名,绑定catchtab点击事件,如下:
<view class="list-item" catchtap="clickFirst">
<image src="../images/four.jpg" />
<view>四级单词</view>
</view>
bindtap :子元素使用bindtap绑定事件后,执行的时候,会冒泡到父元素(触发父元素上绑定的bingtap事件)
catchtap :不会冒泡到父元素上,阻止事件冒泡
catchtab点击事件的跳转用wx.navigateto,js代码如下:
clickFirst: function () {
wx.navigateTo({
url: '../study/detail?title=四级单词',
})
},
wx.navigateto:保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。
wx.redirectTo:关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。
2.单词详情页面
分为内容区和按钮区,内容区需要从数据库中去获取单词信息,在应用到页面上。js代码如下:
var list = require("../../data/word-list");
Page({
data:{
words:"",
soundmark:"",
definition:"",
show:false,
},
onLoad: function (options) {
var title = options.title
if (title) {
wx.setNavigationBarTitle({
title: title,
})
}
var id = Math.floor(Math.random() * 499) + 1;
var word = list.wordList[id];
this.setData({
words: word.content,//数据存储到data里的
soundmark: word.pron,
definition: word.definition,
show: false,
title: title,
});
},
list 是一个js 文件的单词数据,通过options获取上个页面的title来选择对应词书的单词,从list里面随机取单词,把获取到的数据存进data中,在页面显示,如下:
<view class="cet">
<view class="wordPart">
<text class="word">{{words}}</text>
<view class="soundmark">
<image class = 'soundmark-icon' src = "../../pages/images/pron-icon.png"></image>
<text class = "word-pron" bindtap='read'>|{{soundmark}}|</text>
</view>
</view>
<text wx:if = "{{show}}" class = "word-definition">{{definition}}</text>
</view>
内容区显示完成后,来编写按钮区,添加button,在按钮上绑定监听事件,如下:
<view class="btns">
<button class = "button miss" catchtap='show' wx:if='{{!show}}'>不认识</button>
<button class = "button miss" wx:if='{{show}}'>已加入错词本</button>
<button class = "button next" catchtap='next'>下一个</button>
<button class = "button back" catchtap='back'>返回首页</button>
</view>
wx:if =‘{{!show}}’ 来判断是否渲染该代码块,给show默认赋值 false,点击后 为true ,在将该单词加入云数据库wordlist里,代码如下:
show: function () {
this.setData({
show: true
})
db.collection('wordlist').add({
data:{
content:this.data.words,//调用上面data里的数据
definition:this.data.definition,
pron:this.data.soundmark,
}
}).then(res=>{})
},
点击下一个按钮,在从list 中随机取出一个单词,代码如下:
next: function () {
var data = {
title: this.data.title
}
this.onLoad(data);
},
3.生词本
在标签页切换到生词本时,生词本将从云数据库中调出所有单词,显示在页面上,代码如下:
<scroll-view class="content-disbook" scroll-y><!-- scroll-view 滚动视图,scroll-y 纵向滚动 ,并在WXSS里添加一个滚动高度 -->
<view wx:for="{{DataList}}" wx:key="_id"><!-- wx:for 遍历显示数据 -->
<view class="errorword">
<view data-val="{{item._id}}" bindtap="transfer">{{item.content}}</view>
</view>
</view>
</scroll-view>
scroll-view 组件用于实现可滚动视图区域,scroll-y 允许纵向滚动,scroll-x 允许横向滚动。
生词本列表显示写在onShow()事件中,onShow方法是在每次从小程序的前后台切换时都执行的,onLaunch方法是在小程序加载时执行的,因为该页面会多次切换所有选择onShow(),代码如下:
var opid = wx.getStorageSync('openid')
onShow:function(){/* 刷新的数据写在onshow()里 */
let THIS = this
db.collection('wordlist').where({
_openid:opid
}).get().then(res => {
THIS.setData({
DataList:res.data
})
})
},
生词本显示的单词应该是登陆该小程序用户自己添加的,所以应该获取用户的openid,来和数据库中单词的_openid 字段进行配对,通过调用云函数来获取打开小程序用户的openid,代码如下:
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
return {
event,
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID,
}
}
在transfer 点击事件中使用方法e.target.dataset.val会获取当前点击的元素的val 里的当前单词_id值,通过对应id值跳转到对应单词的详情页面,代码如下:
transfer(e){
var id=e.target.dataset.val;
wx.navigateTo({
url: '../BookDetail/BookDetail?id='+id,
})
},
跳转到生词本单词的详情页面,页面结构:内容区和按钮区,代码如下:
<view wx:for="{{words}}" wx:key="*this">
<view class="cet" >
<view class="wordPart">
<text class="word">{{item.content}}</text>
<view class="soundmark">
<image class = 'soundmark-icon' src = "../../pages/images/pron-icon.png"></image>
<text class = "word-pron" >|{{item.pron}}|</text>
</view>
</view>
<text class = "word-definition">{{item.definition}}</text>
<view class="btns">
<button data-val="{{item._id}}" bindtap="remove">已认识</button>
<button class = "button back" catchtap='back'>返回生词本</button>
</view>
</view>
</view>
words 也可以遍历循环,直接{{words.属性名}} 调用
在生词页面跳转到单词详情页面时,初始加载写在onLoad()里,代码如下:
Page({
data:{
words:"",
},
onLoad:function(options){
var ids=options.id;//将列表页面的id赋值
let that=this
db.collection('wordlist').where({//通过id查询数据
_id:ids,
}).get().then(res => {
// res.data 包含该记录的数据
that.setData({
words:res.data
})
})
已认识按钮点击后执行删除操作,从数据库中删除该单词,代码如下:
remove:function(e){
var id=e.target.dataset.val;
db.collection('wordlist').where({
_id:id //通过id 删除
}).remove({
success: function(res) {
}
})
wx.navigateBack()
},
暂时小程序的基本功能都已实现了,未来还会继续添加完善更多的功能,比如增加单词的趣味性玩法,好友PK等等。
下面附上小程序截图:
CSS样式代码我就不写了,本人审美不行。