先来些小程序的基础知识开开胃。主要是熟悉熟悉语法,没怎么记住小程序的 API,它的编程套路就运用的不是太熟练,用到的时候在去看文档,又浪费了自己的时间,还得从新开头,有一种方法就是看自己得笔记,忘了回来看几乎一眼秒懂,多看一眼都是浪费。
一、计数器
index.js 文件
Page({
data: {
a : 0
},
add(){
this.setData({
a : this.data.a + 1
})
}
});
index.wxml 文件:
{{a}}
<button type="primary" bindtap="add">按我加一</button>
来看看效果:
这个 data 很明显不是 Vue 得双向绑定,没错就是抄 React 得 state。
bindtap
不能直接函数调用使用小括号往里面传值,所以函数调用传值我们一般使用自定义属性,然后通过 e.target.dataset
来获取,相比之前函数调用传值是麻烦不少 :
index.wxml 文件
<button type="primary" bindtap="add" data-id="10">获取ID</button>
index.js 文件:
Page({
add(e){
console.log(e.target.dataset.id);//10
}
});
二、小程序发送 Ajax
wx.request({
url: 'https://www.meimichao.com/bee/uploadHandler',
data: {"city":"123"},
method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
//header: {"Content-Type":"application/x-www-form-urlencoded"}, // 设置请求的 header
success: function(res){
console.log(JSON.stringify(res));
},
fail: function(res) {
console.log(JSON.stringify(res));
},
complete: function() {
// complete接口调用结束的回调函数(调用成功、失败都会执行)
}
});
玩过 Jquery 得人都懂没啥讲的。过过。。。
三、 获取屏幕高度
一共两个方法,特别像 NodeJs 中得 fs 模块,提供同步和异步选择。获取手机屏幕高度有什么用,通常来讲是用来做瀑布流的,我们一般在结合 scroll-view 使用,因为 scroll-y 竖直方向的滚动必须提供一个高度,如果 scroll-view 的高度这时恰好等于屏幕高度,那么整个手机屏幕都是滚动区域了
- 异步方法
wx.getSystemInfo({
success (res) {
console.log(res.windowHeight)
}
})
2.同步方法
try {
const res = wx.getSystemInfoSync()
console.log(res.windowHeight)
} catch (e) {
// Do something when catch error
}
四、全局变量
一些通用的变量放置在这里,例如:baseURL
app.js 文件夹里面进行定义,一般来讲字段叫做 globalData(你叫a,b,c,d...都行) 而且 global 都是当作对象来使用,例如:
App({
globalData: {
userInfo: 'Condor Hero'
}
});
任意一个页面的 .js
文件里面都能够通过 getApp()
得到:
const app = getApp();
console.log(app.globalData.userInfo)//Condor Hero
//app.js内部访问
console.log(this.globalData.userInfo);
另一种挂在到全局的方法是:
App.config = {name:'Condor Hero'};
App({});
任意一个页面的 .js
文件里面都能够直接得到:
App.config.name
五、去掉导航栏
把导航栏变成通栏的形式:
去掉之前:
app.json 中加入代码:
"window": {
"navigationStyle": "custom"
}
去掉之后:
六、轮播图
index.js 文件
Page({
/**
* 页面的初始数据
*/
data: {
banners: [
{
'pic': 'b1.jpg'
},
{
'pic': 'b2.jpg'
},
{
'pic': 'b3.jpg'
},
{
'pic': 'b4.jpg'
}
],
indicatorDots: true,//是否显示面板指示
vertical: false,
autoplay: true,
interval: 2000,//滑动方向是否为纵向
duration: 500
}
})
index.wxml
<view>
<view class="swiper">
<swiper indicator-dots="{{indicatorDots}}" autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}">
<block wx:for="{{banners}}" wx:key="{{index}}">
<swiper-item>
<view class="swiper-item">
<image src="/images/{{item.pic}}"></image>
</view>
</swiper-item>
</block>
</swiper>
</view>
</view>
注意小程序图片标签是 image 不是 img,可以当作单标签使用也可以当作双标签使用,src 支持绝对路径和相对路径,当为绝对路径的时候, 一定要加/
前缀,小程序的索引路径一般使用绝对路径,因为如果你要想从项目目录去找图片的 ../../
好几次把人都给弄乱了,另外当你书写路径 /images/logo.png
默认直接去和 app.js 文件同级的 images 里面去查找,特别像 Vue 脚手架默认 @/assets/logo.png
中 @ 表示 src 目录一个道理。还有就是小程序没有<div>、<ul>、<h1>等所有标签。只有<view>标签。
image 的属性,其中lazy-load 上下三屏,如图示:横着表示手机屏。
index.wxss
.swiper-item image{
width: 750rpx;
height: 448rpx;
}
图片的宽度,在我设置为百分之百,图片的底部没能完全显示出来,所以人为的计算了下,1个屏幕是750rpx,图片宽度就是750rpx。
图片要等比,所以高度是
七、wxs语法
WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。可以简单理解为就是 JavaScript。
两者实在太像了:
- JavaScript 的代码是写在
<script></script>
标签里面,文件后缀名为.js
。 - WXS 代码可以编写在 wxml 文件中的
<wxs>
标签内,或以.wxs
为后缀名的文件内。
但是 wxs 又有模块的概念,每个模块都有自己独立的作用域。即在一个模块里面定义的变量与函数,默认为私有的,对其他模块不可见。
一个模块要想对外暴露其内部的私有变量与函数,只能通过 module.exports 实现。
更加需要注意的是:
WXS 不依赖于运行时的基础库版本,可以在所有版本的小程序中运行。
WXS 与 JavaScript 是不同的语言,有自己的语法,并不和 JavaScript 一致。所有ES6的新内容一律不能用,let、const、includes、对象k-v一致省略v、箭头函数都不能用。
WXS 的运行环境和其他 JavaScript 代码是隔离的,WXS 中不能调用其他 JavaScript 文件中定义的函数,也不能调用小程序提供的API。 wxs中定义的函数必须是纯函数。这个函数不能改变任何外部的值,只能返回新的字号。
WXS 函数不能作为组件的事件回调。
由于运行环境的差异,在 iOS 设备上小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍。在 android 设备上二者运行效率无差异。
定义一个 tool.wxs 文件:
function mianji(n) {
return n * n;
}
module.exports = {
mianji: mianji
}
wxml页面中,这样引入刚刚的代码片段:
<view>
<wxs src="./tool.wxs" module="tool"></wxs>
<view>
{{tool.mianji(3)}}
</view>
</view>
module就是命名空间,所有的函数必须打点调用。
一定记住,在 wxs 中,函数只看得见它的参数,看不见外部任何量,尤其是 data 里面的变量,要想使用 data 里面的变量,需要把 data 当做参数传进去,而不是在函数中直接this.data.a
。
同时要记住,小程序不能像 Vue 一样在结构层 wxml 中直接调用函数,例如:
<view>{{add()}}</view>
虽然并不报错,但是也没任何的效果。
总结:
小程序得
{{}}
不能调用除wxs
之外的一切函数:
小程序禁止:{{add()}}
小程序中不能调用除 wxs 之外的一切函数:
到此可以模仿一个小程序 军人体能成绩计算器
八、模板(template)
模板(template)
定义模板:使用 name 属性,作为模板的名字。
<template name="moban">
<view>
我喜欢{{dongwu}}
</view>
</template>
调用模板:使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入
<view class="content">
<scroll-view height="500px">
<template is="moban" data="{{dongwu:'兔子'}}"></template>
<template is="moban" data="{{dongwu:'河马'}}"></template>
</scroll-view>
</view>
is 属性可以使用 Mustache 语法,来动态决定具体需要渲染哪个模板。
模板引用当把 template 单独创立成一个WXML。提供两种文件引用方式 import 和 include。
<import src="tool.wxml"/>
<include src="tool.wxml"/>
- import 的作用域
如:C import B,B import A,在C中可以使用B定义的template,在B中可以使用A定义的template,但是C不能使用A定义的template - 相当于是把模板拷贝到 include 位置
九、tabBar 豆腐屑的右上角添加文本
小程序在选择完订单的时候,一般会出现提醒用户一共选了多少个。
主要代码:app.js 文件
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"iconPath": "/images/icon1.png",
"text": "首页"
},
{
"pagePath": "pages/scroll/scroll",
"iconPath": "/images/icon2.png",
"text": "日志"
}
]
},
设置 tabbar 角标为:
- index:tabBar 的哪一项,从左边算起,第一个为零
- text:显示的文本,超过 4 个字符则显示成
...
onLoad: function (options) {
wx.setTabBarBadge({
index: 1,
text: '1',
})
},
小程序动态隐藏底部的 tabbar:
微信小程序可以使用:wx.hideTabBar();来隐藏
uni-app 可以使用 uni.hideTabBar() 来隐藏。
给有右上角的小按钮增加一个点击事件来隐藏底部 tabbar 栏。
十、scroll-view 无穷滚动 (infinite scroll)
终于来到无穷滚动了,这个常用来做无限下拉滚动效果,利用使用竖向滚动时,必须要给 scroll-view 一个固定高度,一般为屏幕高(wh)。下面这个东西就是利用这个标签做的,你一定见过这种效果:
项目目录:
看看小程序的一个目录,你仔细想想是不是就是 Vue 或 React 的一个组件啊。还有一个放图片的目录:
cover-image:覆盖在原生组件之上的图片视图。
我放图片的时候如果使用
image
标签直接显示是这样的:使用 cover-image 后:
不用讲了吧,以后图片标签就是用 cover-image 标签。
基本布局:
scroll.wxml
<view class="view">
<view class="btn">
<button>杨幂</button>
<button>关晓彤</button>
<button>靳东</button>
<button>易烊千玺</button>
</view>
<scroll-view
style="height: 900rpx;border: 2px solid #ff66cc;"
scroll-y="true"
class="scroll"
>
<view id="yangmi">
<view class="pic">
<cover-image src="/images/yangmi/1.jpg"></cover-image>
<cover-image src="/images/yangmi/2.jpg"></cover-image>
<cover-image src="/images/yangmi/3.jpg"></cover-image>
<cover-image src="/images/yangmi/4.jpg"></cover-image>
<cover-image src="/images/yangmi/5.jpg"></cover-image>
</view>
</view>
<view id="guanxiaotong">
<view class="pic">
<cover-image src="/images/guanxiaotong/1.jpg"></cover-image>
<cover-image src="/images/guanxiaotong/2.jpg"></cover-image>
<cover-image src="/images/guanxiaotong/3.jpg"></cover-image>
<cover-image src="/images/guanxiaotong/4.jpg"></cover-image>
<cover-image src="/images/guanxiaotong/5.jpg"></cover-image>
</view>
</view>
<view id="jindong">
<view class="pic">
<cover-image src="/images/jindong/1.jpg"></cover-image>
<cover-image src="/images/jindong/2.jpg"></cover-image>
<cover-image src="/images/jindong/3.jpg"></cover-image>
<cover-image src="/images/jindong/4.jpg"></cover-image>
<cover-image src="/images/jindong/5.jpg"></cover-image>
</view>
</view>
<view id="yiyangqianxi">
<view class="pic">
<cover-image src="/images/yiyangqianxi/1.jpg"></cover-image>
<cover-image src="/images/yiyangqianxi/2.jpg"></cover-image>
<cover-image src="/images/yiyangqianxi/3.jpg"></cover-image>
<cover-image src="/images/yiyangqianxi/4.jpg"></cover-image>
<cover-image src="/images/yiyangqianxi/5.jpg"></cover-image>
</view>
</view>
</scroll-view>
</view>
scroll.wxss
.view{
display: flex;
}
.scroll{
flex:2;
}
.btn{
flex:1;
}
.btn>button{
height: 20rpx;
width: 110px;
font-size: 14px;
margin: 20rpx 0;
border: 1px solid orange;
}
实现效果:
接下去就是让按钮和滚动区产生关系。先看两个API
滚动实现:scroll.wxml
<view class="view">
<view class="btn">
<button bindtap="changName" data-id="yangmi">杨幂</button>
<button bindtap="changName" data-id="guanxiaotong">关晓彤</button>
<button bindtap="changName" data-id="jindong">靳东</button>
<button bindtap="changName" data-id="yiyangqianxi">易烊千玺</button>
</view>
<scroll-view
style="height: 900rpx;border: 2px solid #ff66cc;"
scroll-y="true"
class="scroll"
scroll-into-view="{{who}}"
scroll-with-animation="true"
>...
</scroll-view>
</view>
scroll.js
Page({
data: {
who: "yangmi"
},
changName(e){
this.setData({
who:e.target.dataset.id
})
}
});
给按钮上色标记位置:
scroll.wxss 加上以下代码:
button.cur{
background-color: red;
}
同时改写 scroll.wxml 按钮位置代码:
<button class="{{who==='yangmi'?'cur':''}}" bindtap="changName" data-id="yangmi">杨幂</button>
<button class="{{who==='guanxiaotong'?'cur':''}}" bindtap="changName" data-id="guanxiaotong">关晓彤</button>
<button class="{{who==='jindong'?'cur':''}}" bindtap="changName" data-id="jindong">靳东</button>
<button class="{{who==='yiyangqianxi'?'cur':''}}" bindtap="changName" data-id="yiyangqianxi">易烊千玺</button>
按钮上完色的效果:
最后一步了,上面演示的都是按钮控制视图,现在滚动滚动区的时候按钮自动变化。先来看一个滚动事件的API说明:
思路到这里就清晰了,我们只需要算出五张杨幂的照片的高度,算出来的高度正好映射一个按钮。现在我们在算一张图片的高度。
使用下面的API:
scroll.wxml 文件给第一张杨幂的照片添加 一个 id 和 一个点击事件。
<cover-image bindtap="computedSize" id="imgHeight" src="/images/yangmi/1.jpg"></cover-image>
同时 scroll.js 文件添加对应的事件:
computedSize(){
const query = wx.createSelectorQuery();
query.select('#imgHeight').boundingClientRect();
query.selectViewport().scrollOffset();
query.exec(function (res) {
res[0].top // #imgHeight节点的上边界坐标
res[1].scrollTop // 显示区域的竖直滚动位置
console.log(res);
})
}
点击图片打印出来一个数据,数组的第一项里面就有 DOM 元素的宽和高:
最后求出来的值为
137.3249969482422
我们四舍五入取 137 就行。注意如果你不想点击图片在计算,可以使用图片的加载事件 bindload。改写如下:
<cover-image bindload="computedSize" id="imgHeight" src="/images/yangmi/1.jpg"></cover-image>
现在每张图片高为 137 ,一个明星一共有五张,一个明星按钮对应的高度为 137 * 5 = 685
,数据得到了现在就可以码代码了。改写 scrolling 事件。增加相应的条件判断。
scroll.js 的 scrolling 函数:
scrolling(e){
const { scrollTop } = e.detail;
if (scrollTop < 685 && this.data.who !== 'yangmi'){
this.setData({
who:'yangmi'
});
} else if (scrollTop > 685 && scrollTop < 1370 && this.data.who !== 'guanxiaotong'){
this.setData({
who: 'guanxiaotong'
});
} else if (scrollTop > 1370 && scrollTop < 2055 && this.data.who !== 'jindong') {
this.setData({
who: 'jindong'
});
} else if (scrollTop > 2055 && scrollTop < 2740 && this.data.who !== 'yiyangqianxi') {
this.setData({
who: 'yiyangqianxi'
});
}
}
修改完我们要的效果就做好了,一个小程序商城导航,效果如下:效果类似web端的楼层导航。
代码优化:
- 上面 scrolling 函数里面一直用到了,this.setData({}),我们可以使用一个函数来替代。条件判断的数值,万一改变了去代码里面改多麻烦,可以考虑用一个数组来替换,数组放在本文件的最上面。
- 每一个明星,应该对应一个数组,用数组来管理图片,这样在 wxml 里面就能使用 wx:for 了,同时 for 循环应该寻的是 template,template 里面也用 for 循环。
完,2019年12月11日23点29分