小程序随笔

作者: 小白不白Zcq | 来源:发表于2020-01-07 10:29 被阅读0次

    2019.12.16号开始接触小程序,也是第一次接触。随笔写些流程也好,想法也罢,方便之后参考。

    一、小程序简介

    1.小程序是一种全新的连接用户与服务的方式。

    2.小程序并非凭空冒出来的一个概念,当微信中的WebView逐渐成为移动Web的一个重要入口时,微信就有相关的JS API了。

    3.小程序的主要语言是JavaScript。小程序的逻辑层和渲染层是分开的,逻辑层运行在JSCore中,并没有一个完整浏览器对象,因而缺少相关的DOM API和BOM API。这一区别导致了前端开发非常熟悉的一些库,例如jQuery等,在小程序中是无法运行的。同时JSCore的环境同NodeJS环境也不尽相同,所以一些NPM的包在小程序中也是无法运行的(只是一部分不可使用,小程序还是支持npm的)

    4.小程序的开发需要经过:申请小程序账号、安装小程序开发者工具、配置项目等等过程方可完成。下面是小程序申请账号的官方文档,一步步的按步骤进行即可。
    https://developers.weixin.qq.com/miniprogram/dev/framework/quickstart/getstart.html

    二、小程序的代码构成

    1.文件类型:

    <1> .json后缀的JSON配置文件
    <2> .wxml后缀的WXML配置文件
    <3> .wxss后缀的WXSS配置文件
    <4> .js后缀的JS配置文件
    JSON配置:JSON是一种数据格式,并非编程语言

    2.创建页面:

    先在项目中创建一个文件夹,然后在开发者工具中右键文件夹,点击“新建Page”,起好名字后,会自动创建“xx.js”、“xx.json”、“xx.wxml”、“xx.wxss”四个文件。创建之后,会在项目app.json中的“pages”项中自动生成路径。

    3.app.json配置介绍

    <1>pages:各个页面的路径,可以理解在这里配置路由。

    <2>permission:在小程序开发中,需要获取用户所在地理位置,需要在app.json中增加premission属性配置。

    "permission": {
        "scope.userLocation": {
          "desc": "你的位置信息将用于小程序位置接口的效果展示"
         }
      }
    

    <3>window:

    用于设置小程序的状态栏、导航条、标题、窗口背景色。

    每一个小程序页面都可以使用.json文件对本页面的窗口表现进行配置(可以理解成小程序页面的顶部靠.json中的window来设置,不过也是可以自定义的,用window方便一些)。
    页面中配置项在当前页面会覆盖app.json的window中相同的配置项(可以理解每个页面中的json配置项的优先级大于app.json配置项)。

    <4>usingComponents:

    引入组件

    这真是我最想吐槽的一个点。。真xxx的是xxx的难用!!
    感受一下:我用小程序的组件,不能全局引用,用到哪个引入哪个,最恐怖的是路径还要自己去文件夹中找。
    目前我是这样用的,如果有更好的用法,希望有大佬指点一下!

      "usingComponents": {
        "l-loading": "/miniprogram_npm/lin-ui/loading/index",
        "l-tabs": "/miniprogram_npm/lin-ui/tabs/index",
        "l-tabpanel": "/miniprogram_npm/lin-ui/tabpanel/index",
        "l-input": "/miniprogram_npm/lin-ui/input/index",
        "l-textarea": "/miniprogram_npm/lin-ui/textarea/index",
        "l-search-bar": "/miniprogram_npm/lin-ui/search-bar/index"
      },
    

    <5>tabBar:

    如果小程序是一个多tab应用(客户端窗口的底部或顶部有tab栏可以切换页面),可以通过tabBar配置项指定tab栏的表现,以及tab切换时显示的对应页面。

    小程序的这一点我觉得还是很好用的,用vue来说就是一个底部标签页的组件,我用vue要用状态管理要自己封装引入,然后在小程序自己定义一个tabBar就可以搞定了。

    "tabBar": {
        "color": "#8c8c8c",
        "selectedColor": "#2A5AAA",
        "backgroundColor": "#fff",
        "list": [
          {
            "pagePath": "pages/index/index",
            "text": "首页",
            "selectedIconPath": "./images/assets/我的订单(选中状态)@3x.png",
            "iconPath": "./images/assets/我的订单(未选中)@3x.png"
          },
          {
            "pagePath": "pages/logs/logs",
            "text": "设置",
            "selectedIconPath": "./images/assets/设置(选中)@3x.png",
            "iconPath": "./images/assets/设置(未选中)@3x.png"
          }
        ],
        "position": "bottom"
      },
    
    4.项目思路

    1.app.js:用户每次登录都会调用wx.login接口获取code,并将code存入缓存。判断用户是否之前已经授权信息,如果已授权则直接进入index首页,仍未授权进入login登录页。

    2.login.js:登陆页面。用户点击登录按钮,弹出授权框,点击授权进入手机绑定页面,拒绝授权则停留在当前页面。

    3.information:手机绑定页面。用户第一次授权成功后进入手机绑定页面。绑定成功后进入首页。

    4.index:首页。在首页点击任意一条信息进入信息详情页。并且将本条信息的单号和tabNum传给信息详情页。

    5.orderDetails:信息详情页。接受上一页的单号和tabNum传给回单上传页面。

    6.replyUpload:回单上传页。点击添加图片调用wx.chooseImage选择图片后调用后台接口,将已选择图片信息上传给服务器,并且获取返回值id。点击确定上传对接上传接口,将id作为参数上传。上传成功后返回index首页。

    eg:用户再次进入该项目的时候,继续执行第一步,不过已经授权过,则会直接进入index首页,以上是此项目的一个大概的思路流程。

    三、小程序应用点

    1.小程序本地存储

    //存数据
    wx.setStorageSync("code",res.code);
    //取数据
    wx.getStorageSync("code")
    

    2.存数据到当前页面data中

    //控制显隐时立刻生效
    that.setData({
      list: res.data.list
    });
    //单纯的赋值
    that.data.list = res.data.list
    

    其实这里面原本是this.setData,而至于为什么要用that,是因为:
    如果使用this在函数中的话会出现——使用回调函数异常

    报错信息:TypeError: Cannot read property 'setData' of undefined
    问题:作用域问题,回调函数中的作用域已经脱离了调用函数,因此需要在回调函数外边把this赋给一个新的变量才可以
    解决方法:var that = this;
    建议:****在每一个方法中都先定义一下that,每次都使用that****

    3.小程序传参/接参
    路由传参
    很重要的一点:url里面都是字符串
    传参如果是对象类型或者数组,隐式转换为[Object,Object]
    JSON.stringify():JavaScript => JSON (直接转)
    JSON.parse():JSON => JavaScript(先转为 JSON 再转为 JS)

     wx.navigateTo({
          url:
            "/pages/****/****?orderMovementGid=" +
            orderMovementGid +
            "&tabNum=" +
            that.data.tabNum
        });
    
      onLoad: function(options) {
        var that = this;
        that.setData({
          orderMovementGid: options.orderMovementGid,
          tabNum: options.tabNum
        });
    }
    

    小程序传参

        wx.navigateTo({
          url: "/pages/costFallIn/costFallIn",
          success: function (res) {
            // 通过eventChannel向被打开页面传送数据
            res.eventChannel.emit("acceptDataFromOpenerPage", {
              status: "chaKan",
              id,(前后一样可以写一个就ok了)
              tlFiles: item.tlFiles,
            });
          },
        });
    
        const eventChannel = this.getOpenerEventChannel()
        // 监听acceptDataFromOpenerPage事件,获取上一页面通过eventChannel传送到当前页面的数据
        eventChannel.on('acceptDataFromOpenerPage', function(data) {
          console.log(data)
        })
    

    4.页面跳转
    页面跳转的话还是参考一下官方文档,有好几种跳转
    我最常用的几种:wx.switchTab(需要跳转至tab页),wx.redirectTo(需要跳转至非tab页),wx.navigateTo(跳转至下一页,自带返回按钮)
    https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.switchTab.html

    5.onLoad和onShow
    不需要刷新的函数写在onLoad里面,
    需要刷新的函数写在onShow里面。
    (这里onShow可以理解为监控路由,路由发生变化的时候,重新调用onShow)

    6.开发者工具
    <1>预览:使用开发者工具预览小程序,点击“预览”按钮,开发者工具会自动打包当前项目,并上传小程序代码至微信的服务器。
    <2>上传:点击上传的话,相当于打包当前小程序,发送“体验版”,可以在微信后台管理中进行查看。
    <3>开发者工具不能识别1rpx,最低2rpx(1px)
    手机可以识别1rpx

    7.小程序解决文字超出不换行问题

    display:block;
    word-break: break-all;
    word-wrap: break-word;
    
    //弹性布局换行
    flex-wrap: wrap;
    

    8.点击事件(bindtap="xxx")

    .wxml
    <view class="bottomButton" bindtap="okBinding">确认绑定</view>
    .js
    okBinding: function() {}
    

    点击事件传参,不能有()会报警告
    需要给元素绑定 data-id='{{item.id}}'。
    从事件对象中:e.currentTarget.dataset.id获取。
    (多个参数就绑定多个data-xxx='{{item.xxx}}')

    9.获取input输入框内容(bindInput="xxx")

    .wxml
    <input label="手机号" placeholder="请输入手机号" type="number" bindinput="phoneInput"/>
    .js
    //每次输入都会触发这个事件
    phoneInput: function(e) {
      this.data.phoneNum = e.detail.value;
    },
    

    10.控制显隐(wx:if)

     <view wx:if="{{tabNum=='PICKUP'}}" >确认提货</view>
    

    11.循环遍历(wx:for)

    <view class="midContent"  wx:for="{{list}}" wx:key="{{index}}"></view>
    wx:for-item="item1" wx:for-index="index1"
    

    12.设置顶部标题

    "navigationBarTitleText": "首页"
    

    动态更改小程序顶部标题

    wx.setNavigationBarTitle({
      title: "我是修改后的标题"
    });
    

    自定义顶部导航栏

    "navigationStyle": "custom",
    

    13.回调函数——我觉得很不友好的一点
    比如我们一个回调函数,正确的话进入success,错误的话进入fail。
    但是小程序的回调函数不同,这是官方解释

    只要成功接收到服务器返回,无论statusCode是多少,都会进入success回调。请开发者根据业务逻辑对返回值进行判断。

    也就是说我们即使调通接口失败了,只要后台返回给我们信息了,也要通过statusCode来判断。

    四、封装组件(自定义提示框)

    <1>新建文件夹
    在根目录下新建components文件夹,然后在文件夹中新建自定义目录,再右键“新建Page”,(记得把prompt-box.js中表头的Page改成Component)。


    新建components.png

    <2>组件:json配置

    {
      "component":true  //官方文档说的是:将component字段设为true可将这一组文件设为自定义组件
    }
    

    <3>组件:wxml编写

    <!-- 提示框组件 -->
    <view class="promptBox">
        提示框
    </view>
    

    <4>app.json全局引入组件

      "usingComponents": {
        "prompt-box": "./components/prompt-box/prompt-box"
      }
    

    <5>父组件:使用组件

    <prompt-box></prompt-box>
    

    五、父子传值

    1.子文件→父文件。(通过 triggerEvent 事件)(需要手动触发获取)

    .wxml
    <!-- 提示框组件 -->
    <view class="promptBox">
        <view class="buttonBox" bindtap="toUpperLevel">朕知道了</view>
    </view>
    
    .js
    // 点击“朕知道了”,传递给父组件信息
    toUpperLevel: function(e) {
      this.triggerEvent("clickzdl", "zzdl");
    },
    
    //通过bind:clickzdl="clickzdlClick"把子组件的clickzdl事件绑定在父组件的clickzdlClick事件上
    .wxml   
    <prompt-box bind:clickzdl="clickzdlClick"></prompt-box>
    
    .js
      // 点击“朕知道了”,接受子组件信息
      clickzdlClick: function(e) {
        var that = this;
        console.log("子组件给父组件传值");
        console.log(e);
        if (e.detail == "zzdl") {
          that.setData({
            promptBoxShow: false
          });
        }
      },
    

    2.父组件→子组件。

    .wxml  (要传给子组件的数据)
    <prompt-box propA="{{dataFieldA}}"></prompt-box>
    
    .js
    Page({
      data: {
        dataFieldA: "登陆异常,请联系管理员"
      },
    
    .js
    Component({
      data: {
        errMsg: "程序出现错误,请联系管理员"
      },
      properties: {
        propA: {
          type: String
        }
      },
      lifetimes: {
        attached: function() {
          var that = this;
          // console.log(that.properties);
          that.setData({
            errMsg: that.properties.propA
          });
        }
      }
    });
    

    六、验证码倒计时(定时器)

    .wxml
    <button class="QRcode">
        <text bindtap="gainCode" wx:if="{{codeShow}}">获取验证码</text>
        <text wx:if="{{!codeShow}}">{{timeDown}}s</text>
    </button>
    
    .js
     var that = this;
     let time = setInterval(function() {
        that.setData({
          codeShow: false,
          timeDown: that.data.timeDown - 1
        });
        if (that.timeDown == 0) {
           that.setData({
             codeShow: true,
             timeDown:60
           });
           clearInterval(time);
           console.log("清除");
        }
     }, 1000);
    

    七、下拉刷新,上拉加载

    官方文档:https://developers.weixin.qq.com/miniprogram/dev/reference/api/Page.html#onPullDownRefresh

    app.json
    {
      "usingComponents": {},
      "navigationBarTitleText": "我的订单",
      "enablePullDownRefresh": true,  //设置为true则默认开启下拉刷新功能
      "onReachBottomDistance": 10  //上拉加载的触发距离
    }
    
    1.下拉刷新

    onPullDownRefresh监听用户下拉刷新事件

      onPullDownRefresh: function() {
        wx.showNavigationBarLoading(); //在标题栏中显示加载(小菊花)
        //模拟加载 模拟网络加载所消耗的时间
        setTimeout(function() {
          wx.hideNavigationBarLoading(); //在标题栏中隐藏加载(小菊花)
          wx.stopPullDownRefresh(); //停止下拉刷新
        }, 1500);
      },
    
    2.上拉加载更多数据

    onReachBottom监听用户上拉触底事件
    在json文件中设置触发onReachBottom的触发距离onReachBottomDistance
    在触发距离内滑动期间,本事件只会被触发一次

      onReachBottom: function() {
        console.log("加载更多");
        let listConcat = [...that.data.list, ...res.data.data.content];
        that.setData({
            list: listConcat
        });
      },
    

    八、很重要的一点

    在微信小程序中,盒子模型box-sizing属性默认是content-box
    可以在每个标签后加上

    box-sizing: border-box;
    

    或者app.wxss加上 小程序所有组件初始化样式 box-sizing: border-box

    view,scroll-view,swiper,swiper-item,movable-area,movable-view,cover-view,cover-image,icon,text,rich-text,progress,button,checkbox-group,checkbox,form,input,label,picker,picker-view,radio-group,radio,slider,switch,textarea,navigator,functional-page-navigator,image,video,camera,live-player,live-pusher,map,canvas,open-data,web-view,ad{
        box-sizing: border-box;
    }
    

    九、小程序的栈!

    首先,先明确两点
    1.小程序的onLoad方法在页面的生命周期中,只执行一次。
    2.先执行onLoad,后执行onShow。

    前提:用户——>首页(A页面)——>上传页面(B页面)。栈的示意图
    前提.png
    第一种情况:进入上传页面(B页面)之后,使用redirectTo返回首页(C页面)。redirectTo会将栈顶出栈,新页面入栈,即B页面出栈,C页面进栈。(redirectTo会进行顶部栈的替换)
    redirectTo.png
    第二种情况:进入上传页面(B页面)之后,使用navigateTo返回首页(C页面)。navigateTo会将C页面添加到栈顶。
    navigateTo.png
    第三种情况:即不使用redirectTo,也不使用navigateTo,使用navigateBack返回至首页。在A页面onShow中打印栈的信息,只有miniHome(A页面)。

    实例参考:https://www.cnblogs.com/caicaizi/p/6652103.html

    var pagelist = getCurrentPages();
    var currPage = pagelist[pagelist.length - 1]; //当前页面
    var prevPage = pagelist[pagelist.length - 2]; //上一个页面
    prevPage.setData({
      statusOk: "直接给上一个页面中的字段赋值",
    });
    wx.navigateBack({
      delta: 1,
    });
    
    上一个页面在onShow中进行操作,因为页面改变,可以触发onShow
    
    跳转页面传参的话在onLoad
    

    十、微信小程序图片显示问题(IOS访问正常,安卓访问不显示)

    有以下几种可能:
    1.非本地图片:确定图片资源存在,copy图片url在浏览器打开,确定图片资源存在且能正常访问。
    2.本地图片:确定相对路径或者绝对路径正确。
    3.微信小程序图片路径,不可存在中文,使用英文做路径和文件名。
    4.文件后缀文小写且保持正确。
    5.网络图片,必须确保域名已经备案。
    注:排除以上5种通病之后,仍出现IOS访问正常,安卓访问不到图片的问题,大概率原因是图片做了CDN转发,多数CDN会默认开启防盗链,需要关闭CDN防盗链,因为防盗链会导致浏览器能显示,而客户端无法显示。
    本内容转自:https://www.cnblogs.com/sheep-sheep/p/9645797.html

    十一、Loading

        wx.showLoading({
          icon: "loading",
          title: "Loading",
          mask: true,
        });
        wx.hideLoading();
    
        wx.showToast({
           title: "刷新成功",
           icon: "success",
           duration: 1000,
        });
    
    下拉刷新时
        wx.showNavigationBarLoading(); //在标题栏中显示加载(小菊花)
        wx.hideNavigationBarLoading(); //在标题栏中隐藏加载(小菊花)
        wx.stopPullDownRefresh(); //停止下拉刷新
    

    十二、forEach

    1.逻辑尽量写在JS文件中
    2.多个三步运算符,要加()
    3.forEach循环中,element相当于item,可以直接点点使用,
    一个参数可以直接写,多个参数要加()

                that.data.list.forEach((element, index) => {
                  if (element.stopStatus == "ARRIVED") {
                    that.setData({
                      statusList: [index],
                      changeIndex: index,
                    });
                  }
                });
    

    十三、接口

    小程序可以调用本地接口
    1.拉下来后台代码,在前端的电脑上跑起来,然后localhost调接口。
    2.后台自己跑起来服务,用后台的ip地址调用接口。

    十四、报文

    请求报文:前端给后台传参。
    响应报文:后台给前端的返回值。

    十五、关于canvas

    1.滑动问题
    前提:设置canvas宽度大于当前可视屏幕宽度,但是却无法左右滑动。

    问题:设置class mask遮罩物,z-index 99 在开发者工具上可以正常滑动,但是在真机上无法滑动。

    原因:(1)canvas是原生组件,原生组件层级最高,其他组件无法通过z-index来覆盖原生组件。
    (2)原生组件脱离WebView渲染流程。但是在开发者工具上,原生组件是用web组件模拟的,不能完全还原真机效果。

    解决方法:使用cover-viewcover-image可以覆盖部分原生组件上面。(这两个是小程序提供的原生组件,专门用来解决原生组件层级问题的)

    原生组件的使用限制:https://developers.weixin.qq.com/miniprogram/dev/component/native-component.html

    相关文章

      网友评论

        本文标题:小程序随笔

        本文链接:https://www.haomeiwen.com/subject/btlboctx.html