前言
总觉得小程序是一种神奇的存在,不用下载安装就能快速使用,而且还不会占用手机内存(毕竟我的手机内存需要留给各种帅哥,嘻嘻)。作为一个前端学习者,在钱的诱惑下决定自己手撸一个小程序。打开自己手机的小程序,发现长的好看一点的也就coco奶茶了,啧啧,那叫一个小清新,于是就开始了我的小程序之旅。终于在我坚持不懈的努力下,写出了个大概。在此分享我的一些心得,希望能给正在学习小程序的小伙伴们一些帮助。
开发工具
- 微信小程序开发工具
- 微信小程序官方文档
- Vscode前端开发工具
- Easy Mock一个可视化,并且能快速生成模拟数据的持久化服务。
小程序主要页面及其功能
首页
首页最主要的就是swiper滑动,这是小程序最常见的功能,其次是底部的tabBar,需要在app.json中先定义好,包括页面跳转,点击一个tab时颜色提亮
<swiper indicator-dots="{{true}}" indicator-active-color="#ff7e00" autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}">
<block wx:for="{{imgUrls}}" wx:key="index">
<swiper-item>
<image src="{{item}}" class="slide-img" mode='aspectFill' />
</swiper-item>
</block>
</swiper>
Page({
data: {
imgUrls:[
'../../images/1.jpg',
'../../images/2.jpg',
'../../images/3.jpg',
'../../images/4.jpg'
],
autoplay:true,
interval:3000,
duration:500
},
order: function(opotions){
wx.navigateTo({
url: '../../pages/choose/choose',
})
},
})
首页及点击tab截图,在我的页面中获取头像和昵称
{
"pages": [
"pages/index/index",
"pages/choose/choose",
"pages/destination/destination",
"pages/address/address",
"pages/order/order",
"pages/mine/mine",
"pages/position/position"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "CoCo都可",
"navigationBarTextStyle": "black"
},
"tabBar": {
"color": "#b7b7b7",
"selectedColor": "#AB956D",
"borderStyle": "black",
"backgroundColor": "#f5f5f5",
"selectedindex": 1,
"list": [
{
"pagePath": "pages/index/index",
"iconPath": "/images/首页1.png",
"selectedIconPath": "/images/首页.png",
"text": "首页"
},
{
"pagePath": "pages/order/order",
"iconPath": "/images/订单1.png",
"selectedIconPath": "/images/订单.png",
"text": "订单"
},
{
"pagePath": "pages/mine/mine",
"iconPath": "/images/我的1.png",
"selectedIconPath": "/images/我的.png",
"text": "我的"
}
]
},
"sitemapLocation": "sitemap.json"
}
点单页面
父组件
<view class="main">
<view class="category-left">
<view wx:for="{{category}}" wx:key="{{item.id}}" data-id="{{item.id}}" data-index="{{index}}" class="cate-list {{curIndex === index ? 'on' : ''}}" bindtap="switchTap">
{{item.name1}}
</view>
</view>
<scroll-view class="category-right" scroll-y scroll-into-view="{{toView}}" scroll-with-animation="{{true}}" style="height:{{conHeight}}rpx;" bindscroll="onScroll">
<block wx:for="{{detail}}" wx:key="{{item.id}}">
<view id="{{item.id}}" bindtap="test" data-index="{{index}}">
<view class="cate-title">
<text>{{item.cate}}</text>
</view>
<view class="cate-box" wx:for="{{item.detail}}" wx:key="{{item.id}}">
<image src="{{item.images1}}" class="img1" />
<view class="drink-name">{{item.name}}</view>
<view class="drink-box">
<text class="drink-price">¥{{item.price}}</text>
<image src="{{item.images3}}" class="drink-reduce" bindtap="reduceCount" data-index="{{index}}"/>
<text class="num">{{item.num}}</text>
<image src="{{item.images2}}" class="drink-add" bindtap="addCount" data-index="{{index}}" data-name="{{item.name}}" data-price="{{item.price}}" />
</view>
</view>
</view>
</block>
</scroll-view>
<count id="count" title="{{countname}}" money="{{countprice}}" nums="{{countnum}}">
</count>
<!-- <information id="information"></information> -->
<view class="footer">
<view class="total">
<image src="../../images/购物车1.png" class="quantity" bindtap="Selected" />
<view wx:if="{{isShow}}">
<view class="total_quantity">{{totaledquantity}}</view>
</view>
</view>
<view class="sum">¥{{totalprice}}</view>
<view class="account" bindtap="Account">去结算</view>
<image src="../../images/arrows.png" class="arrows" />
</view>
</view>
const API = 'https://www.easy-mock.com/mock/5ce7ede7b3ab8d779e20e856/Drink/Drink'
Page({
data:{
totalprice:0,
totaledquantity:0,
isShow:0,
category:[
{name1:'季节限定',id:'season'},
{name1:'醇香奶茶',id:'chunxiang'},
{name1:'醇黑浓情',id:'chunhei'},
{name1:'鲜果鲜茶',id:'xianguo'},
{name1:'白色恋人',id:'baise'},
{name1:'咖啡时光',id:'cofei'},
],
detail:[],
countname:0,
countprice:0,
countnum:0,
menuIndex: 0
},
test (e) {
console.log(e.currentTarget.dataset.index)
this.setData({
menuIndex: e.currentTarget.dataset.index
})
},
addCount:function(e){
console.log(e.currentTarget.dataset.index)
this.count.show();
this.setData({
countname:e.target.dataset.name,
countprice:e.target.dataset.price,
})
const index = e.target.dataset.index
console.log(e);
let carts = this.data.detail
console.log(carts)
let num = carts[this.data.menuIndex].detail[index].num
console.log(num)
let price = carts[this.data.menuIndex].detail[index].price
console.log(price)
num = num + 1
carts[this.data.menuIndex].detail[index].num = num
console.log(carts)
this.setData({
detail:carts,
isShow:1,
countnum:num
})
this.getTotalprice()
this.getTotalnum()
},
reduceCount: function(e){
const index = e.target.dataset.index
console.log(e);
let carts = this.data.detail
console.log(carts)
let num = carts[this.data.menuIndex].detail[index].num
console.log(num)
if(num > 0){
num = num - 1
}else{
return num
}
carts[this.data.menuIndex].detail[index].num = num
console.log(carts)
this.setData({
detail:carts
})
this.getreducenum()
this.getreduceprice()
},
getTotalprice(){
let carts = this.data.detail
let total = 0
let total1 = 0
for(let i = 0; i<carts.length;i++){
for(let j = 0; j<carts[i].detail.length;j++){
if(carts[i].detail[j].price){
total +=carts[i].detail[j].num * carts[i].detail[j].price
total1 =(parseFloat(total)).toFixed(1)
}
}
}
this.setData({
totalprice: total1
})
},
getreduceprice(){
let carts = this.data.detail
let total2 = 0
for(let i = 0; i<carts.length;i++){
for(let j = 0; j<carts[i].detail.length;j++){
if(carts[i].detail[j].price){
total2 -=carts[i].detail[j].num * carts[i].detail[j].price
var total3 = (parseFloat(Math.abs(total2))).toFixed(1)
}
}
}
this.setData({
totalprice: total3
})
},
getTotalnum(){
let carts = this.data.detail
let totalnum = 0
for(let i = 0; i<carts.length;i++){
for(let j = 0; j<carts[i].detail.length;j++){
if(carts[i].detail[j].num){
totalnum +=carts[i].detail[j].num
}
}
}
this.setData({
totaledquantity: totalnum
})
},
getreducenum(){
let carts = this.data.detail
let totalnum = 0
for(let i = 0; i<carts.length;i++){
for(let j = 0; j<carts[i].detail.length;j++){
if(carts[i].detail[j].num){
totalnum =carts[i].detail[j].num
}
}
}
this.setData({
totaledquantity: totalnum,
})
},
switchTap(e){
console.log(e);
this.setData({
toView:e.target.dataset.id,
curIndex:e.target.dataset.index
})
},
onLoad: function (options) {
let self = this
wx.request({
url:API,
method:'get',
success(res){
self.setData({
detail:res.data
})
console.log(res);
}
})
},
onReady: function () {
this.count = this.selectComponent('#count');
// this.information = this.selectComponent('#information');
},
Account: function(){
var that = this
wx.navigateTo({
url: '../../pages/destination/destination?allprice=' + that.data.totalprice +
'&allquantity=' + that.data.totaledquantity + '&show=' + that.data.isShow
})
},
子组件
在子组件中选择属性时会使其背景颜色发生改变,原理是在点击属性框时给其添加一个类名active
<!-- components/count/count.wxml -->
<view class="wx-count" hidden="{{flag}}" bindtap="Close">
<view class="count-container" >
<view class="count-title">{{title}}</view>
<view class="count-metarial">{{metarial}}</view>
<view class="main1">
<button wx:for="{{metarials}}" wx:key="index" class="count-normal {{item.active ? 'active' : ''}}" bindtap="Change" data-taget="{{item.name}}" data-index="{{index}}">{{item.name}}</button>
</view>
<view class="count-temperature">{{temperature}}</view>
<view class="main2">
<button wx:for="{{temperatures}}" wx:key="index" class="normal-ice {{item.active1 ? 'active1' : ''}}" bindtap="Change1" data-taget="{{item.name}}" data-index="{{index}}">{{item.name}}</button>
</view>
<view class="count-sugar">{{sugar}}</view>
<view class="main3">
<button wx:for="{{sugars}}" wx:key="index" class="normal-sugar {{item.active2 ? 'active2' : ''}}" bindtap="Change2" data-taget="{{item.name}}" data-index="{{index}}">{{item.name}}</button>
</view>
<view class="count-prcie">{{money}}</view>
<!-- <view class="count-num">{{nums}}</view> -->
<button class="count-add" bindtap="Add">{{add}}</button>
</view>
</view>
// components/count/count.js
const app = getApp()
Component({
/**
* 组件的属性列表
*/
options: {
multipleSlots: true // 在组件定义时的选项中启用多slot支持
},
// parent
properties: {
title:{
type: String,
value: ''
},
money:{
type: String,
value:''
},
nums:{
type: Number,
value:''
}
},
/**
* 组件的初始数据
*/
data: {
flag:true,
// title:'',
metarial:'加料',
metarials: [
{name:'常规'},
{name:'珍珠'},
{name:'椰果'}
],
temperature:'温度',
temperatures:[
{name:'常温'},
{name:'多冰'},
{name:'少冰'},
{name:'去冰'},
],
sugar:'糖度',
sugars:[
// {name:'常规糖'},
{name:'半糖'},
{name:'微糖'},
{name:'不加糖'},
],
// money:'',
add:'加入购物车',
flag: true,
isActive: false,
cart: []
},
/**
* 组件的方法列表
*/
methods: {
Change:function(e){
var that = this
let index = e.currentTarget.dataset.index
console.log(e.currentTarget.dataset.index);
for (let i = 0; i < that.data.metarials.length; i++) {
let cencal = `metarials[${i}].active`
that.setData({
[cencal]: false
})
}
let test = `metarials[${index}].active`
that.setData({
[test]: true
})
app.globalData.cart.metarial = that.data.metarials[index].name || '常规'
console.log(app.globalData.cart);
},
Change1: function(e){
var that = this
let index = e.currentTarget.dataset.index
console.log(e.currentTarget.dataset.index);
for (let j = 0; j < that.data.temperatures.length; j++) {
let cencal1 = `temperatures[${j}].active1`
that.setData({
[cencal1]: false
})
}
let test1 = `temperatures[${index}].active1`
that.setData({
[test1]: true
})
app.globalData.cart.temperature = that.data.temperatures[index].name || '常温'
console.log(app.globalData.cart);
},
Change2: function(e){
var that = this
let index = e.currentTarget.dataset.index
console.log(e.currentTarget.dataset.index);
for (let k = 0; k < that.data.sugars.length; k++) {
let cencal2 = `sugars[${k}].active2`
that.setData({
[cencal2]: false
})
}
let test2 = `sugars[${index}].active2`
that.setData({
[test2]: true
})
app.globalData.cart.sugar = that.data.sugars[index].name || '半糖'
console.log(app.globalData.cart);
},
//隐藏弹框
hide: function () {
this.setData({
flag: true
})
},
//展示弹框
show: function () {
this.setData({
flag: false
})
},
Add: function(e){
var that = this;
console.log(this.data.metarials);
if (!app.globalData.cart.metarial) {
app.globalData.cart.metarial = '常规'
}
if (!app.globalData.cart.C) {
app.globalData.cart.temperature = '常温'
}
if (!app.globalData.cart.sugar) {
app.globalData.cart.sugar = '半糖'
}
app.globalData.cart.title = that.data.title
app.globalData.cart.money = that.data.money
app.globalData.cart.nums = that.data.nums
app.globalData.carts.push(app.globalData.cart)
app.globalData.cart = {}
console.log(app.globalData.carts);
this.setData({
flag:true
})
},
}
})
订单页面
const QQMapWX = require('./libs/qqmap-wx-jssdk.js');
const qqmapsdk = new QQMapWX({
key: '56JBZ-HXH6P-OR7DG-VF2DH-NZVPS-OFFRO'
});
//app.js
App({
onLaunch: function () {
// 展示本地存储能力
var logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
// 登录
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
}
})
// 获取用户信息
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
wx.getUserInfo({
success: res => {
// 可以将 res 发送给后台解码出 unionId
this.globalData.userInfo = res.userInfo
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
if (this.userInfoReadyCallback) {
this.userInfoReadyCallback(res)
}
}
})
}
}
})
},
globalData: {
userInfo: null,
destination:'',
qqmapsdk,
activity_lat: null,
activity_lng:null,
activity_location:null,
activity_address:null,
cart: {},
carts: []
}
})
const app = getApp()
Page({
data: {
latitude: 0,//地图初次加载时的纬度坐标
longitude: 0, //地图初次加载时的经度坐标
name: "" ,//选择的位置名称
address:"",
totaledquantity:0,
totalprice:0,
isShow: 0,
Hidden: true,
selectAllStatus: false
},
Account: function(){
this.setData({
Hidden:false
})
},
Close: function(){
this.setData({
Hidden:true
})
},
Select: function() {
let selectAllStatus = this.data.selectAllStatus
selectAllStatus = !selectAllStatus
this.setData({
selectAllStatus: selectAllStatus
})
},
Gopay: function(){
wx.switchTab({
url: '../../pages/index/index',
})
},
Choose: function(res){
let self = this
wx.chooseLocation({
success: function(res){
console.log(res);
app.globalData.activity_lat = res.latitude;
app.globalData.activity_lng = res.longitude;
app.globalData.activity_location = res.name;
app.globalData.activity_address = res.address;
self.setData({
name: res.name,
address:res.address
})
console.log(app.globalData.activity_location);
},
})
},
onLoad: function (options) {
console.log(typeof(options.show))
var that = this
that.setData({
totaledquantity: options.allquantity,
isShow: Number(options.show) || 0,
totalprice: options.allprice
})
},
onReady: function () {
let carts = app.globalData.carts
this.setData({
carts:carts
})
console.log(app.globalData.carts)
},
})
结算页面
<action-sheet hidden="{{Hidden}}" >
<view class="mainBox">
<view class="bigBox">
<view class="top_box">
<view class="close" bindtap="Close">X</view>
<view class="pay_title">支付</view>
<view class="sum_price">订单总价</view>
<view class="totaledPrice">¥{{totalprice}}</view>
</view>
<view class="mindle_box">
<view class="pay_way">支付方式</view>
<view class="pay_choose">
<view class="icon">
<image src="../../images/微信支付.png" class="weichat_pay"/>
</view>
<view class="wechat">微信支付</view>
<icon wx:if="{{selectAllStatus}}" bindtap="Select" class="pay_select" color="#f17c0e" type="success_circle" />
<icon wx:else type="circle" color="#f17c0e" bindtap="Select" class="pay_select"/>
</view>
</view>
<view class="under_box">
<view class="confirm" bindtap="Gopay">
<view class="words">确认支付{{totalprice}}元</view>
</view>
</view>
</view>
</view>
</action-sheet>
全部的效果图展示
寄语
以上是我对我小程序简单粗暴式的总结,作为一个初学小程序的小菜鸟,还有许多不足和需要学习的地方。望各位走过路过的小可爱们给我点个赞哈。 附上我的源码地址[github.com/Yanhuan111/…]