日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

618 京东到家-小程序也狂欢

發布時間:2025/3/19 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 618 京东到家-小程序也狂欢 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

618 將至,學了這么久小程序,也該自己動手實踐一下。最近實現了一個京東到家小程序,我將其中比較有意思,而且常用到的功能做一個展示,大家可以參考參考,完整項目在這里 github.daojia.jd

本文的實現

  • 小球落入購物車的拋物線動畫-createAnimation
  • 跳動的小紅點-badge
  • 購物車的顯示和隱藏-actionsheet
  • 獲取詳細地理位置
  • 模糊查詢

參考文檔:w3c小程序文檔、小程序實戰指南、weui.wxml

小球落入購物車的拋物線動畫

實現思路: 創造一個小球,給它一個運動軌跡,最后落入購物車區域。

如果是 DOM 編程,自然是獲取點擊的位置,用 createElement 創建一個元素,定時器給它一個動態的坐標,讓它運動起來,但這并不是 DOM ,而是小程序,使用的是數據綁定。

那這就更好了,只要數據改變,狀態就會相應的改變,那我們趕快給它實現坐標的動態輸入吧。如果你真的就這樣開始做了,那你就會陷入和我之前一樣的困境,小球運動的初始位置不是固定的,你想要讓它在任何位置都能圓潤地滾到購物車,就需要用一個算法,實現這條拋物線。

有聰明的小伙伴可能就想到了貝塞爾曲線,是的這樣確實可行,但對與我這樣的數學“天才”來說,正余弦什么的還是不了不了,打擾了,告辭。

我就想有什么更簡單的方式,能夠動態的添加拋物線動畫呢,這時我上百度Google到了一個 api createAnimation ,就決定是你了。

這是 wx.createAnimation 的官方文檔,簡單來說就是,它會創建一個動畫實例,這個實例可以描述你想要的動畫,并通過頁面的 animation 屬性綁定動畫。

那就開始了

  • 先在頁面文件(也就是你的wxml)寫個 view 來裝載動畫:
<view animation="{{animationY}}" style="position:fixed;top:{{ballY}}px;" hidden="{{!showBall}}"><view class="ball" animation="{{animationX}}" style="position:fixed;left:{{ballX}}px;"></view> </view> 復制代碼

外層 view 實現 x軸運動,內層 view 實現 縱軸y運動。 ballX,ballY是它的(坐標)位置,就是以屏幕左上為原點的坐標軸。

  • js 文件實現動畫的創建和填裝 小球在x軸勻速運動,在y軸以三次貝塞爾曲線規定的加速運動,實現拋物線落入購物車
runBall(e) {// 從全局獲取屏幕高度和寬度let bottomX = this.data.screenWidth,bottomY = this.data.screenHeight// x, y表示手指點擊橫縱坐標, 即小球的起始坐標let ballX = e.detail.x,ballY = e.detail.ythis.setData({ballX: ballX-10,ballY,showBall: false,jump: false})//實例化動畫this.animationX = wx.createAnimation({duration: 1000, timingFunction: 'linear',})this.animationY = wx.createAnimation({duration: 1000, timingFunction: 'cubic-bezier(.93,-0.11,.85,.74)',})// 第一段動畫,向上運動一點this.setDelayTime(10).then(() => {this.animationX.translateX(-100).step()this.animationY.translateY(-10).step()this.setData({animationX: this.animationX.export(),animationY: this.animationY.export()})return this.setDelayTime(200);}).then(() => {// 第二段動畫,落入購物車this.setData({showBall: true})// 平移距離是根據我的元素位置,其他需要自行調整this.animationX.translateX(-ballX-ballY*0.5).step()this.animationY.translateY(bottomY).step()this.setData({animationX: this.animationX.export(),animationY: this.animationY.export()})return this.setDelayTime(1000);}).then(() => {// 重置動畫,回到原點this.animationX.translateX(0).step()this.animationY.translateY(0).step()this.setData({showBall: false,animationX: this.animationX.export(),animationY: this.animationY.export()})}) }, // 同步操作,傳入定時器時間, setDelayTime(second) {return new Promise((resolve, reject) => {setTimeout(() => {resolve()}, second)}) }, 復制代碼.ball {width: 40rpx;height: 40rpx;background-color: #4DCC57;border-radius: 50%;z-index: 999; } 復制代碼

這段js做的事情:

  • 獲取屏幕高度和寬度
  • 獲取點擊位置,我這里就是加入購物車的那個加號,也可以是點擊商品位置,不同需求就不同。
  • 實例化動畫 animationX、animationY
  • 為這個實例添加動畫,我這里有幾段動畫,為了實現小球先向上運動一點距離,再向下,做拋物線運動。還有一個目的就是隱藏這一段,你可以看到 showBall 有不同狀態,因為運動并沒有從我的初始位置開始,這里有bug
  • 最后回到原點并隱藏小球
  • 關于 wx.createAnimation api 的使用,實例.運動方式.step(),step分隔動畫,export() 導出動畫,timingFunction 規定運動速度效果,詳細可見文檔。

    Promise 是異步編程的一種解決方案,比傳統的解決方案–回調函數和事件--更合理和更強大。這里只需要知道,可以讓這幾段動畫分步執行的就行。詳細見廖雪峰Promise

    另外,有一個小彩蛋就是,顯示數量的小紅點,在每次小球落入購物車的時候跳一下,以提醒用戶。是這樣實現的:算了,見下一段

    跳動的小紅點

    這個小紅點是用 weui 的 badge 效果,關于badge詳情見官方文檔:weui.wxml

    <view class="weui-badge {{jump?'badgeJump':''}}" style="position: absolute; display: {{shopCar.length==0?'none':''}}">{{shopCar.length}}</view> 復制代碼

    動態添加類名,jump 決定是否使用 badgeJump 類。

    this.runBall(e) this.setDelayTime(1000).then(() => {this.hasCarList()this.getTotalPrice()this.setData({jump: true}) }) 復制代碼.badgeJump {animation: jump 500ms; } @keyframes jump {0% {transform: translateY(0);}50% {transform: translateY(-50rpx);}100% {transform: translateY(0);} } 復制代碼

    同樣是在調用 runBall 方法的事件中,先調用runBall方法,在小球下落時間結束之后再將值傳入,這樣頁面的效果跟著小球的下落在改變,最后小紅點調皮地跳動一下,提示用戶有新商品加入購物車啦。

    購物車的顯示和隱藏

    想要實現的是點擊一下購物車圖標,從下而上彈出一個菜單,顯示已添加進購物車的物品。可以用 weui actionsheet 實現,沒錯又是 weui。但是我想要的是一個滾動區域而不是固定的,所以還是自己寫一個類似原生actionsheet 的吧,還可以練手。

  • 購物車和遮罩的結構
  • 首先要確定的是,整個頁面就是一屏大小,頁面不能撐出滾動條,但內部可以有滾動區域。遮罩就是整個屏幕的大小,購物車區域可以自行設定一個高度,給它一個固定定位,初始位置是在整個屏幕的下面,并不顯示在可視區,當用戶點擊購物車圖標時,從下方彈出來,單擊遮罩區域,縮回去回去并隱藏。來看代碼是怎么實現的:

    <!-- 遮罩區域 類名控制隱藏與否 --> <view class="{{clicked?'weui-mask':'weui-mask-on'}}" catchtap="hideMask"></view> <!-- 購物車區域 --> <view class="weui-actionSheet {{clicked?'weui-actionsheet_toggle':''}}"><view class="cart-header"><icon class="total-select" type="{{selectAllStatus?'success':'circle'}}" color="#4DCC57" bindtap="selectAll" /><text>{{selectAllStatus?'全選':'全不選'}}</text><text class="cart-total-num"> (已選{{shopCar.length}}件)</text><text class="clear_cart" catchtap="clearCart">清空購物車</text></view><!-- 加入購物車的商品列表 --><scroll-view scroll-y style="width: 100%; height: 700rpx;"></scroll-view> </view> 復制代碼<!-- 底部購物車圖標區域 --> <view class="cart" style="margin-top: 0;"><view class="shop_ft" style="z-index: -999;"><view class="weui-cell shop_car"><view class="weui-cell__hd {{shopCar.length==0?'car-icon_empty':'car-icon_fill'}}" catchtap="{{shopCar.length==0?'':'showCart'}}"><view class="weui-badge {{jump?'badgeJump':''}}" style="position: absolute; display: {{shopCar.length==0?'none':''}}">{{shopCar.length}}</view></view><view class="weui-cell__bd car_status" style="{{shopCar.length==0?'':'color: red;'}}"><text>{{shopCar.length==0?'購物車是空的':car_status}}</text></view></view><view class="weui-cell__ft pay" style="{{shopCar.length==0?'':'background: #4DCC57'}}" catchtap="submitOrder"><text>去結算</text></view></view> </view> 復制代碼
  • 樣式
  • /* 遮罩層 */ .weui-mask {position: fixed;top: 0;left: 0;right: 0;bottom: 0;background: rgba(0, 0, 0, .6); } .weui-mask-on {display: block; } /* 購物車 actionsheet */ .weui-actionSheet {background-color: #fff; position: fixed;bottom: 0;width: 100%; max-height: 800rpx; margin-bottom: 100rpx;z-index: 99; /* 事先隱藏才下方 */transform: translateY(100%);transition: transform .3s;font-size: 32rpx;backface-visibility: hidden;/*定義當元素不面向屏幕時是否可見*/ } /* 回到原位顯示出來 */ .weui-actionsheet_toggle {transform: translate(0, 0);transition: transform .3s; } 復制代碼
  • js 控制顯示與隱藏
  • hideMask() {this.setData({clicked: false}) }, // 點擊購物車的觸發事件 showCart() {const shopCar = wx.getStorageSync('myCart')shopCar.forEach(item => {if (item.id == this.data.shop_id) {myCart = item.list}})this.setData({// 購物車和遮罩的顯隱clicked: !this.data.clicked,shopCar: myCart})this.getTotalPrice() }, 復制代碼

    這個功能的難點應該是樣式,是整個頁面高度的控制和購物車區域的定位,這里還有一個scroll-view高度自適應的方法,可以試一試,
    flex 布局 、scroll-view的容器設置 flex: auto; overflow: auto;

    獲取詳細地理位置

    開始做這個功能的時候,第一個想法是,這種東西肯定是有api支持的,翻文檔去。 果然有:wx.getLocation(OBJECT),nice,那不就OK了嗎?你們哪,還是 naive,too young,too simple。仔細看,該方法只是返回的位置坐標等信息,并未返回地理位置名稱。

    騰訊位置服務 提供的接口 SDK 可以解決問題。怎么弄官方文檔已經寫的很清楚了,接下來就看看我是怎么應用的

    首先,按照文檔申請秘鑰,并下載 SDK,下載完成后,將文件解壓到 utils 文件夾,這里有兩個文件,壓縮和不壓縮的,建議壓縮的。

    然后,在需要獲取位置的文件中引入

    const QQMapWX = require('../../utils/qqmap-wx-jssdk') const qqmapsdk 復制代碼

    接下來就可以使用SDK獲取詳細位置了,如下

    <view class="location"><navigator class="par" hover-class="none" url="../location/location?page=1"><image src="../../assets/images/location.png"/><!-- 顯示地址 --><text>{{address}}</text></navigator> </view> 復制代碼

    index.js

    onLoad(options) {/*判斷是第一次加載還是從position頁面返回如果從position頁面返回,會傳遞用戶選擇的地點*/if (app.globalData.address) {//設置變量 address 的值this.setData({address: app.globalData.address});} else {// 實例化API核心類qqmapsdk = new QQMapWX({//此key需要用戶自己申請key: 'JF2BZ-DDH65-DCUIH-QU3TN-FT4UF-EEFEH'});var that = this// 調用接口qqmapsdk.reverseGeocoder({success: function (res) {that.setData({address: res.result.address // 詳細地址}) },fail: function (res) {// console.log(res)},complete: function (res) {// console.log(res)}});} }, 復制代碼

    我的需求是,在進入程序時,自動獲取位置信息,并顯示在頁面,所以直接放置在 onload 里,success 的回調函數返回的 res.result.address 就是詳細信息了.

    而我這里另外做了一個判斷,是因為我還提供了一個用戶自主選擇地址的功能,地址顯示優先為用戶自主選擇的。有相同需求的小伙伴可以繼續看下去。

    <view class="weui-cells weui_cell__nav-chooseLocation" bindtap="chooseLocation" style="display: {{page==1?'':'none'}};"><view class="weui-cell"><view class="weui-cell__hd"><image src="http://static-o2o.360buyimg.com/daojia/new/images/icon/location-eye@2x.png" style="margin-right: 5px;vertical-align: top;width:20px; height: 20px;"></image></view><view class="weui-cell__bd">點擊定位當前地點</view><view class="weui-cell__ft weui-cell__ft_in-access"></view></view> </view> 復制代碼

    location.js

    //選擇地點 chooseLocation: function () {wx.chooseLocation({success: res => {//選擇地點之后返回到首頁wx.switchTab({url: '/pages/index/index'})this.setData({address: res.address})// 設置全局變量app.globalData.address = res.address},fail: err => {console.log(err)}}) }, 復制代碼

    綁定的 catchtab 屬性觸發 chooseLocation 事件,wx.chooseLocation api 將直接返回當前位置,如果沒有,檢查是否開啟定位。將位置存入全局變量,在返回首頁之后可見,地址已改為用戶選擇的。

    這里的頁面跳轉選擇 switchTab 而不是常用的 navigateTo 或 redirectTo,是因為小程序為了性能消耗考慮,不允許打開超過 5 個的頁面,返回主頁 tabbar 使用 switchTab 是較好的選擇,而通過設置全局變量 address 來傳遞地址信息,也正是在這種情況下,比較適用的傳遞數據的方法之一。

    搜索-模糊查詢

    看起來這個查詢有很多,比如關鍵字啊,熱搜啊,歷史記錄查啊,但實際上用的都是同一個查詢器,先來看看吧

  • 搜索頁面布局 使用的是 weui 的 searchbar ,簡單實用
  • <view class="weui-search-bar"><view class="weui-search-bar__form"><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="{{placeholder}}" value="{{inputVal}}" bindinput="inputTyping" /><view class="weui-icon-clear" wx:if="{{hasItems}}" bindtap="clearInput"><icon type="clear" size="14"></icon></view></view></view><view class="weui-search-bar__btn"><text class="weui-search-bar__text" catchtap="doSearch">搜索</text></view> </view> 復制代碼
  • 使用 bindinput="inputTyping" ,它可以監測你的每一次輸入,并通過 e.detail.value 向你反饋出來,我們可以以此獲得關鍵字。
  • inputTyping: function (e) {this.setData({search: {inputVal: e.detail.value // 由于我的搜索是使用模板建立的,數據傳遞需要嵌套一下},input: e.detail.value,})this.showKeyList(e.detail.value) }, 復制代碼
  • weui-searchbar 自帶清空搜索框,挺方便,接拿來用。
  • clearInput: function () {this.setData({search: {inputVal: ""},}) }, 復制代碼
  • 接下來就是對關鍵字的處理
    將關鍵字字符串用 split 方法,分割為字符串數組,在關鍵字列表中查詢每一個關鍵字符,使用 indexOf 方法檢索,如果存在這樣一個字符,就返回這個字符的下標,如果沒有將返回 -1,最后將檢索結果放入數組中,這就是在搜索框下部顯示的關鍵字列表了。
  • showKeyList(keyWords) {const key = keyWords ? keyWords.split('') : []const keyListAll = app.globalData.keyListconst keyList = []keyListAll.forEach(item => {key.forEach(k => {let i = item.indexOf(k)if (i > -1) {keyList.push(item)}})})this.setData({search: {keyList, // 查詢結果將在頁面顯示}}) }, 復制代碼
  • 既然有了關鍵字,那么就可以查詢數據 在這里,我也是使用如上方法,分割字符串,依次查詢,并且將這個方法封裝成一個函數,只需傳入要檢索的關鍵詞和目標數組,就可以在任何地方調用它進行查詢。
  • // 關鍵字查詢 search(keyWords, arr) {const cur = []const desc = new Set() // 使用 set 可以去重const key = keyWords ? keyWords.split('') : []arr.forEach(ele => {key.forEach(k => {let i = ele.title.indexOf(k)if (i > -1) {cur.push(ele.id)desc.add(ele)}})})this.setData({cur,search: {desc: Array.from(desc)}}) }, // 數據查詢 searchItem(keyWords) {const goods = app.globalData.details,shops = app.globalData.shopInfo,temp = [],list = []goods.forEach(item => {item.desc.forEach(ele => {temp.push(ele)}) })// 調用搜索this.search(keyWords, temp)shops.forEach(item => {this.data.cur.forEach(i => {if (item.goodslist.indexOf(i) > -1) {list.push(item)}})})var resList = Array.from(new Set([...list]))this.setData({search: {resList,desc: this.data.search.desc,},})if (this.data.search.resList.length > 0) {this.setData({hasItems: true,search: {resList,desc: this.data.search.desc,hasItems: true,},})} else {this.setData({hasItems: false,search: {hasItems: false,},})} }, 復制代碼
  • 熱搜查詢和歷史記錄再次查詢 馬上就用到了剛才封裝的方法了, 這是熱搜和歷史記錄共用的查詢方法,只需一步調用
  • add_search(e) {const index = e.currentTarget.dataset.indexthis.setData({search: {inputVal: index,},input: index,})this.searchItem(index) }, 復制代碼

    其實查詢功能還可以精簡很多,只是我的偽數據數組太多,需要聯合查詢,比較麻煩。感覺數據處理還是SQL語句方便多哈,多表查詢,模糊查詢。。。

    以上

    希望對大家有幫助

    總結

    以上是生活随笔為你收集整理的618 京东到家-小程序也狂欢的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。