問題:
小程序里如果通過條件渲染不起作用虏劲,可以嘗試通過雙重的a:if來判斷(下面只有type為1和2的情況用含,本來我們可以用a:else的但是不起作用)
對于input表單的雙向綁定
<form onSubmit="dropOut">
<view class="drop-warpper white">
<view class="line">
<label>收款人姓名</label>
<input placeholder="請輸入你的姓名" value="{{person.name}}" onBlur="modifyName"/>
</view>
<view class="line">
<label>支付寶賬號</label>
<input placeholder="請輸入你的支付寶賬號" value="{{person.number}}" onBlur="modifyNumber" />
</view>
</view>
<text class="intro">請正確填寫您本人支付寶,提現(xiàn)發(fā)起后糯笙,24小時內(nèi)即可到賬</text>
<button size="default" class="down-button {{person.name && person.number ? 'active' : ''}}" onTap="toDownload" hover-class="none">立即提現(xiàn)</button>
</form>
data: {
person: {
name: '',
number: ''
}
},
modifyName(e) {
const {value} =e.detail
this.setData({
'person.name': value
})
},
modifyNumber(e) {
const {value} = e.detail
this.setData({
'person.number': value
})
},
toDownload() {
const {name,number} = this.data.person
if (!name.trim()) {
app.$toast('fail','名字不能為空')
} else if(!number.trim()) {
app.$toast('fail','支付寶賬號不能為空')
} else {
my.navigateTo({
url: `/pages/goldCenter/goldConvert/downGuide/downGuide?accountBalance=${this.data.accountBalance}`
})
}
}
要點:通過給每個input監(jiān)聽一個onBlur失去焦點事件,來修改綁定的值鹃栽,然后點擊按鈕的時候判定一下對應(yīng)的值為不為空
<view slot="header" class="header-title" a:if="{{type === 1}}">金幣福利兌換說明</view>
<view slot="header" class="header-title" a:if="{{type === 2}}">優(yōu)惠券詳情</view>
基本目錄結(jié)構(gòu)
- acss
可以通過page來修改當(dāng)前頁面的樣式
page {
background: green;
}
新建頁面的時候選擇新建小程序頁面(相關(guān)的四個文件都會被創(chuàng)建)
app.json
"pages": [
// 第一個就是首頁
"pages/index/index",
"pages/hello/hello"
],
app的生命周期
onLaunch -> 項目初始化完成時觸發(fā)档玻,只觸發(fā)一次
onSHow -> 頁面展示的時候觸發(fā)
onHide -> 頁面隱藏的時候觸發(fā)
onError -> 程序出現(xiàn)錯誤時觸發(fā)
App({
onLaunch(options) {
// 第一次打開
// options.query == {number:1}
console.log('第一次打開')
},
onShow(options) {
// 從后臺被 scheme 重新打開
console.log('頁面展示')
},
onHide() {
console.log('頁面隱藏')
throw new Error('此處發(fā)生錯誤')
},
onError() {
console.log('頁面報錯')
}
});
page的生命周期
onLoad -> 頁面加載時執(zhí)行,每個頁面只執(zhí)行一次
onReady -> 頁面初次渲染完成茫藏,每個頁面只執(zhí)行一次
onShow -> 頁面顯示后執(zhí)行一次误趴,可執(zhí)行多次
onHide -> 頁面每次隱藏時執(zhí)行一次
onUnload -> 頁面卸載執(zhí)行一次
- 這里要注意是先執(zhí)行的onShow頁面顯示,然后等到頁面視圖渲染完成后才執(zhí)行onReady
- 頁面卸載鉤子觸發(fā)可以通過頁面重定向(會先關(guān)閉當(dāng)前頁面务傲,然后進(jìn)行跳轉(zhuǎn))
<view onTap="close">關(guān)閉</view>
close() {
my.redirectTo({
// 這里需要注意這里的url需要寫成絕對路徑
url: '/pages/index/index'
});
}
onReachBottom -> 在有滾動條的情況下頁面滾動到底部時觸發(fā)
onPullDownRefresh -> 下拉刷新的時候觸發(fā)的鉤子(必須在對應(yīng)的頁面的json里開啟"pullRefresh": true)
onShareAppMessage -> 分享時觸發(fā)的鉤子
注意分享鉤子必須返回一個對象凉当,對象里面有三個屬性,title售葡,desc和path
onShareAppMessage() {
console.log('分享')
return {
title: '你好女朋友',
desc: '我是你未來的男朋友',
path: 'pages/hello/hellp'
}
}
全局常量看杭、對象、自定義函數(shù)的使用
在app.js里定義全局的屬性挟伙、對象和方法
App({
// 里面是你要定義的全局屬性或方法
name: 'lifa',
age: 18,
body: {
leg: 120,
eyes: 'big'
},
make() {
console.log('aaa')
}
}
在app.js中定義的只需要在每一個頁面的.js中通過一個getApp()就可以獲取到app的實例
const app = getApp()
Page({
onReady() {
console.log(app)
console.log('當(dāng)前頁面渲染完成')
console.log(app.name)
console.log(app.age)
console.log(app.body)
app.make()
},
})
設(shè)置背景色和標(biāo)題
全局設(shè)置
- app.json
"window": {
"defaultTitle": "My App",
"titleBarColor": "#ccc"
}
單頁面配置
{
"defaultTitle": "one",
"titleBarColor": "#ccc"
}
可以在目錄pages里配置一個目錄里面裝別的文件
tabBar
textColor: 文字顏色
selectedColor: 文字選中后顏色
backgroundColor: 背景顏色
items: 每個單獨tab項(數(shù)組)
items tab數(shù)組配置
pagePath:頁面路徑
name: 文字
icon: 未選中的圖標(biāo)
activeIcon: 選中后的圖標(biāo)
導(dǎo)航欄數(shù)據(jù)結(jié)構(gòu)
"tabBar": {
"textColor": "字體顏色",
"selectedColor": "選中顏色",
"backgroundColor": "底色",
"items": [
{
"pagePath": "pages/index/index",
"name": "首頁",
"icon": "未選中圖標(biāo)",
"activeIcon": "選中后圖標(biāo)"
}
]
}
獲取和修改data要通過this.data.屬性名
導(dǎo)航組件<navigate></navigate>
hover-class: 點擊時改變的樣式
hover-start-time: 按住ms后出現(xiàn)點擊狀態(tài)
hover-stay-time: 手指釋放ms后保留的狀態(tài)
url: 頁面跳轉(zhuǎn)的地址
open-type:跳轉(zhuǎn)類型
- 默認(rèn):navigate -> 保留當(dāng)前頁面楼雹,跳轉(zhuǎn)到新頁面(左上方會有返回按鈕)
- redirect -> 銷毀當(dāng)前頁面,跳轉(zhuǎn)新頁面尖阔,不能再返回當(dāng)前頁(會觸發(fā)onUnload)
- navigateBack -> 返回上一級頁面(與navigate配合使用贮缅,就和直接在左上方點返回是一樣的)
- switchTab -> 跳轉(zhuǎn)到tab選項卡頁面
<navigator url="/pages/index/index">
頁面跳轉(zhuǎn)(默認(rèn)navigate)
</navigator>
<navigator url="/pages/index/index"
open-type="redirect"
>
頁面跳轉(zhuǎn)(redirect)
</navigator>
<navigator url="/pages/other/hello/hello"
open-type="switchTab"
hover-class="other-navigator-hover">
頁面跳轉(zhuǎn)到首頁(switchTab)
</navigator>
導(dǎo)航api
功能和navigator組件一致
<view onTap="jump">
導(dǎo)航api跳轉(zhuǎn)
</view>
Page({
data: {},
onLoad() {},
jump(){
my.navigateTo(
{
url: '/pages/index/index'
}
)
}
});
數(shù)據(jù)綁定和條件渲染
<view a:if="{{student.age < 18}}">未成年</view>
<view a:elif="{{student.age > 18}}">成年了</view>
<view a:else>18</view>
Page({
data: {
student: {
age: 18
}
}
})
列表渲染
默認(rèn)每一個是item,索引是index介却,可以通過 a:for-item自定義item谴供,和a:for-index自定義index
<view a:for="{student.courses}" a:for-item="lesson" a:for-index="i">
下標(biāo):{{i}},
課程名: {{lesson.name}},
節(jié)數(shù):{{lesson.counts}}
</view>
data: {
student: {
courses: [
{
name: 'lili',
counts: 100
},
{
name: 'lili',
counts: 100
}
]
}
}
view和block的區(qū)別
block就相當(dāng)于template不會有標(biāo)簽顯示在頁面中,而view會作為標(biāo)簽顯示在頁面中
6種不同的事件類型
tap:點擊事件
longTap:
<view onTap="tap">
點擊事件
</view>
<view onLongTap="longTap">
長按點擊事件
</view>
<view onTouchStart="touchStart">
開始觸摸(點擊)
</view>
<view onTouchMove="touchMove">
觸摸后移動
</view>
<view onTouchEnd="touchEnd">
觸摸結(jié)束
</view>
<view onTouchCancel="touchCancel">
觸摸中斷(非正常結(jié)束齿坷,比如觸摸過程中手機來電)
</view>
Page({
data: {},
onLoad() {},
tap() {
console.log('點擊事件')
},
longTap() {
console.log('長按點擊事件')
},
touchStart() {
console.log('開始觸摸')
},
touchMove() {
console.log('觸摸后移動')
},
touchEnd() {
console.log('觸摸結(jié)束')
},
touchCancel() {
console.log('觸摸中斷')
}
});
dataset自定義數(shù)據(jù)的使用
<view data-name="lifa" onTap="getDataName">
獲取dataName
</view>
getDataName(e) {
console.log(e)
console.log(e.target.dataset.name) //lifa
}
用來在列表循環(huán)的方法中拿到你對應(yīng)item中的數(shù)據(jù)
<view a:for="{{lists}}" onTap="getIndex" data-index="{{index}}">
...
</view>
data: {
lists: [
{name: 'lifa', age: 18},
{name: 'linlin', age: 18}
]
},
getIndex(e){
const {index} = e.target.dataset
console.log(index) //對應(yīng)的每次點擊拿到當(dāng)前的索引值
}
圖片組件
lazyLoad是否懶加載桂肌,默認(rèn)為false
onError圖片加載錯誤時執(zhí)行的方法
onLoad圖片加載成功后觸發(fā)
<image src="" class="" style="" lazyLoad="{{true}}" onError="imgError" onLoad="imgLoad"/>
imgError() {
console.log('加載失敗')
},
imgLoad() {
console.log('加載成功')
}
圖片的4種縮放模式與9種裁剪模式
- 4中縮放模式
其中scaleToFill是默認(rèn)的模式
- 9中裁剪模式
輪播組件:swiper
可滾動視圖組件:scroll-view
<scroll-view scroll-x="{{true}}" class="scroll-items" >
<image mode="scaleToFill" src="/resources/items/1001.png" class="shop-img"/>
<image mode="scaleToFill" src="/resources/items/1002.png" class="shop-img"/>
<image mode="scaleToFill" src="/resources/items/1001.png" class="shop-img"/>
<image mode="scaleToFill" src="/resources/items/1002.png" class="shop-img"/>
<image mode="scaleToFill" src="/resources/items/1001.png" class="shop-img"/>
<image mode="scaleToFill" src="/resources/items/1002.png" class="shop-img"/>
<image mode="scaleToFill" src="/resources/items/1001.png" class="shop-img"/>
<image mode="scaleToFill" src="/resources/items/1002.png" class="shop-img"/>
</scroll-view>
</view>
.scroll-items {
width: 100%;
white-space: nowrap;
}
接口調(diào)用-輪播圖
小程序的api都是my.的
一般在onReady里請求接口
全局的baseUrl可以寫在app.js里
// app.js
App({
baseUrl: 'https://www.imoocdsp.com',
})
// index.axml
<swiper indicator-dots="{{true}}">
<block a:for="{{carousels}}">
<swiper-item >
<image mode="scaleToFill" src="{{item.imageUrl}}" class="swiper-img"/>
</swiper-item>
</block>
</swiper>
// index.js
const app = getApp()
Page({
data: {
carousels: []
},
onReady() {
my.request({
url: app.baseUrl + `/index/carousels`, // 目標(biāo)服務(wù)器url
method: 'post',
headers: {'content-type': 'application/json'},
success: (res) => {
this.setData({
carousels: res.data.data
})
},
});
}
});
接口封裝
// request.js
export default function request(url, method='post', data={}) {
return new Promise((resolve, reject) => {
let option = {
url,
method,
data
}
my.request({
...option,
success: (res) => {
if(res.data.status === 200) {
resolve(res.data)
} else {
reject(res.data)
}
},
fail: () => {
reject('失敗')
}
})
})
}
//api/index.js
import request from '/untils/request.js'
const url = {
Carousels: '/index/carousels',
RecommendProduct: '/index/items/rec',
newList: '/index/items/new'
}
const host = 'https://www.imoocdsp.com'
for (let key in url) {
if(url.hasOwnProperty(key)){
url[key] = host + url[key]
}
}
export default {
carousels() {
return request(url.Carousels)
},
recommendProduct() {
return request(url.RecommendProduct)
},
newList() {
return request(url.newList)
}
}
對上面封裝的接口進(jìn)行使用
import index from '/api/index.js'
Page({
data: {
carousels: [],
newItemList: [],
recommendProduct: []
},
onReady() {
index.carousels().then(
(res => {
this.setData({carousels: res.data})
})
)
index.recommendProduct().then(
res => {
this.setData({recommendProduct: res.data})
}
)
index.newList().then(
res => {
this.setData({newItemList: res.data})
}
)
}
});
因為我們的onReady生命周期就和created一樣只會在頁面第一次加載的時候執(zhí)行一遍,所以我們的數(shù)據(jù)更新可以在下拉刷新中操作
將一開始的數(shù)據(jù)獲取的操作放到一個初始化方法里永淌,然后在onReady和onPullDownRefresh中都調(diào)用崎场,前面說過下拉刷新要在json中配置"pullRefresh": true
onPullDownRefresh () {
this.initData()
},
onReady() {
this.initData()
},
initData() {
index.carousels().then(
(res => {
this.setData({carousels: res.data})
})
)
index.recommendProduct().then(
res => {
this.setData({recommendProduct: res.data})
}
)
index.newList().then(
res => {
console.log(res.data)
this.setData({newItemList: res.data})
}
)
}
navigate帶參跳轉(zhuǎn)到下一頁面
<input type="text" placeholder="請輸入搜索商品名..." auto-focus class="search-input"
confirm-type="search" onConfirm="searchItems" />
searchItems(e) {
const { value } = e.detail
if (value.trim() !== '') {
my.navigateTo({
// 1.將參數(shù)放到url中
url: "/pages/query/list/list?itemName=" + value
})
}
}
// 2.在跳轉(zhuǎn)到的頁面(list)中的onLoad鉤子里獲取當(dāng)前傳進(jìn)來的參數(shù)
// - list
onLoad(params) {
const {itemName} = params
console.log(itemName) // 這里的itemName就是你傳進(jìn)來的參數(shù)
}
navigator組件帶參
<navigator url="/pages/query/list/list?searchType=cat&catId=0&catName=奢侈品" open-type="navigate">
<image src="/resources/category/0-luxury.png" class="cat-ico" />
<view class="cat-name">奢侈品</view>
</navigator>
顯示loading
- 頂部topbar的loading
// 開啟
my.showNavigationBarLoading()
// 關(guān)閉
my.hideNavigationBarLoading()
- body里的loading
// 開啟
my.showLoading({
content: '瘋狂加載中...' // 自定義的loding文字
})
// 關(guān)閉
my.hideLoading()
這里開啟的時候在請求最初的位置,關(guān)閉在complete方法里遂蛀,因為不管成功還是失敗都會關(guān)閉
export default function request(url, method='post', data={}, headers='application/json') {
return new Promise((resolve, reject) => {
let option = {
url: app.baseUrl + url,
method,
headers: {'content-type': headers},
data
}
my.showLoading({
content: '瘋狂加載中...'
})
my.request({
...option,
dataType: 'json',
success: (res) => {
if(res.data.status === 200) {
resolve(res.data)
} else {
reject(res.data)
}
},
fail: () => {
reject('失敗')
},
complete: () => {
my.hideLoading()
}
})
})
}
公用模板組件的使用
新建一個template文件照雁,在這個文件里建你需要公用的組件,然后在里面的axml中使用一個template標(biāo)簽答恶,并且指定name饺蚊,然后在當(dāng)前模板中的acss中把公用的樣式拷貝進(jìn)去
<template name="itemList">
// 這里面是公用的代碼
<view class="new-item-list">
<view class="item-outter" a:for="{{newItemList}}">
<image src="{{item.cover}}" class="new-item-cover" />
<view class="item-border">
<view class="tags" a:for="{{item.tagList}}" a:for-item="tag">{{tag}}</view>
</view>
<view class="price-border">
<view class="price">¥{{item.priceDiscountYuan}}</view>
<view class="like-counts">
{{item.likeCounts}}
<image src="/resources/icon/smallIco/likes.png" class="like-ico" />
</view>
</view>
</view>
</view>
</template>
在需要使用模板的地方通過import標(biāo)簽引入
<import src="/pages/template/itemList/itemList">
// 這里的is后面的就是你上面的name
//newItemList鍵名會作為傳入模板中的變量,也就是上面對應(yīng)的newItemList悬嗓,也就是鍵名是什么你模板里就對應(yīng)寫什么
// list當(dāng)前頁面的data里的數(shù)據(jù)污呼,將list賦給newItemList
<template is="itemList" data="{{newItemList: list}}"></tempalte>
修改內(nèi)部屬性
this.setData({
prize: this.data.prize+1 //這里就是通過this.data
})
動態(tài)添加一個class
// 如果sIndex+1等于index就添加active否則就為空,必須通過三元運算符判斷
<view class="check-item {{index === sIndex+1 ? 'active' : ''}}"></view>
使用動畫api實現(xiàn)加入購物車動畫
- 首先需要在組件中使用animation屬性綁定數(shù)據(jù)
<view animation="{{animationInfo}}" class="animation-img" style="opacity:{{animationOpacity}};background-image:url('{{headerImages[0]}}')"></view>
- 在js里導(dǎo)出這個動畫(這里需要注意每次要修改動畫實例綁定的數(shù)據(jù)都需要重新export())
onShow() {
// 創(chuàng)建動畫
var animation = my.createAnimation({
duration: 500
})
this.animation = animation
this.setData({
// 導(dǎo)出動畫效果到頁面
animationInfo: animation.export()
})
},
addToCart() {
this.setData({
animationOpacity: 1
})
this.showAddToCartAnimation()
},
showAddToCartAnimation() {
// 旋轉(zhuǎn)的同時在水平方向移動包竹,動畫結(jié)束必須加.step()
this.animation.rotate(-180).translateX('296rpx').step()
this.setData({
animationInfo: this.animation.export()
})
}
- 實現(xiàn)購物車動畫復(fù)原(把設(shè)置的值都變?yōu)?)燕酷,每次點擊玩過一段時間動畫復(fù)原籍凝,再點擊重新開始
思路:點擊完動畫結(jié)束后給一個setTimeout,然后在幾秒后把動畫復(fù)原苗缩,這樣下次再點擊又從最開始的狀態(tài)開始動畫
// 復(fù)原動畫
setTimeout(() => {
// 這里因為需要先將動畫的小圓點透明度變?yōu)?饵蒂,然后再還原動畫,所以不能同時設(shè)置
this.setData({
animationOpacity: 0,
cartIco: 'cart-full'
})
this.animation.rotate(0).translateX(0).step({
duration: 0
})
// 再透明度變?yōu)?后再還原動畫
setTimeout(() => {
this.setData({
animationInfo: this.animation.export()
})
},550)
},600)
完整代碼
<view class="add-to-cart" onTap="addToCart">
<!-- 定義動畫組件酱讶,創(chuàng)建實例 -->
<view animation="{{animationInfo}}" class="animation-img" style="opacity:{{animationOpacity}};background-image:url('{{headerImages[0]}}')"></view>
放入購物車
</view>
onShow() {
// 創(chuàng)建動畫
var animation = my.createAnimation({
duration: 500
})
this.animation = animation
this.setData({
// 導(dǎo)出動畫效果到頁面
animationInfo: animation.export()
})
},
addToCart() {
this.setData({
animationOpacity: 1
})
this.showAddToCartAnimation()
},
showAddToCartAnimation() {
// 旋轉(zhuǎn)的同時在水平方向移動
this.animation.rotate(-180).translateX('370rpx').step()
this.setData({
animationInfo: this.animation.export()
})
// 復(fù)原動畫
setTimeout(() => {
// 這里因為需要先將動畫的小圓點透明度變?yōu)?退盯,然后再還原動畫,所以不能同時設(shè)置
this.setData({
animationOpacity: 0,
cartIco: 'cart-full'
})
this.animation.rotate(0).translateX(0).step({
duration: 0
})
// 再透明度變?yōu)?后再還原動畫
setTimeout(() => {
this.setData({
animationInfo: this.animation.export()
})
},550)
},600)
}
使用緩存api實現(xiàn)購物車商品添加
設(shè)置緩存
my.setStorageSync({
key: 'student',
data: {
name: '',
age: 18
}
})
獲取緩存
var stu = my.getStorageSync({
key: 'student'
})
console.log(stu)
刪除緩存(同步 )
my.removeStorageSync({
key: 'student'
})
清除所有緩存
my.clearStorage()
實現(xiàn)購物車重復(fù)商品不再添加到數(shù)組里而是對應(yīng)id下的count+1
addToCart() {
this.setData({
animationOpacity: 1
})
this.showAddToCartAnimation()
this.cartItemIncrease()
},
cartItemIncrease() {
const itemId = this.data.item.id
let cartArray = my.getStorageSync({
key: 'cartArray', // 緩存數(shù)據(jù)的key
}).data
// 先判斷是否有緩存的數(shù)據(jù)泻肯,如果沒有就等于一個空數(shù)組
if(!cartArray) {
cartArray = []
}
// 把當(dāng)前的對象賦值給這個數(shù)組
let cartItem = {itemId,counts:1}
cartArray.forEach((item,index) => {
// 如果數(shù)組里面有id等于你當(dāng)前的對象里的id就把當(dāng)前index記錄下來
if (item.itemId === cartItem.itemId) {
this.setData({
index
})
}
})
// 通過index是否大于-1來判斷是直接push還是當(dāng)前數(shù)組里對應(yīng)的id里的count+1
if (this.data.index > -1) {
cartArray[this.data.index].counts+=1
} else {
cartArray.push(cartItem)
}
my.setStorageSync({
key: 'cartArray', // 緩存數(shù)據(jù)的key
data: cartArray, // 要緩存的數(shù)據(jù)
});
},