微信小程序(wepy)

1.链接: blog.csdn.net/qq_26585943…

www.jianshu.com/p/0078507e1…

微信小程序开发(wepy框架)

布局: rpx 设计稿750px, 设计稿多大就写多大的

一、生命周期(app.js)

  • onLaunch 用户首次打开小程序,触发 onLaunch(全局只触发一次)这里做第三方开发平台自定义配置项 注意: ext.json也可以覆盖本地的配置项目,例如小程序跳转小程序就是在ext.json可以进行配置,手机扫码会进行读取ext.json进行覆盖本地的配置
  • wx.getExtConfigSync() 动态读取ext 字段自定义的数据字段

  • onLoad[(options)] 加载小程序,options参数拦截,模块只能触发一次,tabbar菜单, 页面模块进行切换不进行调用了, 页面是每次都会调用的

涉及到模块页面是否是是及时更新,如果及时更新放到onShow里面

  • onHide 进入后台,进程没有杀死
  • onError 错误监听函数 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
  • 顺序 onLuach => onLoad => onHide

页面生命周期(page.js):

  • onLoad --监听页面加载
  • onShow --监听页面显示
  • onReady --监听页面初次渲染完成
  • onHide --监听页面隐藏
  • onUnload ---监听页面卸载
    • 其中,打开小程序后会依次执行onLoad => onShow => onReady

    • 前后台切换会分别执行onHide和onShow方法,

    • 当小程序页面销毁时会执行 onUnload方法

     export default class index extends wepy.page {
      config = {};  //配置信息   
      components = {}; //組件配置
      data = {};  //页面数据
      methods = {};  //元素绑定事件区域
      events = {}; //子组件$emit给父组件发数据,触发父组件方法
      watch = {}; //监听数据变化
      //==> 生命周期
      onLoad(options) {
      // scene=decodeURIComponent(options.scene);  二维码参数
      // 一般参数  {}
     }
    onReady() {
      // Do something when page ready.
    }
    onShow() {
      // Do something when page show.
    }
    onHide() {
      // Do something when page hide.
    }
    onUnload() {
      // Do something when page close.
    }
    //下拉
    onPullDownRefresh() {
      // Do something when pull down.
    }
    //上拉
    onReachBottom() {
      // Do something when page reach bottom.
    }
    //分享
    onShareAppMessage() {
      // return custom share data when user share.
    },
    //页面滚动
    onPageScroll() {
      // Do something when page scroll
    }
    onResize() {
      // Do something when page resize
    }
    
    //==> 自定义方法
    getQuery(){
      ...  
    }
    createImage() {
      ....
    }
    
    
    复制代码

二、配置文件. 小程序配置config

app.wpy文件

  • pages: [] 页面,小程序所页面,必要的页面,
  • subPackages:[] 分包配置,将模块页面放入,上面就可以不用配置了

  • window:{} 所有页面配置
    1. backgroundTextStyle
    2. navigationBarBackgroundColor
    3. navigationBarTextStyle
    4. onReachBottomDistance: 240 //实现无感加
    5. navigationStyle:default/custom 微信小程序自定义顶部导航栏 ,顶部导航栏就会消失,保留右上角胶囊状的按钮
  • tabBar:[] 小程序下面切换配置,可以自己写
    1. 最多五个,最少2个,每次修改完要提交微信审核
  • navigateToMiniProgramAppIdList: [] 小程序跳转小程序配置, 目前最多10个
  • globalData全局数据 [类似于vuex redux 数据共享],一般外链文件
  • methods 全局方法 , 所有页面都可以共用的,一般外链文件

三、页面配置信息 conifig (重点)

app.json配置如果和页面配置冲突了,那么会采用页面配置的

  • navigationBarTitleText title
  • navigationBarTextStyle 字体颜色 ["white" /"blank"]
  • enablePullDownRefresh 是否下拉属性
  • disableScroll 是否可以滚动
  • disableSwipeBack 是否可以IOS左滑返回上一级,或着关闭小程序

四、一个wpy文件的组成

  • template模板,结构
  • script脚本
    1. data页面数据 this.xxx = xxx; 进行修改
    2. methods 页面方法 @绑定的 内置的方法
    3. events 是子组件传递的方法 $emit子元素传父元素事件 .sync props对象进行接收设置twoWay: true父元素下发的数据更新子元素跟着改变
    4. watchs 监听数据 数据发生改变进行处理

五、 微信授权登录流程

wepy登录流程: blog.csdn.net/weixin_4156…

<script>
import wepy from 'wepy'
import 'wepy-async-function'
import { setStore } from 'wepy-redux'
import configStore from './store'
const store = configStore()
setStore(store)
 
export default class extends wepy.app {
  config = {
    pages: [
      'pages/index',
      'pages/charts',
      'pages/test'
   
    ],
    window: {
      backgroundTextStyle: 'light',
      navigationBarBackgroundColor: '#fff',
      navigationBarTitleText: 'WeChat',
      navigationBarTextStyle: 'black'
    }
  }
 
  globalData = {
    userInfo: null,
    ret:null,
    config:null,
    apiUrl:'后台地址'
  }
 
  constructor () {
    super()
    this.use('requestfix')
    this.use('promisify')
  }
  onLaunch() {
    this.testAsync()
    this.init();
  }
  // 初始化获取config
  init(){
    wepy.request('初始化后台api').then(
      (ret)=>{
        this.globalData.config = ret.data.config;
        console.log('======初始化成功=======');
        //初始化成功判断是否授权
        this.checkSettingStatus();
      }
    )
  }
  //判断登录状态/是否授权
  async checkSettingStatus(){
    try {
      let auth = await wepy.getSetting();    //调用getSetting Api
      let authSetting = auth.authSetting;    //获取authSetting用来判断是否授权
      console.log('---开始判断---');    
      if(authSetting['scope.userInfo']){
          console.log('---已经授权---');
          //已经授权情况下直接获取userInfor
          let userInfo= await wepy.getUserInfo();    
          this.globalData.ret = userInfo;
          //调用登录
          this.login();
      }else{
        //如果没有授权跳转至授权页进行授权(新版只能通过调用按钮来调出授权框)
        //授权页面button需要赋予open-type='getUserInfo'属性
        //bindgetuserinfo='scope' bind方法用来授权/获取userInfor
        console.log('---用户未授权---');
        wepy.navigateTo({ url: './test' });
      }
      } catch (error) {
      console.log(error)
    }
  }
  //登录方法
 async login(){
   try {
    console.log('---调用login方法---')
    let token = wepy.getStorageSync('token') || '';    
    let {code:code} = await wepy.login();  //通过调用login获取code 判断是否开始登录
     if(code){
       console.log('---获取信息发送网络请求---');
       let ret = this.globalData.ret
       wepy.request({
         url: '', //开发者服务器接口地址",
         data: {
           code : code,
           rawData : ret.rawData,
           token:token
         },
          method:'POST',
          header:{
            'Content-Type':'application/x-www-form-urlencoded'
          }
       }).then((res)=>{
            console.log('---网络请求返回成功---')
           console.log(res)
           let response = res.data;
           if(response.code == 1){
             console.log('---登录正常,返回值1---');
             console.log(response);
             this.globalData.userInfo = response.data.userInfo;
             wepy.setStorageSync('token',response.data.userInfo.token);
             console.log(this.globalData.userInfo );
           }else{
             console.log('---登录异常---');
             wepy.setStorageSync('token','');
           }
       });
     }else{
       console.log('---login返回异常---')
     }
   } catch (error) {
    console.log(error) 
   }
    
  }
  sleep (s) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('promise resolved')
      }, s * 1000)
    })
  }
 
  async testAsync () {
    const data = await this.sleep(3)
    console.log(data)
  }
 
  getUserInfo(cb) {
    const that = this
    if (this.globalData.userInfo) {
      return this.globalData.userInfo
    }
  }
}
</script>
复制代码
=> 进入首页判断用户是否登录(是否有用户信息) => 没有登录 => 进入登录页面
1.第一步 进入首页检测
 HttpRequest.checkSessionAndLogin(this.$parent); //进行判断是否登录,是否登录过期

2. 第二步,进行判断
static async checkSessionAndLogin(app) {
    let that = this;
    if (app.globalData.userInfo) {
        let session = await wepy.checkSession(); //是否过期了,
        if (!session) {
            that.login(app);
        }
    } else {
        that.login(app);  //没有登录,去登录页面
    }
}

//3.登录授权
static async login(app) {
    let that = this;
    let res_login = await wepy.login(); //登录
    if (res_login.code) {   // code => 用户登录凭证(有效期五分钟)
        app.globalData.code = res_login.code;
        let res_setting = await wepy.getSetting();  //=> //调用getSetting Api 返回API对象
        if (res_setting.authSetting['scope.userInfo']) { ///获取authSetting用来判断是否授权
            that.getUserLoginInfo(app, res_login.code);
            return true;
        } else {   //没有授权, 进入登录页面
            wepy.navigateTo({
                url: 'login'
            });
            wepy.hideLoading();
        }
    }
}


//4. 已经授权, 取得用户信息进行存储
static async getUserLoginInfo(app, code) {
    let that = this;

    // 已经授权,可以直接调用getUserInfo获取头像昵称,不会弹框
    let res_userInfo = await wepy.getUserInfo();
    if (res_userInfo) {
        app.globalData.userInfo = res_userInfo.userInfo;
        let invite_app_user_id = app.globalData.invite_app_user_id; //首页进入URL参数放入数据池的
        let step_prize = app.globalData.step_prize; //步数邀请 //首页进入URL参数放入数据池的

        let punch_the_clock = app.globalData.punch_the_clock; //打卡邀请
        let query = {
            code: code,
            app_id: app.globalData.configInfo.appid,
            raw_data: res_userInfo.rawData,
            iv: res_userInfo.iv,
        };
        if (invite_app_user_id) {  //如果是空则不传
            query.invite_app_user_id = invite_app_user_id;
        }
        if (step_prize) { //步数邀请,该值为1
            query.step_prize = step_prize;
        }

        if (punch_the_clock) { //打卡邀请,该值为1
            query.punch_the_clock = punch_the_clock;
        }
        //调用后台接口
        that.request({
            query: query,
            url: app.globalData.basePath + '/auth',
            success: function (backData) {
                if (backData.data.status == "1") {
                    app.globalData.userInfo = backData.data.data;
                    // getUserLoginInfo是网络请求,可能会在Page.onLoad之后才返回,所以此处加入callback以防止这种情况
                    if (app.userInfoReadyCallback) {
                        app.userInfoReadyCallback(backData.data.data);
                    }
                    wepy.hideLoading();
                } else {
                    wepy.hideLoading();
                }
            }
        })
    }
}



微信授权button按鈕
 <button id="getUserInfo" open-type="getUserInfo"   hidden="true"  bindgetuserinfo="bindGetUserInfo"></button>
 
bindGetUserInfo(e) {
    //用户单击授权按钮确定,进行返回首页
    if (e.detail.errMsg == "getUserInfo:ok") {
        wepy.navigateBack();
    }
}

复制代码

六、项目问题总结:

  • 获取公共数据
    • 页面内采用: this.$parent ==> [ app = getApp() ]
    • 组件内部: this.parent.parent
  • 小程序跳转小程序配置 在app.json里面配置navigateToMiniProgramAppIdList:[]
  • 弹框出来阻止页面滑动,
  <view class="outer_chain_pop" @tap="hidePopModel" catchtouchmove='stopPageScroll'></view>
  stopPageScroll () {
      return false;
  },
复制代码
  • 弹框单击, 单击弹框区域外隐藏弹框,利用事件冒泡
 <view class="share_pop" @tap="hidePopModel" catchtouchmove='stopPageScroll'>
      <view class="share_pop_box {{shareObj.slideUp}}" @tap.stop='preventEvent'></view>
 </view>
 
 //单击弹框区域外, 弹框消失
 hidePopModel() {
      this.shareObj.isShowSharePop = false;
      this.isPageNoScroll = '';
      this.isShowCanvas = false;
      this.isShowChainPop = false;
  },
  //单击弹框,阻止事件
  preventEvent() {
      return false;
  },
复制代码
  • button按钮样式重置
  button {
      background: transparent !important;
  }
  button::after {
      border: none;
  }
复制代码
  • 微信修改了分享机制,导致开发者拿不到任何分享后的回调(成功、失败、完成)
  • 用 scroll-view 如果要横向滚动的话,除了要设置 scroll-x 属性,还要设置 white-space: nowrap; 的样式,子元素设置 display: inline-block
  • 如果你用了一个定时器,在退出页面的时候要记得清除,不然这个定时器还会一直执行
  • 小程序分享图片必须是5:4比例,如果不是,则进行补图, 首先用canvas画图,转为图片,这张图片进行分享图片
  • 回到顶部,安卓会有抖动的效果,动画时间直接设为0, IOS没事
  • IOS下拉会出现白色背景,盖一层,定位到上面,优化
  • IOS在模块内左滑会关闭小程序,在config对象设置disableSwipeBack:true 不关闭小程序
  • 生成专属图片分享,canvas生成图片进行分享
  • 邀请好友,分享一律query参数
  • 参数接受问题:
    • 跳转?后面的参数在onLoad里面用options接受,返回的是一个对象 eg:pages/pagesWpy/index?from='step' {}
    • 小程序二维码扫码跳转进来的,在onLoad里面使用var scene = decodeURIComponent(options.scene)获取,他返回的是一个字符串 ?后面的参数 "",在进行参数格式化返回一个的对象,进行处理

  • wx.navigateTo(导航切换) 和wx.switchTab(控制 tabBar 的切换)

  • 自定义底部导航和内置tabBar导航

  • 自定义组件

  • 解析 HTML 的三种方法(www.qinziheng.com/xiaochengxu…)

    • wxParse 解析富文本 插件处理,引用
    • rich-text 解析富文本 标准HTML都可以解析
    • web-view 解析富文本,公众号文章展示,显示网页内容,组件权限最高
    • juejin.im/post/5bb86a…
  • 使用微信开发者工具–>添加项目,项目目录请选择dist目录。

  • 微信开发者工具–>项目–>关闭ES6转ES5。 重要:漏掉此项会运行报错。

  • 微信开发者工具–>项目–>关闭上传代码时样式自动补全。 重要:某些情况下漏掉此项也会运行报错。

  • 微信开发者工具–>项目–>关闭代码压缩上传。 重要:开启后,会导致真机computed, props.sync 等等属性失效。(注:压缩功能可使用WePY提供的build指令代替,详见后文相关介绍以及Demo项目根目录中的wepy.config.js和package.json文件。)

  • WePY中的methods属性只能声明页面wxml标签的bind、catch事件,不能声明自定义方法

  • onload只会在页面加载时候执行,比如用navigateBack回到之前的页面的时候,之前那个页面不会再执行onload, 所以我们要触发某些函数的时候,我们可以放在onshow里面,即使是navigateBack回来也会执行

  • 同一个页面想要2个分享?

    • 需要在Page中添加onShareAppMessage方法,否则点右上角菜单不会出现转发选项 除了右上角菜单外,可以使用button组件的open-type="share" button组件和右上角的点点点都是调用onShareAppMessage方法 通过参数中的from字段区分事件来源是菜单menu还是按钮button(某需求要求两个分享不同) 通过onShareAppMessage方法返回的对象来定制转发界面显示的内容
  • 全屏蒙版弹窗遮不住tabBar?

    • tabBar的层级还是很高的,当出现全屏蒙版弹窗时,是无法盖住tabBar的, 可以调用微信的hidetabbar,不过需要注意兼容低版本 wx.hideTabBar({}) / wx.hideTabBar({})
  • canvas生成分享图

    • 创建canvas对象,画图,draw()花完,进行canvas转图片, 回调里面, wx.canvasToTempFilePath(options)

图解布局:

小程序优化

juejin.im/post/5b496d…

离开页面

进入页面

打开小程序

项目目录分配 src是源文件夹, dist是打包完的文件夹

HttpRequest.js封装
import wepy from 'wepy'
import globalData from '@/infrastructure/globalData/global' //公用数据
import dialog from '@/assert/utils/dialog';
const params = globalData.parapms; //接口公共参数
const basePath = globalData.basePath; //域名
class HttpRequest {
    static setPromise(url, method, options = {}, type) {
        if(type !=='md') { //其他接口
            options = Object.assign(options, params);
            url = (basePath + url);
        }
        return wepy.request({
            url ,
            method,
            dataType: 'json',
            data: options,
            header: {
                'content-type':'application/json'
            }
        });
    }

    //统一接口拦截,请求是否成功
    static validation(res) {
        return new Promise((resolve, reject) => {
            if (typeof res !=='undefined') {
                let code = res.data.status;
                if (code == 1) {
                    resolve(res.data);
                } else if(code == 0) {
                    //错误处理
                    let timer = null;
                    clearInterval(timer);
                    if(res.data.error=="活动已关闭,该页面已隐藏"){
                            reject(res.data);
                    }else{
                        wepy.showToast({
                            title: res.data.error,
                            icon: 'none',
                            duration: 2000
                        });
                        timer = setTimeout(() => {
                            dialog.hideLoading();
                            reject(res); //返回错误信息
                        }, 2000);
                    }
                   
                }
            }
        });
    }

    static get(url,  options = {}, type) {
        return HttpRequest.setPromise(url, "get",options,type);
    }

    static post(url, options = {}) {
        return HttpRequest.setPromise(url, "post", options);
    }

    static delete(url, options = {}) {
        return HttpRequest.setPromise(url, "delete", options);
    }

    static put(url, options = {}) {
        return HttpRequest.setPromise(url, "put",options);
    }
}
export default HttpRequest;
复制代码
七、常用方法封装
  1. 获取URL参数
 function getQuery(key, url) {
    url = url || window.location.href + '';
    if (url.indexOf('#') !== -1)
        url = url.substring(0, url.indexOf('#'));
    let rts = [],
        rt;
    let queryReg = new RegExp('(^|\\?|&)' + key + '=([^&]*)(?=&|#|$)', 'g');
    while ((rt = queryReg.exec(url)) != null) {
        rts.push(decodeURIComponent(rt[2]));
    }
    if (rts.length == 0) return null;
    if (rts.length == 1) return rts[0];
    return rts;
}
复制代码

2.保存图片到手机

```
  <block wx:if="{{shareObj.scopeFlag}}">
    <view class="" @tap.stop="saveImg" @tap.stop='preventEvent'>
      <button class="canvas_image_btn_save" @tap.stop='handleSetting1'>去授权</button>
    </view>
  </block>

  <block wx:if="{{shareObj.settingFlag}}">
    <button class="canvas_image_btn_save"  open-type="openSetting" bindopensetting='handleSetting'>去设置</button>
  </block>

//保存图片,判断是否授权,没有授权则进入授权页面进行授权
function checkoutSaveImg() {
  wx.getSetting({
    success: res => {
      //进行去授权
      if (!res.authSetting['scope.writePhotosAlbum']) {
        if(this.shareObj.scope) {  //授权完毕了, 包括失败和成功
          this.shareObj.scopeFlag = false;
          this.shareObj.settingFlag = true;
        } else {
          this.shareObj.scopeFlag = true;
          this.shareObj.settingFlag = false;
        }
        this.shareObj.saveImgSettingFlag = false;

        this.$apply();
      } else {  //授权完毕,进入设置页面进行设置
        this.shareObj.saveImgSettingFlag = true;
        this.shareObj.settingFlag = false;
        this.shareObj.scopeFlag = false;
        this.isShowCanvas = true;
        this.$apply();
      }
    }
  });
}

//调取授权弹框进行授权
function handleSetting1(e) {
    //判断是否开启授权
    wx.getSetting({
      success: res => {
        //进行去授权
        if (!res.authSetting['scope.writePhotosAlbum']) {
          wx.authorize({
            scope: 'scope.writePhotosAlbum',
            success: () => {
              this.shareObj.saveImgSettingFlag = true;
              this.shareObj.scopeFlag = false;
              this.shareObj.settingFlag = false;
              this.isShowCanvas = true;
              this.shareObj.scope = true;
              this.$apply();
            },
            fail: () => {
              debugger
              this.shareObj.scope = true;
              this.shareObj.settingFlag = true;
              this.shareObj.saveImgSettingFlag = false;
              this.shareObj.scopeFlag = false;
              this.$apply();
            }
          });
        } else {  //授权完毕,进入设置页面进行设置
          if (!e.detail.authSetting['scope.writePhotosAlbum']) {
            Tips.alert('不授权无法保存', 2000);
            this.shareObj.saveImgSettingFlag = false;
            this.shareObj.settingFlag = true;
            this.shareObj.scopeFlag = false;
            this.isShowCanvas = true;
          } else {
            this.shareObj.saveImgSettingFlag = true;
            this.shareObj.settingFlag = false;
            this.shareObj.scopeFlag = false;
            this.isShowCanvas = true;
          }
          this.$apply();
        }
      }
    });
  },
```
复制代码

3.分享图片

//邀请注册,和页面默认转发功能,进入首页
function setShare(options) {
    options = options || {};
    let imageUrl = options.imageUrl || 'https://xiaomengtong.oss-cn-beijing.aliyuncs.com/statics/xiaomengtong-small-program/share_img_one.png'; //默认当前页面截取
    let title = options.title || '阅读新体验,活动玩不停';
    let path = options.path || '/pages/pagesWpy/index'; //默认回到首页
    return {
        title,
        imageUrl,
        path,
    }
}
复制代码

4.随机生成字符串

function getRandomString() {
    let str = "",
        range = 30,
        arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];

    // 随机产生
    for (let i = 0; i < range; i++) {
        str += arr[Math.round(Math.random() * (arr.length - 1))];
    }
    return str;
},
复制代码
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值