使用小程序的 scroll-view 实现无限滚动

先来些小程序的基础知识开开胃。主要是熟悉熟悉语法,没怎么记住小程序的 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 的高度这时恰好等于屏幕高度,那么整个手机屏幕都是滚动区域了

  1. 异步方法
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 栏。


小程序动态隐藏底部的 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-into-view

scroll-with-animation

滚动实现: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说明:


bindscroll

思路到这里就清晰了,我们只需要算出五张杨幂的照片的高度,算出来的高度正好映射一个按钮。现在我们在算一张图片的高度。
使用下面的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端的楼层导航。

最后的成果图

代码优化:

  1. 上面 scrolling 函数里面一直用到了,this.setData({}),我们可以使用一个函数来替代。条件判断的数值,万一改变了去代码里面改多麻烦,可以考虑用一个数组来替换,数组放在本文件的最上面。
  2. 每一个明星,应该对应一个数组,用数组来管理图片,这样在 wxml 里面就能使用 wx:for 了,同时 for 循环应该寻的是 template,template 里面也用 for 循环。

完,2019年12月11日23点29分

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容