Create by jsliang on 2018-9-17 17:58:56
Recently revised in 2018-10-22 09:58:07javascript
Hello 小夥伴們,若是以爲本文還不錯,記得給個 star , 大家的 star 是我學習的動力!GitHub 地址css
2019-08-16 13:41:40 因爲這篇文章可能比較久遠,文章進行了微調,一些 bug 可能修復,或者其中一些連接壞了,請小夥伴們前往 GitHub 獲取最新文章。html
首個微信小程序實踐記錄:
工做量: PSD 18 張 (導出的 JPG 30 張)
耗時:12 個工做日
總結1: 在頁面製做商,須要 3 周工做日(工做 15 天)搞定,先後端對接口另計。實際上,12 個工做日能夠搞定全部頁面,可是應該往前鋪 1.5D 熟悉框架,日後鋪 1.5D 整理代碼。固然每一個人的耗時可能不一樣,可根據我的實際狀況進行調整。
總結2:在 API 調用上,根據接口數量可能須要 7-12 個工做日進行 API 調用,難點表如今: 1. 接口不夠豐富,數據量不足; 2. 接口數據不夠正式真實,跟前面的假數據相差太大; 3. 接口可能無法正常調用 等緣由。故因根據小程序業務邏輯進行工做時長的報備。前端
這裏有 jsliang 微信小程序開發中遇到的全部坑,以及在填坑過程當中的一些我的經驗。jsliang 利用這篇教程存儲一些經常使用的微信小程序開發技巧,方便查找。它可能教不了你什麼,但至少能省下你百度的功夫。java
請結合 《目錄》 和 《返回目錄》 來進行跳轉,得到更好的閱讀體驗。node
本文技術支持:Ansen江git
注1:因爲更新頻繁,有時候平臺上的文章版本可能沒有圖片或者目錄沒法跳轉,因此小夥伴須要獲取最新資料的,請前往 GitHub:地址github
注2:若是小夥伴使用的是手機版打開,那麼推薦小夥伴使用電腦打開,由於各平臺的手機端大都不支持頁內跳轉,看起來比較費勁。web
目前已有 48 個坑。數據庫
請各位按目錄檢索時注意:
3.一、3.二、3.3…… 等二級目錄對應着一個章節。
3.1.一、3.1.二、3.1.3…… 等三級目錄將該二級目錄這個大章節詳細拆分紅諸多小坑,方便查看。
本文章原名【微信小程序 100 坑】
微信小程序的開發教程,或許寫出來是很是受歡迎的。
可是:
因此,在這裏, jsliang 結合 「平常躺坑」 ,先爲你解決小程序的 100 個坑!雖然如今可能還不夠,可是第一天我就碰到 4/5 個了,我想我能夠幫大家躺完 100 個的!!!
如今的微信開發者工具顯示的開發版本是:"libVersion": "2.0.4"
若是你開發的版本已經解決了這個 bug ,或者你以爲這個 bug 還有其餘解決方法,或者你以爲這個玩意還有其餘 bug ,請告訴我,我會補充到這篇文檔上,順帶記上您的大名,謝謝!
QQ: 1741020489
這裏的坑:
但願小夥伴在百度中或者無心看到這篇文章,請熟練使用瀏覽器的 Ctrl + F
,查找須要的問題答案。
本組件目前已有 5 個坑,有興趣的小夥伴能夠詳看。
代碼來源於該地址:微信組件 swiper 。
爲方便小夥伴查看,下面貼出原版代碼:
demo.wxml
<swiper indicator-dots="{{indicatorDots}}"
autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}">
<block wx:for="{{imgUrls}}">
<swiper-item>
<image src="{{item}}" class="slide-image" width="355" height="150"/>
</swiper-item>
</block>
</swiper>
<button bindtap="changeIndicatorDots"> indicator-dots </button>
<button bindtap="changeAutoplay"> autoplay </button>
<slider bindchange="intervalChange" show-value min="500" max="2000"/> interval
<slider bindchange="durationChange" show-value min="1000" max="10000"/> duration
複製代碼
demo.js
Page({
data: {
imgUrls: [
'http://img02.tooopen.com/images/20150928/tooopen_sy_143912755726.jpg',
'http://img06.tooopen.com/images/20160818/tooopen_sy_175866434296.jpg',
'http://img06.tooopen.com/images/20160818/tooopen_sy_175833047715.jpg'
],
indicatorDots: false,
autoplay: false,
interval: 5000,
duration: 1000
},
changeIndicatorDots: function(e) {
this.setData({
indicatorDots: !this.data.indicatorDots
})
},
changeAutoplay: function(e) {
this.setData({
autoplay: !this.data.autoplay
})
},
intervalChange: function(e) {
this.setData({
interval: e.detail.value
})
},
durationChange: function(e) {
this.setData({
duration: e.detail.value
})
}
})
複製代碼
好的,上面就是微信官方文檔的演示代碼,若是你跟着演示代碼走了一遍碰到疑問的話,看看這裏我挖的土是否是能填好你的坑:
demo.wxml
中出現的 <image src="{{item}}" class="slide-image" width="355" height="150"/>
這行, width
和 height
的行內屬性是忽悠老百姓的,它並沒卵用 !咱們須要在 slide-image
這個 class
類中修改 width
和 height
。簡而言之,行內樣式都是騙人的,乖,咱們仍是去 demo.wxss
寫樣式吧~
在任何出現圖片的地方(包括但不限於輪播圖),若是你發現不只行內寫法無效以外,還發現單純地給圖片加 class
,去 *.wxss
寫樣式也無效的話。那麼,我建議小夥伴最好採用樣式加劇法,即 .image-wrap .image
這種寫法格式,來確保圖片樣式能進行修改。詳細用法可看下文。
swiper
屬性值。官方文檔說明:
雖然,它的屬性名和屬性值是這麼說的。可是,用的時候,首先你須要在 demo.wxml
中的 swiper
綁定這個屬性名,而後在 demo.js
中設置其屬性值。值得注意的是,它的綁定值,稍微不一樣於 Vue
, 須要設置 {{}}
形式。若是文字描述你看得不是很清楚,能夠參照下面的代碼進行理解。
關於輪播圖的地址跳轉,在微信小程序的官網是沒用說起的,也是 jsliang 去百度查看了下,才知道怎麼設置(多是我一開始就挑戰的難度過高了麼 -_-|| ),在下面 jsliang 貼出來代碼~想知道怎麼解決的能夠去看看:首先,在 data
中設置 link
;而後,設置 navigator
導航遍歷 item.link
。
關於 wx:key
, wx:key
的做用是:當數據改變觸發渲染層從新渲染的時候,會校訂帶有 key 的組件,框架會確保他們被從新排序,而不是從新建立,以確保使組件保持自身的狀態,而且提升列表渲染時的效率。可是,在其 swiper
中,小程序自己是沒有寫的,因此它會帶有 warning
,這裏也是個小坑, jsliang 也是百度了下也知道這件事:點我瞭解。
下面給出這 5 個坑的解決代碼,若有不對,盡情指出:
index.wxml
<view class="carousel">
<swiper indicator-dots="{{indicatorDots}}" autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}" indicator-color="#707071" indicator-active-color="#fff" circular="true">
<!-- wx:key : 提升列表渲染效率 -->
<block wx:for="{{imgUrls}}" wx:key="{{item.index}}">
<swiper-item>
<navigator url="{{item.link}}" hover-class="navigator-hover">
<image src="{{item.url}}" class="slide-image" />
</navigator>
</swiper-item>
</block>
</swiper>
</view>
複製代碼
index.wxss
.carousel .slide-image {
width: 100%;
height: 420rpx;
}
複製代碼
index.js
Page({
data: {
imgUrls: [
{
link: '../index/index',
url: 'http://img02.tooopen.com/images/20150928/tooopen_sy_143912755726.jpg',
},
{
link: '../demo/demo',
url: 'http://img06.tooopen.com/images/20160818/tooopen_sy_175866434296.jpg',
},
{
link: '../logs/logs',
url: 'http://img02.tooopen.com/images/20150928/tooopen_sy_143912755726.jpg'
}
],
indicatorDots: true,
autoplay: true,
interval: 5000,
duration: 1000
}
})
複製代碼
本組件目前已有 3 個坑,有興趣的小夥伴能夠詳看。
tabBar :底部菜單欄,須要在 app.json
中設置。使用方法:見下文。
navigator :導航切換。使用方法:地址
switchTab :控制 tabBar 的切換。使用方法:地址
在這裏,咱們講下 tabBar
的坑,若是你在 app.json
中設置了 tabBar
:
app.json
"tabBar": {
"list": [{
"pagePath": "pages/index/index",
"text": "首頁",
"iconPath": "./public/index_tabBar1_nor.png",
"selectedIconPath": "./public/index_tabBar1.png"
}, {
"pagePath": "pages/demo/demo",
"text": "發現",
"iconPath": "./public/index_tabBar2_nor.png",
"selectedIconPath": "./public/index_tabBar2.png"
}, {
"pagePath": "pages/logs/logs",
"text": "個人",
"iconPath": "./public/index_tabBar3_nor.png",
"selectedIconPath": "./public/index_tabBar3.png"
}]
}
複製代碼
那麼,咱們就須要經過設置 switchTab
來控制底部導航的跳轉,而不能經過 navigator
來跳轉:
demo.wxml
<view>
<button bindtap="linkTo">Hello</button>
</view>
複製代碼
demo.js
linkTo: function () {
wx.switchTab({
url: '../index/index'
});
},
複製代碼
那麼問題又來了,當咱們切換到子頁面的時候,咱們發現 tabBar
這個底部導航欄不見了,而後問了下 Ansen江 ,他說以前是整個小程序都有的,有些頁面還要千方百計去隱藏。
可是如今嘛……它沒了!沒了啊!!!在微信小程序的文檔沒看到有喚起底部導航條的方法,難道我要作一個導航條了麼 -_-||
回答是:yes!
因此,下面給出該底部導航條 tabBar
的實現狀況和代碼片斷:
注:圖片寬高均爲 54rpx
*.wxml
<view class="nav">
<view class="nav-home" bindtap="goHome">
<image src="../../public/index_productDetail_icon_home.png"></image>
<text>首頁</text>
</view>
<view class="nav-service">
<image src="../../public/index_productDetail_icon_service.png"></image>
<text>在線諮詢</text>
</view>
<view class="nav-phone" bindtap="callWaiter">
<image src="../../public/index_productDetail_icon_phone.png"></image>
<text>電話諮詢</text>
</view>
<navigator url="../indexPurchaseProduct/indexPurchaseProduct">
<view class="nav-buy">
<text>當即訂購</text>
</view>
</navigator>
</view>
複製代碼
*.wxss
.nav {
display: flex;
justify-content: space-around;
font-size: 20rpx;
border: 1px solid #ccc;
position: fixed;
bottom: 0;
background: #fff;
}
.nav view {
display: flex;
flex-direction: column;
align-items: center;
}
.nav image {
width: 54rpx;
height: 54rpx;
}
.nav text {
margin-top: 7rpx;
}
.nav-home {
border-right: 1px solid #ccc;
width: 130rpx;
padding-top: 5rpx;
}
.nav-service {
border-right: 1px solid #ccc;
width: 130rpx;
padding-top: 5rpx;
}
.nav-phone {
width: 130rpx;
padding-top: 5rpx;
}
.nav-buy {
background: #eb333e;
color: #fff;
width: 360rpx;
height: 98rpx;
line-height: 80rpx;
font-size: 34rpx;
}
複製代碼
*.js
callWaiter: function(res) {
wx.makePhoneCall({
phoneNumber: '13264862250',
success: function(res) {
console.log("撥打成功");
console.log(res);
},
fail: function(res) {
console.log("撥打失敗");
console.log(res);
},
complete: function(res) {
console.log("撥打完成");
console.log(res);
}
})
},
goHome: function() {
wx.switchTab({
url: '../index/index'
})
},
複製代碼
在最近的工做中,又發現一個小問題:
像這個導航條,它須要根據頁面所在的模塊,動態地展現不一樣位置的狀態爲活躍,並且它是須要在多個頁面重複出現的,若是每一個頁面我都要複製粘貼一遍,到時候要修改起來的時候,麻煩不說,最重要的是,它可能影響我前端的性能了,能不能直接將其封裝起來呢?
自定義組件:連接
是的,發如今小程序文檔中是存在這個東西的。固然,至於過程當中我百度了幾篇文章來輔助寫出下面的代碼,你猜?
子組件寫法
navBar.wxml
<!-- 底部導航條 -->
<view class="navBar">
<view class="navBar-home" bindtap='goHome'>
<image wx:if="{{homeActive}}" src="../../public/index_tabBar1.png"></image>
<image wx:if="{{!homeActive}}" src="../../public/index_tabBar1_nor.png"></image>
<text>首頁</text>
</view>
<view class="navBar-explore" bindtap='goExplore'>
<image wx:if="{{exploreActive}}" src="../../public/index_tabBar2.png"></image>
<image wx:if="{{!exploreActive}}" src="../../public/index_tabBar2_nor.png"></image>
<text>發現</text>
</view>
<view class="navBar-user" bindtap='goUser'>
<image wx:if="{{userActive}}" src="../../public/index_tabBar3.png"></image>
<image wx:if="{{!userActive}}" src="../../public/index_tabBar3_nor.png"></image>
<text>個人</text>
</view>
</view>
複製代碼
navBar.wxss
/* 底部導航條 */
.navBar {
width: 100%;
padding: 18rpx 0;
border-top: 1rpx solid #cccccc;
display: flex;
justify-content: space-around;
position: fixed;
bottom: 0;
background: #fff;
}
.navBar image {
width: 55rpx;
height: 55rpx;
}
.navBar view {
display: flex;
flex-direction: column;
align-items: center;
font-size: 20rpx;
color: #999999;
}
.navBar-user text {
color: #d0a763;
}
複製代碼
navBar.js
// pages/componentNavBar/navBar.js
Component({
/**
* 組件的屬性列表
*/
properties: {
homeActive: {
type: Boolean,
value: false
},
exploreActive: {
type: Boolean,
value: false
},
userActive: {
type: Boolean,
value: false
}
},
/**
* 組件的初始數據
*/
data: {
},
/**
* 組件的方法列表
*/
methods: {
// 返回首頁
goHome: function (e) {
wx.switchTab({
url: '../index/index',
})
},
// 返回發現頁
goExplore: function (e) {
wx.switchTab({
url: '../explore/explore',
})
},
// 返回個人頁面
goUser: function (e) {
wx.switchTab({
url: '../user/user',
})
},
showCode: function(e) {
console.log(e);
let that = this;
console.log(that.data);
}
}
})
複製代碼
navBar.json
{
"component": true,
"usingComponents": {}
}
複製代碼
而後,在父組件的使用,只須要:
*.wxml
<view>
<navBar userActive="{{userActive}}"></navBar>
</view>
複製代碼
*.json
{
"usingComponents": {
"navBar": "../componentNavBar/navBar"
}
}
複製代碼
*.js
data: {
userActive: true
},
複製代碼
怎樣?這就是自定義組件的寫法,是否是以爲特好用涅,一次寫完,終身受用。
本節目前已有1個坑,有興趣的小夥伴能夠詳看。
在微信中,它自帶了一套屬於本身的單位:rpx
, rpx
不一樣於以前咱們認識的 px
、 rem
、 em
,若是你的設計稿是 750 px 的,那麼很容易的, 1px = 1rpx ,可是,若是設計稿不是 750 px ,那麼將形成一個 bug ,至於這個 bug 如何解決……
-_-|| 誰知道呢……要不先把UI設計師宰了?
知識補充:關於 rpx 。
本節目前已有 2 個坑,有興趣的小夥伴能夠詳看。
若是你在開發過程當中,發現只能寫英文了,而中文沒法輸入了,千萬別急,也別怪輸入法出 bug 了,你只須要:重啓開發工具。
若是你某時刻,忽然發現你無法滾動代碼進行查看,而是須要拖動滾動條才行,請別怪你的鼠標,你能夠去瀏覽器打開一篇文章看看,enm...你的鼠標仍是好的~因此,請:重啓開發工具。
本節目前已有 2 個坑,有興趣的小夥伴能夠詳看。
首先,科普下 組件 與 API 是什麼:
Function
或者後端接口,前端直接調用就好了。 可是,在微信小程序官方文檔中,組件與API,拆分地有點不科學。
例如:輪播圖與底部導航條
wxml
、 wxss
、 js
中要設置對應的參數,一個只須要在 app.json
中設置就行。 可能微信小程序考慮到底部導航條不該該有太大的變化(例如讓你修改太多樣式或者 js
),因此將導航條內嵌至源碼中了。
可是,這可能致使什麼重要影響嗎?是的,若是底部導航條須要進行修改呢?例如:3.2.3 自定義組件。這樣的狀況下,咱們的開發時間就有所增長了。
若是小夥伴你常常有去看微信小程序官方文檔的話,那麼你必定會有一件事須要吐槽,那就是:
明明上次我見到過某個 API 實現了我須要作的功能,可是改天我回去查找的時候,它卻提示我沒有這個玩意,這是什麼鬼?!
是的,跟咱們 3.13 黑科技:<modal> 這一章中講到的 <modal>
這個黑科技同樣,有時候官方文檔也不是萬能的,它總會有這樣那樣的毛病,致使咱們找不到須要的東西,只能去百度了 -_-||
本節目前已有 3 個坑,有興趣的小夥伴能夠詳看。
Flex佈局又稱彈性佈局,在小程序開發中比較適用。可是因爲 jsliang 以前沒怎麼用過 Flex 佈局,因此在這裏我們特地去踩下坑,充實下本身。【小程序開發之頁面佈局】【阮一峯-Flex 佈局教程】
在咱們佈局頁面的時候,最好看看 阮一峯 的教程,平時遇到佈局的問題的時候,我都習慣去上面 阮一峯 的文章看看:
基礎概念:地址
<!-- 設置 flex 佈局 -->
display: flex;
<!--
一、決定主軸的方向
row - (默認)水平方向,起點在左端
row-reverse - 水平方向,起點在右端
column - 垂直方向,起點在上沿
column-reverse - 垂直方向,起點在下沿
-->
flex-direction: row | row-reverse | column | column-reverse;
<!--
二、一條軸線(一行)排不下時如何解決
nowrap - (默認)不換行
warp - 換行,第一行在上方
wrap-reverse - 換行,第一行在下方
-->
flex-wrap: nowrap | wrap | wrap-reverse;
<!--
三、flex-flow = flex-direction + flex-wrap。即 flex-flow 是這兩個屬性的合集
row nowrap - (默認)水平方向,起點在左端,不換行
-->
flex-flow: <flex-direction> || <flex-wrap>;
<!--
四、justify-content 定義項目在主軸上的對齊方式
flex-start - 左邊對齊
flex-end - 右邊對齊
center - 居中對齊
space-between - 兩端對齊,空格在中間
space-around - 空格環繞
-->
justify-content: flex-start | flex-end | center | space-between | space-around;
<!--
五、align-items 定義項目在交叉軸上如何對齊
flex-start - 頂部對齊,即文字圖片等頂部同一條線上
flex-end - 底部對其,即文字圖片等底部在同一條線上
center - 中間對其,即文字圖片無論多高,都拿它們的中間放在同一條線上
stretch - 將文字圖片充滿整個容器的高度,強制統一
baseline - 將每項的第一行文字作統一在一條線上對齊
-->
align-items: flex-start | flex-end | center | stretch | baseline;
<!--
六、align-content 定義多根軸線的對齊方式。若是隻有一根軸線(只有一行),該屬性不起做用
flex-start - 這幾行頂部對齊
flex-end - 這幾行底部對齊
center - 這幾行居中對齊
stretch - 這幾行進行擴展或者縮放,從而填滿容器高
space-between - 這幾行中間使用空格進行填充
space-around - 這幾行兩邊及中間進行填充
-->
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
複製代碼
實現效果以下:
如圖,這是咱們要實現的左右佈局效果。那麼,在微信小程序要怎麼作呢?
*.wxml
<view class="top-recommended-headlines">
<view class="top-recommended-headlines-left">
<text>熱門推薦</text>
</view>
<view>
<image src="../../public/index_top_recommended_headlines.png"></image>
</view>
<view class="top-recommended-headlines-right">
<navigator url="../indexProduct/indexProduct">查看所有 ></navigator>
</view>
</view>
複製代碼
*.wxss
.top-recommended-headlines {
display: flex;
align-items: flex-end;
height: 31rpx;
line-height: 31rpx;
margin-bottom: 10rpx;
}
.top-recommended-headlines-left text {
font-size: 32rpx;
font-weight: bold;
}
.top-recommended-headlines image {
width: 366rpx;
height: 31rpx;
margin-left: 10rpx;
}
.top-recommended-headlines-right navigator {
font-size: 26rpx;
color: #a9a9a9;
margin-left: 50rpx;
}
複製代碼
實現效果以下:
如圖,這是咱們要實現的左右佈局效果。那麼,在微信小程序要怎麼作呢?
*.wxml
<view class="weui-tab__content-item3" wx:for="{{tabs3Content}}" wx:key="{{item.index}}">
<navigator url="../indexProductArticle/indexProductArticle">
<view class="weui-tab__content-item3-question">
<image src="../../public/index_productDetail_icon_question.png"></image>
<text>{{item.title}}</text>
</view>
<view class="weui-tab__content-item3-answer">
<image src="../../public/index_productDetail_icon_answer.png"></image>
<text>{{item.content}}</text>
</view>
<view class="weui-tab__content-item3-detail">
<text class="weui-tab__content-item3-detail-datatime">{{item.datatime}}</text>
<text class="weui-tab__content-item3-detail-reader">{{item.reader}}閱讀</text>
<text class="weui-tab__content-item3-detail-label">#{{item.label}}#</text>
</view>
</navigator>
<view class="weui-tab__content-item3-gap">
<image src="../../public/index_productDetail_gap.png"></image>
</view>
</view>
複製代碼
*.wxss
.weui-tab__content-item3 {
padding-left: 30rpx;
padding-right: 30rpx;
margin-top: -10rpx;
margin-bottom: 10rpx;
}
.weui-tab__content-item3:first-child {
padding: 40rpx 30rpx 0;
}
.weui-tab__content-item3-question image {
width: 30rpx;
height: 30rpx;
}
.weui-tab__content-item3-question text {
font-size: 30rpx;
line-height: 46rpx;
font-weight: bold;
color: #333;
margin-left: 10rpx;
}
.weui-tab__content-item3-answer image {
width: 30rpx;
height: 30rpx;
}
.weui-tab__content-item3-answer text {
font-size: 26rpx;
line-height: 42rpx;
color: #a9a9a9;
margin-left: 10rpx;
}
.weui-tab__content-item3-detail {
display: flex;
justify-content: space-between;
font-size: 26rpx;
color: #a9a9a9;
}
.weui-tab__content-item3-detail-label {
color: #d0a763;
}
.weui-tab__content-item3-gap image {
width: 100%;
height: 30rpx;
}
複製代碼
*.js
tabs3Content: [
{
title: '員工發明創造是否屬於職務發明的認證標準?',
content: '隨着企業對知識產權在企業發展中核心競爭力的認識力提升,企業保護自身知識產權的意識不斷加強,使其技術得......',
datatime: '2018-03-05',
reader: '2081',
label: '知識產權'
}
]
複製代碼
本節目前已有 1 個坑,有興趣的小夥伴能夠詳看。
在小程序中,若是你使用 wxss,你是能夠發現有 background-image
的提示的。可是,若是你設置它的背景圖是本地圖片,你會發現,它是不生效的。
解決方案:
https://xxxx/xxx.jpg
;image
組件 + position
定位而不是使用 background-image
。本節目前已有 1 個坑,有興趣的小夥伴能夠詳看。
二者的區別是,<view>
是一個組件,會在頁面上作渲染;<block>
不是一個組件,它僅僅是一個包裝元素,只接受控制屬性,不會在頁面中作任何渲染。
因此,若是你僅僅是須要包裹,而不是渲染一個層,可使用 <block>
提高性能。
本節目前已有 2 個坑,有興趣的小夥伴能夠詳看。
首先,咱們要實現的效果是:
而後, jsliang 的想法是:
*.wxml
<view class="search">
<input class="search-product-input" bindinput="bindKeyInput" auto-focus maxlength='10'></input>
<label class="search-placeholder">
<image class="search-placeholder-icon" src="../../public/index_indexProduct_icon_search.png"></image>
<text class="search-placeholder-text">搜索產品</text>
</label>
<view></view>
</view>
複製代碼
*.wxss
.search {
height: 100rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
position: relative;
}
.search-product-input {
background: #f5f5f5;
width: 650rpx;
height: 65rpx;
border-radius: 30rpx;
font-size: 30rpx;
padding-left: 20rpx;
}
.search-placeholder {
font-size: 26rpx;
text-align: center;
margin-top: -65rpx;
z-index: 2;
}
.search-placeholder-icon {
width: 24rpx;
height: 24rpx;
}
.search-placeholder-text {
margin-left: 10rpx;
}
複製代碼
你注意到了嗎?在 *.wxml
中, jsliang 設置了個空的 <view>
,若是你把這個 <view>
去掉,你會驚奇地發現,它……下來了……
好吧,可能有其餘的實現方式,可是若是你下次使用這種方式,注意上面這個坑~
回頭看了下 WeUI
的實現方式,發現跟個人思路是挺像的,關於 input
的實現方式,如今依據 WeUI
,成功實現了輸入框:
源碼奉上:
*.wxml
<!-- 搜索框 -->
<view class="search">
<view class="weui-search-bar">
<view class="weui-search-bar__form {{inputShowed ? 'form-border' : ''}}">
<view class="weui-search-bar__box">
<icon class="weui-icon-search_in-box" type="search" size="14"></icon>
<input type="text" class="weui-search-bar__input" placeholder="搜索" value="{{inputVal}}" focus="{{inputShowed}}" bindinput="inputTyping" />
<view class="weui-icon-clear" wx:if="{{inputVal.length > 0}}" bindtap="clearInput">
<icon type="clear" size="14"></icon>
</view>
</view>
<label class="weui-search-bar__label" hidden="{{inputShowed}}" bindtap="showInput">
<icon class="weui-icon-search" type="search" size="14"></icon>
<view class="weui-search-bar__text">搜索</view>
</label>
</view>
<view wx:if="{{inputVal.length <= 0}}" class="weui-search-bar__cancel-btn" hidden="{{!inputShowed}}" bindtap="hideInput">取消</view>
<view wx:if="{{inputVal.length > 0}}" class="weui-search-bar__submit-btn" hidden="{{!inputShowed}}" bindtap="searchInput">搜索</view>
</view>
</view>
複製代碼
*.js
Page({
data: {
inputShowed: false,
inputVal: ""
},
showInput: function () {
this.setData({
inputShowed: true
});
},
hideInput: function () {
this.setData({
inputVal: "",
inputShowed: false
});
},
clearInput: function () {
this.setData({
inputVal: ""
});
},
inputTyping: function (e) {
this.setData({
inputVal: e.detail.value
});
}
})
複製代碼
*.wxss
.search {
height: 100rpx;
padding: 18rpx 30rpx;
}
.weui-search-bar {
padding: 0;
background-color: #fff;
border-top: none;
border-bottom: none;
height: 64rpx;
}
.weui-search-bar__form {
border: none;
}
.form-border {
border: 1rpx solid #f5f5f5;
background: #f5f5f5;
}
.weui-search-bar__label {
background: #f5f5f5;
border-radius: 30rpx;
}
.weui-search-bar__cancel-btn {
font-size: 26rpx;
background: rgb(8, 202, 186);
color: #fff;
padding: 2rpx 20rpx 0 20rpx;
border-radius: 10rpx;
}
.weui-search-bar__submit-btn {
font-size: 26rpx;
background: rgb(8, 200, 248);
color: #fff;
padding: 10rpx 20rpx 0 20rpx;
border-radius: 10rpx;
}
複製代碼
本節目前已有 1 個坑,有興趣的小夥伴能夠詳看。
官方文檔:地址
在這裏,提醒廣大小夥伴注意了,注意了,注意了!重要的事說三遍。
當你新建 page
的時候,微信 web 開發者工具會自動幫你添加分享事件:
/**
* 用戶點擊右上角分享
*/
onShareAppMessage: function (res) {
// 實現分享功能
return {
title: this.data.productName,
path: '/pages/indexProductDetail.js?productId=' + this.data.productId,
imageUrl: this.data.videoImageSrc,
success: (res) => {
console.log("分享成功~");
},
fail: (res) => {
console.log("分享失敗~");
}
}
}
複製代碼
因此,若是你在前面定義了,它會在最下面偷偷幫你清空,而後你就以爲沒法自定義分享事件……
是的,jsliang 打死都不認可這是我本身的鍋,新手注意!新手注意!!新手注意!!!
本節目前已有 1 個坑,有興趣的小夥伴能夠詳看。
熟知盒模型的小夥伴應該知道,盒模型有兩種計算方式:
在 border-box
中,整個 view
的寬、高,包括 margin
、padding
、border
。
而在 content-box
中,整個 view
的寬、高,則不包括上面元素。
如上圖,若是一個 view
,你的代碼以下:
view {
box-sizing: border-box;
margin: 10rpx;
width: 100rpx;
height: 100rpx;
padding: 10rpx;
}
複製代碼
那麼,你的整個寬高仍是 100rpx
。
可是,若是你的代碼以下:
view {
box-sizing: content-box;
margin: 10rpx;
width: 100rpx;
height: 100rpx;
padding: 10rpx;
}
複製代碼
那麼,你的整個盒子寬高是 120rpx
。
若是你在設計頁面中,發現內容區被撐爆了,那麼,請檢查下如今的 border-box
是什麼。
本節目前已有 6 個坑,有興趣的小夥伴能夠詳看。
使用 WeUI 的導航條,首先須要引用 WeUI 的 CSS 樣式:地址
下載 weui.wxss
並在 app.wxss
中引用便可
app.wxss
/* 引用WeUI */
@import 'weui.wxss';
複製代碼
而後,咱們直接往頁面加入它的選項卡並根據項目需求修改其樣式:
*.wxml
<view class="tab">
<view class="weui-tab">
<view class="weui-navbar">
<block wx:for="{{tabs}}" wx:key="*this">
<view id="{{index}}" class="weui-navbar__item {{activeIndex == index ? 'weui-bar__item_on' : ''}}" bindtap="tabClick">
<view class="weui-navbar__title">{{item}}</view>
</view>
</block>
<view class="weui-navbar__slider" style="left: {{sliderLeft}}px; transform: translateX({{sliderOffset}}px); -webkit-transform: translateX({{sliderOffset}}px);"></view>
</view>
<view class="weui-tab__panel">
<!-- 所有 -->
<view class="weui-tab__content" hidden="{{activeIndex != 0}}">
<view class="weui-tab__content-item1">
<text>所有</text>
</view>
</view>
<!-- 已付款 -->
<view class="weui-tab__content" hidden="{{activeIndex != 1}}">
<view class="weui-tab__content-item2">
<text>已付款</text>
</view>
</view>
<!-- 待付款 -->
<view class="weui-tab__content" hidden="{{activeIndex != 2}}">
<view class="weui-tab__content-item3">
<text>待付款</text>
</view>
</view>
</view>
</view>
</view>
複製代碼
*.wxss
.tab {
font-size: 26rpx;
}
.tab image {
width: 173rpx;
height: 29rpx;
}
.weui-navbar {
border-top: 1rpx solid #efefef;
border-bottom: 1rpx solid #efefef;
}
.weui-navbar__slider {
background: #d0a763;
width: 4em;
}
.weui-navbar__item.weui-bar__item_on {
color: #d0a763;
}
.weui-tab__content {
margin-bottom: 100rpx;
}
複製代碼
*.js
var sliderWidth = 52; // 須要設置slider的寬度,用於計算中間位置
Page({
/**
* 頁面的初始數據
*/
data: {
// 選項卡導航
tabs: ["所有", "已付款", "待付款"],
activeIndex: 1,
sliderOffset: 0,
sliderLeft: 0,
},
// 選項卡切換
tabClick: function (e) {
this.setData({
sliderOffset: e.currentTarget.offsetLeft,
activeIndex: e.currentTarget.id
});
},
/**
* 生命週期函數--監聽頁面加載
*/
onLoad: function (options) {
// 計算搜索框活躍條
var that = this;
wx.getSystemInfo({
success: function (res) {
that.setData({
sliderLeft: (res.windowWidth / that.data.tabs.length - sliderWidth) / 2,
sliderOffset: res.windowWidth / that.data.tabs.length * that.data.activeIndex
});
}
});
}
})
複製代碼
自定義選項卡的代碼實現:
實現效果圖以下:
實現代碼以下:
*.wxml
<view>
<view class="weui-tab__nav">
<text wx:for="{{tabs2Nav}}" wx:key="item.index" class="{{item.state == 1 ? 'weui-tab__nav-active' : ''}}" bindtap="tabs2NavClick" data-labelId="{{item.id}}">{{item.label}}</text>
</view>
<view class="weui-tab__content-item2" wx:for="{{tabs2Content}}" wx:key="{{item.index}}">
<view class="weui-tab__content-item-descritpion">
<view class="{{item.type == 1 ? 'weui-tab__content-item-icon-type' : 'hide'}}">
<image src="../../public/index_productDetail_icon_word.png"></image>
</view>
<view class="{{item.type == 2 ? 'weui-tab__content-item-icon-type' : 'hide'}}">
<image src="../../public/index_productDetail_icon_excel.png"></image>
</view>
<view class="{{item.type == 3 ? 'weui-tab__content-item-icon-type' : 'hide'}}">
<image src="../../public/index_productDetail_icon_ppt.png"></image>
</view>
<view class="{{item.type == 4 ? 'weui-tab__content-item-icon-type' : 'hide'}}">
<image src="../../public/index_productDetail_icon_pdf.png"></image>
</view>
<view class="weui-tab__content-item-descritpion-content">
<text class="weui-tab__content-item-descritpion-content-title">{{item.title}}</text>
<view class="weui-tab__content-item-descritpion-content-datatime">
<text class="weui-tab__content-item-descritpion-content-datatime1">發佈時間:{{item.datatime}}</text>
<text class="{{item.effectiveTime ? 'weui-tab__content-item-descritpion-content-datatime2' : 'hide'}}">生效時間:{{item.effectiveTime}}</text>
</view>
</view>
</view>
<view class="weui-tab__content-item-download-state" bindtap='downloadFile' data-url="{{item.url}}">
<image src="../../public/index_productDetail_icon_undown.png"></image>
</view>
</view>
</view>
複製代碼
*.wxss
.weui-tab__nav {
background: #f5f5f5;
border: 1rpx 0rpx solid #e6e6e6;
height: 90rpx;
padding: 17rpx 41rpx;
display: flex;
justify-content: space-between;
}
.weui-tab__nav text {
border-radius: 56rpx;
height: 56rpx;
line-height: 56rpx;
padding: 15rpx 23rpx;
font-size: 26rpx;
font-weight: bold;
}
.weui-tab__nav-active {
color: #fefefe;
background: #d0a763;
}
.weui-tab__content-item2 {
display: flex;
justify-content: space-between;
padding: 25rpx 30rpx;
}
.weui-tab__content-item-descritpion {
display: flex;
justify-content: space-between;
}
.weui-tab__content-item-descritpion image {
width: 60rpx;
height: 70rpx;
}
.hide {
display: none;
}
.weui-tab__content-item-descritpion-content {
margin-left: 26rpx;
}
.weui-tab__content-item-descritpion-content-title {
font-size: 28rpx;
font-weight: bold;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
.weui-tab__content-item-descritpion-content-datatime {
font-size: 22rpx;
color: #bbb;
}
.weui-tab__content-item-descritpion-content-datatime1 {
margin-right: 35rpx;
}
.weui-tab__content-item-download-state image {
width: 64rpx;
height: 64rpx;
}
複製代碼
*.js
data: {
tabs2Nav: [
{
id: '1',
label: '法律大全',
state: 1
},
{
id: '2',
label: '合同模板',
state: 0
},
{
id: '3',
label: '民事',
state: 0
},
{
id: '4',
label: '行政',
state: 0
},
{
id: '5',
label: '執行',
state: 0
}
],
tabs2Content: [
{
title: '中華人名共和國民用航空法(2015年...).doc',
url: 'https://wxmcard.imusic.cn/testfordocdownload.doc',
datatime: '2018-01-26',
effectiveTime: '2018-01-26',
type: '1'
},
{
title: '原生申訴表格.xls',
url: 'https://wxmcard.imusic.cn/testfordocdownload.doc',
datatime: '2018-01-26',
type: '2'
},
{
title: '法律常識大聚集及範例.ppt',
url: 'https://wxmcard.imusic.cn/testforpptdownload.pptx',
datatime: '2018-01-26',
effectiveTime: '2018-01-26',
type: '3'
},
{
title: '事業單位法律基礎知識總結.pdf',
url: 'https://wxmcard.imusic.cn/testforpdfdownload.pdf',
datatime: '2018-01-26',
effectiveTime: '2018-01-26',
type: '4'
}
],
// 選項卡第二屏分組
tabs2Content1: [
{
title: '中華人名共和國民用航空法(2015年...).doc',
datatime: '2018-01-26',
effectiveTime: '2018-01-26',
type: '1'
},
{
title: '原生申訴表格.xls',
datatime: '2018-01-26',
type: '2'
},
{
title: '法律常識大聚集及範例.ppt',
datatime: '2018-01-26',
effectiveTime: '2018-01-26',
type: '3'
},
{
title: '事業單位法律基礎知識總結.pdf',
datatime: '2018-01-26',
effectiveTime: '2018-01-26',
type: '4'
}
],
tabs2Content2: [
{
title: '合同模板.doc',
datatime: '2018-01-26',
effectiveTime: '2018-01-26',
type: '1'
}
],
tabs2Content3: [
{
title: '民事合同模板.doc',
datatime: '2018-01-26',
effectiveTime: '2018-01-26',
type: '1'
}
],
tabs2Content4: [
{
title: '行政合同模板.doc',
datatime: '2018-01-26',
effectiveTime: '2018-01-26',
type: '1'
}
],
tabs2Content5: [
{
title: '執行合同模板.doc',
datatime: '2018-01-26',
effectiveTime: '2018-01-26',
type: '1'
}
]
},
// 選項卡2切換
tabs2NavClick: function(e) {
var that = this;
console.log("完整的數據是:");
console.log(that.data.tabs2Nav);
console.log("點擊的標籤是:");
console.log(e.currentTarget.dataset.labelid);
var newTabs2Content;
console.log("正在經歷的標籤是:");
for(var i=0; i<that.data.tabs2Nav.length; i++) {
console.log(that.data.tabs2Nav[i].id);
that.data.tabs2Nav[i].state = 0;
if (that.data.tabs2Nav[i].id == e.currentTarget.dataset.labelid) {
that.data.tabs2Nav[i].state = 1;
console.log("將改變的標籤是:");
console.log(that.data.tabs2Nav[i]);
// 改變內容
var changeContentName = "tabs2Content" + (i + 1);
if (changeContentName == "tabs2Content1") {
console.log(that.data.tabs2Content1);
newTabs2Content = that.data.tabs2Content1;
} else if (changeContentName == "tabs2Content2") {
newTabs2Content = that.data.tabs2Content2;
} else if (changeContentName == "tabs2Content3") {
newTabs2Content = that.data.tabs2Content3;
} else if (changeContentName == "tabs2Content4") {
newTabs2Content = that.data.tabs2Content4;
} else {
newTabs2Content = that.data.tabs2Content5;
}
console.log("但願轉換內容到:");
console.log(changeContentName);
}
}
this.setData({
tabs2Nav: that.data.tabs2Nav,
tabs2Content: newTabs2Content
})
},
複製代碼
綁定事件如何傳遞數據:
若是學過 Vue
的同窗,應該知道 Vue
的數據傳遞形式是: @click='tabs2NavClick(item.id)'
那麼,在微信小程序中,你千萬記得,綁定時間的傳遞參數的方式不是這樣子的,而是:
<text wx:for="{{tabs2Nav}}" wx:key="item.index" bindtap="tabs2NavClick" data-labelId="{{item.id}}">{{item.label}}</text>
複製代碼
經過 data-*="{{item}}"
的形式傳遞的~而後你須要在 js
中,經過 e.currentTarget.dataset.labelid
來獲取。
而後,注意了,這裏還有個小 bug。在代碼中,咱們使用的是 data-labelId="{{item.id}}"
,而獲取數據的時候,咱們獲取的是 labelid
,是的,駝峯不見了~
參考連接:連接
如何在方法中獲取 data
中定義的數據:
若是我想在選項卡切換的方法 tabs2NavClick
中獲取 data
裏面的數據,那麼我應該怎麼作呢?
是的,經過:
tabs2NavClick: function(e) {
var that = this;
console.log(that.data.tabs2Nav);
}
複製代碼
這種形式,咱們就能夠獲取到 data
中的數據。
參考連接:連接
如何實現文字省略:
加入你有一段文本,你想讓頁面根據自身寬度,自動省略多餘長度,那麼,咱們能夠設置下面的 css
代碼,從而實現文字省略效果(不使用 js 的緣由,是由於 js 沒有 css 那麼靈活)
text {
overflow:hidden;
text-overflow:ellipsis;
display:-webkit-box;
-webkit-line-clamp:1;
-webkit-box-orient:vertical;
}
複製代碼
參考連接:連接
本節目前已有 2 個坑,有興趣的小夥伴能夠詳看。
一個坑就是一個故事。
故事都有四元素:時間,地點,人物,事情。
前三個自沒必要說,咱們直接講事情通過:咱們項目的負責人須要一個留言彈窗,而後裏面有個文本框能夠填信息,最後點擊【留言】按鈕將數據傳到後端,點擊【取消】按鈕關閉彈窗。
需求是否是很簡單~既然微信小程序有本身的官方文檔。那麼,怎麼方便怎麼來吧,因而 jsliang 在微信小程序中搜索關鍵字 彈窗
:
看了下搜索記錄,最匹配的就是上面這個了。enm...好像沒看到放文本框的?先試試:
額(⊙o⊙)…
很差意思打擾了,我去百度看看:連接
咦~ 它這裏好像有個 <modal>
標籤?Ctrl+C、Ctrl+V 試試先~
Duang~~~這不就是我要的效果麼,挖槽,黑科技?因而 jsliang 去小程序那裏搜了下 modal
……enm...蜜汁尷尬,好像只有上面的 wx.showModal()
方法……因而 jsliang 滿頭黑線……好嘛,黑科技黑科技!!!
下面貼出實現代碼:
*.wxml
<text class="article-message-board-head-addMessage" bindtap="modalinput">寫留言</text>
複製代碼
*.js
Page({
data: {
// 彈窗
hiddenmodalput: true, //能夠經過hidden是否掩藏彈出框的屬性,來指定那個彈出框
},
//點擊按鈕指定的hiddenmodalput彈出框
modalinput: function () {
this.setData({
hiddenmodalput: !this.data.hiddenmodalput
})
},
//取消按鈕
cancel: function () {
this.setData({
hiddenmodalput: true
});
},
//確認
confirm: function () {
wx.showToast({
title: '留言成功!',
})
this.setData({
hiddenmodalput: true
})
}
})
複製代碼
好的,上面就實現了一個簡單的可填寫文本的彈窗了。
做爲一枚職業填坑人,怎麼能知足於上面的兩種彈窗形式呢!因而,使用百度大法又找到了一篇填坑文:連接
因此,總結下就有了四種彈窗寫法:
類型 | 說明 | 地址 |
---|---|---|
模態彈窗 | wx.showModal(Object) - 模態彈窗就是上面的第一種彈窗,它能夠給你選擇【取消】或者【肯定】 | 連接 |
<modal> | <modal>是上面的第二種彈窗,能夠提供用戶填寫 | 連接 |
消息彈窗 | wx.showToast(Object) - 消息彈窗就是操做成功或者操做失敗的那一刻,系統的提示彈窗,無需用戶操做,可設定幾秒自動關閉 | 連接 |
操做菜單 | wx.showActionSheet(Object) - 操做菜單相似於彈出的下拉菜單,提供你選擇其中某項或者【取消】 | 連接 |
在這裏,就講完了微信小程序的四種彈窗形式了。若是你改樣式改的煩啊煩的,可能你須要封裝一個屬於本身的彈窗?嘿嘿,說不定你的產品經理會有興趣讓你開發一個 beautiful
彈窗的~
這坑我不填,我沒碰到~碰到了再說!在這裏預留下這個坑,哈哈。
本節目前已有 6 個坑,有興趣的小夥伴能夠詳看。
在小程序的文章處理中,文章的主體內容,通常來講,後端會採用富文本的形式存儲數據到數據庫。就是說,你要在 view
中展現 html
變遷。可是,你知道的,小程序不採用瀏覽器的那一套,因此,你可能須要兜圈子了:連接
在上面這篇文章中,講述了三種解析富文本的方法:
在百度大法的渲染下,jsliang 採用了 wxParse。
Github 的 wxParse 地址:連接
使用方法很簡單,照着它 GitHub 地址去擼就是了。然而,坑不是那麼容易填的 o(╥﹏╥)o
( bug1 )wxParse 在其神祕源碼中,會將你的 html+css 樣式弄亂,例如:px
要轉成 rpx
,才能在小程序中正常顯示,若是你不處理……enm...你試試~
( bug2 )而後,若是你忽然發現,內容沒法顯示,那麼,恭喜你又觸發了 bug,這個是 wxParse 代碼的一個 bug,在一些特殊的手機裏面,在 wxparse/html2json.js 中的第 112 和 119行,都有一個 console.dir() 這個函數的使用,它使你的內容不能正常顯示了。把這個函數註釋掉,內容就能夠正常顯示出來了。
if (name == 'class') {
// console.dir(value); // 112 行
// value = value.join("")
node.classStr = value;
}
// has multi attibutes
// make it array of attribute
if (name == 'style') {
// console.dir(value); // 119行
// value = value.join("")
node.styleStr = value;
}
複製代碼
( bug3 )若是你須要引用圖片,那麼,你會發現引用不成功。這是由於,咱們在網頁後臺編輯器裏面上傳的圖片,是採用相對路徑的,上傳成絕對網絡地址路徑以後,換成域名,就無法很好的展現了。因此最好的方法,就是修改 html2json.js 這個文件,讓 wxParse 自動添加域名前綴:地址
( bug4 )空格無法被正確替換,須要修改 wxDiscode.js
中的 strcharacterDiscode
:
// 將原語句註釋掉,替換爲下面的語句
// str = str.replace(/ /g, ' ');
str = str.replace(/ /g, '\xa0');
複製代碼
( bug5 )如何幹掉控制檯 console 中 wxParse 的一大串輸出:
wxParse.js
// 36行註釋掉
console.log(JSON.stringify(transData, ' ', ' '));
// 41行註釋掉
console.log(JSON.stringify(transData, ' ', ' '));
複製代碼
綜上,jsliang 氣得差口吐白沫了……換換換!有空要換成其餘兩種方式才行!!!
jsliang 還未使用過 rich-text,這裏先預留個坑。若是小夥伴們在開發 rich-text 過程當中碰到過各類坑,能夠跟 jsliang 提一下,我會寫進這章節,順帶在章節尾寫上你的大名,辛苦了~
jsliang 還未使用過 web-view,這裏先預留個坑。若是小夥伴們在開發 web-view 過程當中碰到過各類坑,能夠跟 jsliang 提一下,我會寫進這章節,順帶在章節尾寫上你的大名,辛苦了~
本節目前已有 1 個坑,有興趣的小夥伴能夠詳看。
在小程序中,它有一些自定義的方法,例如 open-type
,是須要 <button>
來承接的。
因此,若是你寫好了一個 view
,裏面有很好看的樣式了,你原本打算用 bindtap
來搞事情的。可是,忽然接到信息,須要外套一層 <button open-type="***">
,而後發現,樣式須要從新跳過……
enm...加油不哭,從新寫過樣式吧~
本節目前已有 1 個坑,有興趣的小夥伴能夠詳看。
就像上一章所說的,有時候,無可奈何,咱們必須在 <button>
中內嵌個 <image>
或者 <text>
之類的,那麼,通常怎麼作呢?
如今,假設我有一個 42*40
的圖片,我來試試調下它的樣式:
*.wxml
<button open-type='share'>
<image src="../../public/explore_activityDetail_icon_share.png"></image>
</button>
複製代碼
*.wxss
.activity-user-action button {
width: 42rpx;
height: 80rpx;
margin: 0;
padding: 0;
margin-top: -21rpx;
background: #fff;
}
.activity-user-action button::after {
border: none;
}
.activity-user-action image:last-child {
width: 42rpx;
height: 40rpx;
}
複製代碼
如上,咱們須要設置這個按鈕的高度是圖片高度的 2 倍,而後還須要設置 margin-top
的高度爲圖片高度的 1/2(注意 margin 與 margin-top 的順序,若是你不知道順序的重要性,推薦你使用 margin: -21rpx 0 0 0
),同時 margin
、padding
、background
、border
須要清空。
本節目前已有 2 個坑,有興趣的小夥伴能夠詳看。
在瀏覽器中,有 F5 刷新,有鼠標滾輪滑動加載。
那麼,換到微信小程序,又是怎樣子的呢?
是的,這就要說說用戶下拉動做和上拉觸底了:
下拉事件在小程序文檔的解釋:連接
/**
* 頁面相關事件處理函數--監聽用戶下拉動做
*/
onPullDownRefresh: function () {
},
複製代碼
上拉觸底在小程序文檔的解釋:連接
/**
* 頁面上拉觸底事件的處理函數
*/
onReachBottom: function () {
},
複製代碼
這兩個事件,都是在你新建 page
的時候,會自動添加的,小夥伴們注意下,省得前面寫了,被後面的覆蓋了哦~
本節目前已有 1 個坑,有興趣的小夥伴能夠詳看。
<input class="phone-number"></input>
<button>獲取電話號碼</button
如今,假設咱們在小程序中輸入了一個 class
爲 phone-number
的input
框,而且有一個 <button>
。那麼,咱們在微信小程序中,須要如何獲取該 phone-number
的值呢?
<input>
中設置 name
爲 phoneNumber
data
中設置 phoneNumber: ''
bindinput="phoneCodeInput'
phoneCodeInput
方法來修改 this.data.phoneNumber
<button>
的綁定事件中獲取 phoneNumber
步驟繁雜,下面貼出實現代碼:
*.wxml
<input maxlength='11' placeholder='請輸入手機號碼' placeholder-class="phone-number" name="phoneNumber" bindinput='phoneNumberInput'></input>
<button class="get-phone-number" bindtap="getPhoneNumber">獲取驗證碼</button>
複製代碼
*.js
Page({
data: {
// 輸入的手機號碼
phonenumber: '',
},
// 獲取手機號碼
phoneNumberInput: function(e) {
this.setData({
phonenumber: e.detail.value
})
},
// 點擊獲取驗證碼
getPhoneNumber: function (e) {
var phoneNumber = this.data.phonenumber
console.log(phoneNumber);
}
})
複製代碼
看到這裏,若是有習慣 jQuery
,習慣操做 dom
節點的小夥伴可能會抱有很大疑惑:「它就不能像 jQuery
同樣直接獲取 dom
的內容麼?」
答案是,有的:地址。可是,在這裏, jsliang 並不推薦小夥伴這麼作,想要學好一門新的技術,就不能由於舊的技術而限制了本身的觀念。時代在進步,科技在發展,咱們不學更多的知識,只能被淘汰在前端的潮流中。
本節目前已有 2 個坑,有興趣的小夥伴能夠詳看。
此次的需求是:判斷用戶是否登陸,若是登陸了就跳轉到首頁,若是沒登陸就跳轉到登陸頁。
咱們都知道,在微信小程序中,有個 onLaunch
方法,微信小程序官方文檔對其描述就是:每一個頁面進來須要先加載 onLaunch
方法,再去執行其餘方法。而後,在 jsliang 嘗試設置在 onLaunch
中調用 wx.login()
,卻發現,index.js
的 onLoad
方法是先於 onLaunch
執行的,這致使咱們無法預先獲取到須要的信息:
index.js
的 onload
app.js
中的 onLaunch
迫於無奈,jsliang 對其進行了百度:地址 。經過百度這篇文章發現,有兩個解決方案:
Promise
來進行進程管理 可是,因爲 jsliang 對於 Promise
的作法,以爲其太過複雜,故新增了一個 page/login
。
那麼,如何在用戶進入首頁閱讀文章、查看產品以前,先對用戶進行微信受權、帳號登陸呢?
onLogin
的 Storage
,在 index.js
中的 onload
進行判斷,若是用戶未進行登陸,則使用 wx.redirectTo()
跳轉到登陸頁面:index.js
onLoad: function (options) {
if (!wx.getStorageSync('isLogin')) {
wx.redirectTo({
url: '../login/login',
})
}
}
複製代碼
onLogin
爲 true
。login.js
loginSubmit: function(e) {
wx.setStorageSync('isLogin', true);
}
複製代碼
這樣,咱們就作到了路由守衛,即你不登陸,不給跳轉到首頁。
本節目前已有 1 個坑,有興趣的小夥伴能夠詳看。
在 Ansen江 的推薦下,參照 Ansen江 的 api.js
,對我這邊的小程序接口 request
進行了 promise
封裝,並作了 api.js
的分離。
api.js
/*
* @Author: jsliang
* @Date: 2018-10-11 09:11:26
* @LastEditors: jsliang
* @LastEditTime: 2018-10-11 09:11:29
* @Description: 接口文件
*/
// 引入請求頭文件
import header from './header.js';
// 加載中
const Loading = {
show() {
wx.showLoading({
title: '加載中'
});
},
hide() {
wx.hideLoading()
}
};
// 加載中白名單
const loadingWhite = [
'index/index'
]
// 將請求進行 Promise 封裝
const fetch = ({url, data, header}) => {
// 白名單地址會顯示加載中狀態
if(loadingWhite.includes(url)) {
Loading.show();
}
// 打印接口請求的信息
console.log(`【step1】API接口:${url}`);
console.log("【step2】header請求頭:");
console.log(header);
console.log("【step3】data傳參:");
console.log(data);
// 返回 Promise
return new Promise((resolve, reject) => {
wx.request({
url: getApp().globalData.api + url,
header: header,
data: data,
success: res => {
Loading.hide();
// 成功時的處理
if (res.data.code == 0) {
console.log("【step4】請求成功:");
console.log(res.data);
return resolve(res.data);
} else {
wx.showModal({
title: '請求失敗',
content: res.data.message,
showCancel: false
});
}
},
fail: err => {
Loading.hide();
// 失敗時的處理
console.log(err);
return reject(err);
}
})
})
}
/**
* code 換取 openId
* @data {
* jsCode - wx.login() 返回的 code
* }
*/
export const wxLogin = data => {
return fetch({
url: "tbcUser/getWechatOpenId",
header: header.newHeader(),
data: data
})
}
複製代碼
在上面進行了分離 api.js
後,接着在其餘地方調用 api.js
:
login.js
import {
wxLogin
} from "../../utils/api.js"
// 登陸
wx.login({
success: res => {
// 發送 code ,獲取 openId
console.log("\n【API:獲取 openId】");
wxLogin({
jsCode: res.code
}).then(
res => {
console.log("【step5】返回成功處理:");
console.log(res);
},
err => {
console.log("【step5】返回失敗處理:");
console.log(err);
}
)
}
})
複製代碼
輸出結果:
這樣,咱們就成功作了 request
的封裝,並經過調用 api.js
的形式,分離了代碼,從而更方便地進行編程。
本節目前已有 1 個坑,有興趣的小夥伴能夠詳看。
在頁面佈局中,咱們常用列表展現,而後在列表展現上,有時候該列表的最後一條數據下面是沒有下劃線或者虛線的。
那麼,當數據讀取到最後一條的時候,如何判斷已經到了最後一條,再也不展現下劃線或者虛線呢?
*.wxml
<view class="content">
<view wx:for="{{topRecommended}}" wx:key="{{item.recommendId}}" wx:for-index="index">
<navigator url="../indexProduct/indexProduct">
<view class="content-item">
<image src="{{item.coverImage}}"></image>
<view class="content-item-text">
<text class="content-item-text-title">{{item.recommendTitle}}</text>
<text class="content-item-text-content">{{item.recommendDescription}}</text>
<view class="content-item-text-row">
<text class="content-item-text-user">{{item.userCount}}人在用</text>
<text class="content-item-text-price">¥{{item.productPrice}}</text>
</view>
</view>
</view>
</navigator>
<view class="{{(index+1) == topRecommended.length ? 'content-item-gap-hide' : 'content-item-gap'}}">
<image src="../../public/index_top_recommended_content_item_gap.png"></image>
</view>
</view>
</view>
複製代碼
在這裏,咱們對要循環的對象使用 wx:for-index="index
,即:
<view wx:for="{{topRecommended}}" wx:key="{{item.recommendId}}" wx:for-index="index">
複製代碼
而後,咱們在下劃線/點虛線位置進行 class
判斷,若是 index+1 == topRecommended.length
,那麼咱們就換一個樣式:class="{{(index+1) == topRecommended.length ? 'class1' : 'class2'}}"
,即:
<view class="{{(index+1) == topRecommended.length ? 'content-item-gap-hide' : 'content-item-gap'}}">
複製代碼
這樣,咱們就作到了判斷是否處於最後一條數據,從而經過 class
來隱藏下劃線或者虛線。
經過 CSS
的 last-child { ... }
,能夠直接修改最後的 view
樣式:
*.wxss
.content-item-gap:last-child {
display: none;
}
複製代碼
這樣,就不須要複雜的 JS
邏輯,從而實現最後一個下劃線的顯示影藏。
若是你想了解下 last-child
爲什麼物:連接
本節目前已有 1 個坑,有興趣的小夥伴能夠詳看。
在微信小程序中,客服系統也是個至關詭異的玩意。
目前實現:
*.wxml
<button open-type="contact" send-message-title='{{productName}}' send-message-img='{{videoImageSrc}}' send-message-path='../indexProductDetail/indexProductDetail?productId={{productId}}' show-message-card='true'>
<view class="nav-service">
<image src="../../public/index_productDetail_icon_service.png"></image>
<text>在線諮詢</text>
</view>
</button>
複製代碼
可是,這不能知足個人要求:
這些,都須要咱們的小程序發佈後進行驗證。
本節目前已有 2 個坑,有興趣的小夥伴能夠詳看。
話很少說,先丟出實現代碼:
*.wxml
<view class="container" bindtap='downloadFile' data-url="{{downloadUrl}}">
<button>點我下載</button>
</view>
複製代碼
*.js
Page({
data: {
downloadUrl: '網上隨便找一個下載地址'
},
downloadFile: function(e) {
// 獲取傳遞過來的下載地址
var url = e.currentTarget.dataset.url;
// 調用下載 API
wx.downloadFile({
url: url,
success: function (res) {
console.log("下載文件成功");
console.log(res);
var tempFilePath = res.tempFilePath;
// 在線預覽文檔
wx.openDocument({
filePath: tempFilePath,
success: res => {
console.log("打開成功");
},
fail: res => {
console.log(res);
},
complete: res => {
console.log(res);
}
})
},
fail: function () {
console.log("下載失敗");
}
})
}
})
複製代碼
而後,在下載的時候,後端小夥伴偷懶,上傳的是沒有數據的 Word、PPT,這時候,小程序會報:openDocument:fail filetype not supported
的 error,因此小夥伴們要注意下。
本節目前已有 1 個坑,有興趣的小夥伴能夠詳看。
因爲 jsliang 平時都是使用 ES5 ,一直口嚷嚷說要步入 ES6 大堂,可是一直就是沒入門,因此乘着有功夫,儘可能使用 ES6 ,用熟了才能進步。
綁定方法寫法修改:
getUserPhone: function(e) {
console.log(e);
}
複製代碼
getUserPhone(e) {
console.log(e);
}
複製代碼
循環寫法:
for(var i = 0; i <= array.length; i++) {
console.log(array[i]);
}
複製代碼
for (let i of array) {
console.log(i);
}
複製代碼
本節目前已有 1 個坑,有興趣的小夥伴能夠詳看。
官方地址:地址
官方實現效果:
項目實現效果:
從圖中能夠看出,咱們大概要實現3個步驟:
調整 CSS,使 Video 佔滿 100% 的寬,而且居頂。
調整 HTML+CSS,使圖片覆蓋住視頻。
編寫 JS,使圖片點擊時,隱藏圖片,播放視頻。
*.wxml
<view class="video">
<!--
1. 綁定接口視頻路徑
2. controls - 可控制播放暫停
3. show-fullscreen-btn - 顯示全屏按鈕
-->
<video id="video" src="{{videoSrc}}" controls show-fullscreen-btn></video>
<!-- 經過 playVideo 這個方法來控制 showVideo 這個屬性,從而控制遮罩的產品圖片是否隱藏 -->
<cover-view class="{{showVideo ? 'video-mask' : 'hide-video-mask'}}" bindtap='playVideo'>
<cover-image class="video-image" src="{{videoImageSrc}}"></cover-image>
</cover-view>
<!-- 經過 playVideo 這個方法來控制 showVideo 這個屬性,從而控制遮罩的播放按鈕是否隱藏 -->
<cover-view class="{{showVideo ? 'video-mask' : 'hide-video-mask'}}" bindtap='playVideo'>
<cover-image class="video-button" src="../../public/index_productDetail_video_button.png"></cover-image>
</cover-view>
</view>
複製代碼
*.wxss
/* 設置視頻寬高 */
video {
width: 100%;
height: 420rpx;
}
/* 隱藏遮罩層 */
.hide-video-mask {
display: none;
}
/* 遮罩層 */
.video-mask {
width: 100%;
height: 420rpx;
position: absolute;
top: 0;
left: 0;
z-index: 8;
}
/* 遮罩層圖片 */
.video-image {
width: 100%;
height: 420rpx;
position: absolute;
top: 0;
left: 0;
z-index: 9;
}
/* 遮罩層播放按鈕 */
.video-button {
width: 98rpx;
height: 98rpx;
position: absolute;
top: 50%;
left: 50%;
margin-top: -49rpx;
margin-left: -49rpx;
z-index: 99;
}
複製代碼
*.js
Page({
data: {
// 視頻字段
// videoSrc: 'http://wxsnsdy.tc.qq.com/105/20210/snsdyvideodownload?filekey=30280201010421301f0201690402534804102ca905ce620b1241b726bc41dcff44e00204012882540400&bizid=1023&hy=SH&fileparam=302c020101042530230204136ffd93020457e3c4ff02024ef202031e8d7f02030f42400204045a320a0201000400',
videoSrc: '',
videoImageSrc: '',
showVideo: true,
},
/**
* 播放視頻
*/
playVideo: function () {
var that = this;
that.setData({
showVideo: false
});
// videoContext 的定義在 onReady 上
this.videoContext.play();
},
/**
* 生命週期函數--監聽頁面初次渲染完成
*/
onReady: function () {
this.videoContext = wx.createVideoContext("video")
},
})
複製代碼
如上,實現了視頻播放。
這章主要講解小夥伴們發現的 bug 及其解決思路,有興趣的小夥伴能夠私我QQ:1741020489,我將把你提出的 bug 寫進這篇文章並附上你的大名(看我的意願),謝謝小夥伴們的支持~
注:小夥伴們提出的 bug,若是包含詳細的問題描述和解決方案,我會統計進該文章的 bug 清單。
本組件目前已有 ? 個坑,有經驗的小夥伴能夠進行補充。
問題提出者:掘金 史前圖騰。
問題反饋:wx.getFileSystemManager().readdir
文件夾讀取 api
報錯,但仍會返回結果。
問題解決:這個 api 做用是讀取某個目錄下的文件名,正常會返回文件名數組,可是如今 IDE 在返回數據以前會報 'indexOf' 未定義的錯誤,並不影響api 使用。我看官方論壇上月就有人反應了,至今未修復。
本組件目前已有 ? 個坑,有經驗的小夥伴能夠進行補充。
問題提出者:掘金 jilaokang。
問題反饋:textare問題很是多,補一個。
問題解決:已聯繫大佬,等待回覆。
jsliang 的文檔庫 由 梁峻榮 採用 知識共享 署名-非商業性使用-相同方式共享 4.0 國際 許可協議進行許可。
基於github.com/LiangJunron…上的做品創做。
本許可協議受權以外的使用權限能夠從 creativecommons.org/licenses/by… 處得到。