微信小程序记录与项目实践

44 篇文章 0 订阅
43 篇文章 0 订阅

wx.opensetting废弃之后的二次授权(可以通过button也可以通过modal的方式,很多人说不可以用showModal但本人亲测可用,版本为2.8.3)

   wx.showModal({
        title: '提示',
        content: '这是一个模态弹窗',
        success(res) {
          if (res.confirm) {
            console.log('用户点击确定')
            wx.openSetting({
              success(res) { console.log(res) },
              fail(res) { console.log(res) },
            })
          }
        }
      })
点击确定即可进入权限设置页面      

如果直接使用wx.openSetting会报错:VM1015:1 openSetting:fail can only be invoked by user TAP gesture.

自定义弹窗防止底层触摸

/****弹窗****/
<view catchtouchmove='true'>
    ...
</view>

监听左上角返回键 

 onUnload: function () {
    wx.reLaunch({
      url: '../logs/logs'
    })

拨打电话

wx.makePhoneCall({
      phoneNumber: '123456789' // 仅为示例,并非真实的电话号码
 })

客服(小程序后台可以绑定客服人员)

<button open-type="contact" bindcontact="handleContact">客服</button>

置顶

wx.pageScrollTo({
      scrollTop: 0
    })

动画

let that = this
var animation = wx.createAnimation({
      // 动画持续时间
      duration: 500,
      // 定义动画效果,当前是匀速
      timingFunction: 'linear'
    })
    // 将该变量赋值给当前动画
    that.animation = animation
    // 先在y轴偏移,然后用step()完成一个动画
    animation.translateY(1000).step()
    // 用setData改变当前动画
    that.setData({
      // 通过export()方法导出数据
      animationData: animation.export(),
      chooseSize: true
    })

地址三级联动

wxml
<view style='height:84rpx;background:#fff;border-bottom:1px solid #D9D9D9;line-height:84rpx;'>
        <view class="section__title" style='display:inline-block;line-height:85rpx;color:rgba(0,0,0,1);font-size:33rpx;float:left;'>选择地址</view>
        <picker mode="region" bindchange="bindRegionChange" value="{{detailed}}" custom-item="{{customItem}}"
      name="detailed" style='display:inline-block;font-size:33rpx;color:#C7C7CC;width:71%;margin-left:36rpx;height:75rpx;letter-spacing:2rpx;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}' >
          <view class="picker {{clas}}" >{{detailed}}</view>
        </picker>
      </view>
js

Page({
  data: {
    customItem: [],
    detailed: '请选择',
  },
  //省市联动
  bindRegionChange: function (e) {
    var that = this
    //为了让选择框有个默认值,    
    that.setData({
      clas: ''
    })   //下拉框所选择的值
    console.log('picker发送选择改变,携带值为', e.detail.value)
    this.setData({
      //拼的字符串传后台
      detailed: e.detail.value[0] + " " + e.detail.value[1] + " " + e.detail.value[2],
      //下拉框选中的值
      region: e.detail.value
    })

    this.setData({
      "AddSite.area": e.detail.value[0] + " " + e.detail.value[1] + " " + e.detail.value[2]
    })
    console.log(this.data.AddSite)
  },
})

 

小程序强制更新

在app.js的onLaunch方法中使用:

const updateManager = wx.getUpdateManager()
 
updateManager.onCheckForUpdate(function (res) {
    // 请求完新版本信息的回调
    console.log(res.hasUpdate)
})
 
updateManager.onUpdateReady(function () {
    wx.showModal({
        title: '更新提示',
        content: '新版本已经准备好,是否重启应用?',
        success: function (res) {
            if (res.confirm) {
                // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
                updateManager.applyUpdate()
            }
        }
    })
})
 
updateManager.onUpdateFailed(function () {
    // 新的版本下载失败
    wx.showModal({
        title: '更新提示',
        content: '新版本下载失败',
        showCancel:false
    })
})

轮播图

<swiper indicator-dots="true" autoplay="true" interval="5000" duration="1000" style='width: 100%'>
  <swiper-item wx:for="{{imgUrls}}" wx:for-item="imgItem">
    <image src='{{imgItem}}' class="slide-image" width="355" height="150" />
  </swiper-item>
</swiper>

下拉刷新

app.json

"window": {
  "enablePullDownRefresh": true
}
onPullDownRefresh: function () {
  wx.stopPullDownRefresh()
}

自定义属性

<view class='zright' bindtap='choseCoupon' data-info='{{item}}'  data-id='{{index}}'>

choseCoupon: function (e) {
    console.log(e.currentTarget.dataset.id)
    console.log(e.currentTarget.dataset.info)
}


bindtap和catchtap 以及 .currentTarget和.target

bindtap事件属于冒泡事件 
当事件没有冒泡行为时,e.target是tap点击事件触发的对象(也就是点击的是谁,e.currentTarget是事件绑定在哪个元素上(也就是这个事件在哪个组件上)。
e.targe可以理解是最里面的view   e.currentTarget是view的父元素 即被冒泡的父元素
catchtap阻止事件冒泡 
当事件没有冒泡行为时,e.target与e.currentTarget都指向事件触发的对象。
target:事件源组件对象(事件触发的对象)  currentTarget:当前组件对象(事件触发被冒泡的对象)
冒泡事件有:touchstart   touchmove   touchend  longtap   tap这五个事件,其余的事件为非冒泡事件。 
总结:
currentTarget可能会等于target,但是target不一定会等于currentTarget,看事件类型 即非冒泡相等 冒泡不相等 currentTarget是父元素 target是事件触发的对象
冒泡:事件从里层到外层

小程序和vue的语法区别 

数据绑定
小程序(不加括号,为被认为是字符串)
<image src="{{imgSrc}}"></image>
vue
<img :src="imgSrc"/>

循环渲染
小程序
<text wx:for="{{items}}">{{item}}</text>
vue
<li v-for="item in items">
    {{ item.message }}
</li>

显示隐藏
小程序中,使用wx-if和hidden控制元素的显示和隐藏
vue中,使用v-if 和v-show控制元素的显示和隐藏

事件处理
小程序中,全用bindtap(bind+event),或者catchtap(catch+event)绑定事件
vue:使用v-on:event绑定事件,或者使用@event绑定事件

绑定事件传参
vue可以直接传参 例如 @click="say('明天不上班')"
小程序不可以直接传参数 通过e.currentTarget.dataset.*的方式获取


双向绑定
小程序的表单没有v-model
使用this.setData({key:value})代替v-model


页面生命周期

 onLoad  onReady  onShow onHide   onUnload 卸载 onPullDownRefresh 下拉  onReachBottom 上拉

组件

子组件
生命周期
created 组件实例化,但节点树还未导入,因此这时不能用setData
attached 节点树完成,可以用setData渲染节点,但无法操作节点
ready 组件布局完成,这时可以获取节点信息,也可以操作节点
moved 组件实例被移动到树的另一个位置
detached 组件实例从节点树中移除


在子组件的json文件中,将该文件声明为组件
{
  "component": true
}
在需要引入的父组件的json文件中,在usingComponents填写引入组件的组件名以及路径

"usingComponents": {
    "tab-bar": "../../components/tabBar/tabBar"
  }

父组件引入
<tab-bar currentpage="index"></tab-bar>

父子通信
在子组件properties中,接收传递的值

properties: {
    currentpage: { 
      type: String, // 类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
      value: 'index'  
    }
  }

子父通信

子组件
 var myEventDetail = "我是子组件通信父组件的"
 this.triggerEvent('myevent', myEventDetail) //myevent自定义名称事件,父组件中使用
父组件
<bar bind:myevent="toggleToast" ref="bar"></bar>
// 获取子组件信息
toggleToast(e){
    console.log(e.detail)
}

通过id或者class调用子组件的方法
this.selectComponent('#id').syaHello()
//vue是使用ref名调用 this.$ref.bar.子组件的方法

 

通信

缓存方式
a页面:wx.setStorageSync("data","b页面的数据")
b页面:console.log(wx.getStorageSync("data")) //"b页面的数据"

getCurrentPages() 方式
getCurrentPages() 获取当前页面栈。数组中第一个元素为首页,最后一个元素为当前页面。
使用:
  let pages = getCurrentPages();
    let curPage = pages[pages.length - 1];//现在页面
    let beforePage = pages[pages.length - 2];//上一个页面
    console.log(curPage)
    beforePage.setData({ text: "我是上个页面修改的" })
注意事项
不要在 App.onLaunch 的时候调用 getCurrentPages,此时 page 还没有生成。
页面A必须使用 wx.navigateTo() 跳转到下一页面B,不能使用wx.redirectTo等其它的跳转方式,这样会关闭上一个页面,导致页面B无法获取上一页的Page实例
getCurrentPages无法实现tab页面之间的通信 原因也很简单 getCurrentPages是页面栈 tab之间是switchTab路由通信的 不存在页面栈

url传递通信

events.js
/**
 * 使用方式:
 * 1、接收方js代码中
 *  1.1 引入该类,如:let flashEvent = require('你的路径/utils/FlashEvent.js');
 *  1.2 注册FlashEvent,如:在onLoad中
 *    flashEvent.register(flashEvent.EVENT_KEYS.FIRST_EVENT, this, function (data) {
 *       this.setData({
 *         eventCallBack: data
 *       })
 *    })
 *  1.3 注销FlashEvent,如:在onUnload中调用 flashEvent.unregister(flashEvent.EVENT_KEYS.FIRST_EVENT, this);
 * 2、发送方js代码中
 *  2.1 引入该类,如:let flashEvent = require('你的路径/utils/FlashEvent.js');
 *  2.2 发送事件,如:flashEvent.post(flashEvent.EVENT_KEYS.FIRST_EVENT, '发送的数据');
 */
// 事件定义 方便维护管理 - 新事件添加到此处
const EVENT_KEYS = {
  FIRST_EVENT: "FIRST_EVENT"
}

// 存储组合后的事件
var eventData = {};
/**
 * register 注册事件:再Page
 * key 事件名
 * context 上下文-当前page的this
 * callback 事件回调
 */
function register(key, context, callback) {
  var eventInfo = [context, callback];
  var callbacks = eventData[key];
  if (Array.isArray(callbacks)) {
    callbacks.push(eventInfo);
  } else {
    eventData[key] = [eventInfo];
  }
}
/**
 * unregister 注销事件
 * key 事件名
 * context 上下文-当前page的this
 */
function unregister(key, context) {
  var callbacks = eventData[key];
  if (Array.isArray(callbacks)) {
    eventData[key] = callbacks.filter((eventInfo) => {
      return eventInfo[0] != context;
    })
  }
}
/**
 * post 发送事件
 * key 事件名
 * data 传递的数据
 */
function post(key, data) {
  var callbacks = eventData[key];

  if (Array.isArray(callbacks)) {
    callbacks.map((eventInfo) => {
      var context = eventInfo[0];
      var callback = eventInfo[1];
      callback.call(context, data);
    })
  }
}
// 导出代码
module.exports = {
  EVENT_KEYS: EVENT_KEYS,
  register: register,
  unregister: unregister,
  post: post
}



//使用
a页面
let flashEvent = require('./../../utils/events.js');
flashEvent.register(flashEvent.EVENT_KEYS.FIRST_EVENT, this, function (data) {
      console.log(data)  //监听数据 打印出:发送的数据
    })

b页面
 let flashEvent = require('./../../utils/events.js');
 flashEvent.post(flashEvent.EVENT_KEYS.FIRST_EVENT, '发送的数据');
  // 注销FlashEvent,如:在onUnload中调用 
 //flashEvent.unregist(flashEvent.EVENT_KEYS.FIRST_EVENT, this);



//store.js
/**
 * @author xiaoheng
 * @time 2019/8/1
 * @github https://github.com/xiaoheng21
 * @tip 还在找工作,有机会望告知,坐标北京
 */
/**
 * 状态管理类
 * @constructor 构造函数
 * @_data  内部数据,用来保存页面数据
 * @addData 添加页面数据的方法
 * @removeData 移除不需要的页面数据,减小内存压力
 */
class Store {
  constructor() {
    this._data = {};
  }

  /**
   * 向数据池里添加数据
   * @param { Object<this> } context 保存当前页面的执行上下文,也就是当前页面的 this
   * @param { String } name 当前页面数据的名字,用于在别的页面读取数据,默认值为当前页面的路径
   */
  addData(context, name) {
    // 如果传了 name 就用传过来的,如果未传就用页面路径
    let routeName = name ? name : context.route;
    //设置代理,用于简化操作
    let proxyContext = new Proxy(context, {
      // 获取数据,如果数据在外层,返回外层数据
      get: function (context, property) {
        if (property in context) {
          return context[property];
        } else {
          // 如果外层找不到数据, 就在 "this.data" 里找,若有,返回数据
          if (property in context.data) {
            return context.data[property];
          } else {
            //若没有,报错
            console.error(`${name}页面没有此属性`);
          }
        }
      },
      // 改变数据, 封装 "this.setData", 简化操作
      set: function (context, property, value) {
        context.setData({
          [property]: value
        });
        return true;
      },
      // 判断数据是否存在
      has: function (context, property) {
        return property in context.data;
      }
    });
    // 将代理对象添加进数据池
    this._data[routeName] = proxyContext;
  }

  /**
   * 从数据池里移除页面数据
   * @param { String } name 需要移除的页面的名字
   */
  removeData(name) {
    if (name in this._data) {
      delete this._data[name];
    } else {
      console.error(`希望删除的属性不存在`);
    }
  }
}

// 创建单例对象,全局共享一个数据池
const store = new Store();

// 创建代理, 私有化 _data, 简化用户操作, 提高安全性
let proxyStore = new Proxy(store, {
  // 若访问的属性为 add remove 函数, 直接返回函数
  get: function (store, property) {
    if (property in store) {
      return store[property];
    } else {
      // 若访问的数据为页面数据, 则返回页面代理对象
      if (property in store._data) {
        return store._data[property];
      } else {
        // 若没有页面信息, 报错
        console.error("访问的页面数据未载入数据池");
      }
    }
  }
});

export default proxyStore;

使用:
import store from "./../utils/store.js"

添加页面数据
store.addData( context, name )
参数说明:
context
执行上下文,也就是当前页面的 this
name
命名当前页面,也就是在别的页面取值的时候 store.name.属性,默认值为当前页面的路径


移除页面数据
store.removeData( name )
参数说明
name
希望删除的页面数据的名字


获取数据
let value = store.页面name.属性
这样既可获取数据,后台是用代理封装了数据池,从而方便用户使用


修改数据
store.页面name.属性 = value
这样赋值即可,后台使用的依然是封装的 setData


检测属性是否存在
property in store.页面name

微信授权失败处理(有关授权的代码一般放在onShow生命周期里面)

方案一
wx.getSetting({
          success: function (res) {
            var statu = res.authSetting;
            if (!statu['scope.userLocation']) {
//没有权限直接跳转权限设置页
              wx.navigateTo({
                url: './../setSetting/setSetting',
              })
//提示用户没有权限直接跳转权限设置页
              // wx.showModal({
              //   title: '是否授权当前位置',
              //   content: '需要获取您的地理位置,请确认授权,否则地图功能将无法使用',
              //   success: function (tip) {
              //     console.log(tip)
              //     if (tip.confirm == true) {
              //       wx.navigateTo({
              //         url: './../setSetting/setSetting',
              //       })
              //     }
              //   }
              // })
            }
setSetting.wxml
<button type='primary' open-type="openSetting">  授权登录 </button>

方案二
可以把授权按钮封装成弹窗组件形式(太长不贴代码了)

小程序登录 (就是通过login得到临时登录code去服务端后台请求得到openid和session_key和用户信息)

wxml
<button open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">点击授权</button>
js
bindGetUserInfo(res) {
    let info = res;
    console.log(info);
    if (info.detail.userInfo) {
      console.log("点击了同意授权");
      wx.login({
        success: function (res) {
          if (res.code) {
            wx.request({
              url: 'http://www.test.com/test',//服务端接口
              data: {
                code: res.code,
                nickName: info.detail.userInfo.nickName,
                avatarUrl: info.detail.userInfo.avatarUrl
              },
              header: {
                'content-type': 'application/json' // 默认值
              },
              success: function (res) {
                  var userinfo = {};
                  userinfo['id']=res.data.id;
                  userinfo['nickName'] = info.detail.userInfo.nickName;
                  wx.setStorageSync('userinfo', userinfo);                    
              }
            })
          } else {
            console.log("授权失败");
          }
        },
      })
 
    } else {
      console.log("点击了拒绝授权");
    }
  }

小程序使用菜单

  wx.showActionSheet({
      itemList: ['从手机相册选择', '拍照'],
      success: function (res) {
        console.log(res.tapIndex)
      },
      fail: function (res) {
        console.log(res.errMsg)
      }
    })

 

微信使用相册选择图片

         
 wx.chooseImage({
      count: 1, // 默认9
      sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
      sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
      success: function (res) {
        // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
        var tempFilePaths = res.tempFilePaths
        console.log(tempFilePaths)
        that.setData({
          src: tempFilePaths,
        })
      }
    })
//实例 
//js
  /** 选择图片Banner */
  chooseBanner: function () {
    var that = this;
    if (this.data.banner.length < 3) {
      wx.chooseImage({
        count: 2, //最多选择1张图片- that.data.banner.length,
        sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
        sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
        success: function (res) {
          // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
          console.log(res.tempFilePaths);
          if (res.tempFilePaths.count == 0) {
            return;
          }
          //上传图片
          var imgArrNow = that.data.banner;
          imgArrNow = imgArrNow.concat(res.tempFilePaths);
          that.setData({
            banner: imgArrNow
          })
          that.chooseViewShowBanner();
        }
      })
    } else {
      wx.showToast({
        title: '限制选择6个文件',
        icon: 'loading',
        duration: 1000
      })
    }
  },

  /** 删除图片Banner */
  deleteImvBanner: function (e) {
    var banner = this.data.banner;
    var itemIndex = e.currentTarget.dataset.id;
    banner.splice(itemIndex, 1);
    this.setData({
      banner: banner
    })
    //判断是否隐藏选择图片
    this.chooseViewShowBanner();
  },


  /** 是否隐藏图片选择Banner*/
  chooseViewShowBanner: function () {
    if (this.data.banner.length >= 3) {
      this.setData({
        chooseViewShowBanner: false
      })
    } else {
      this.setData({
        chooseViewShowBanner: true
      })
    }
  },

  /** 查看大图Banner */
  showImageBanner: function (e) {
    var banner = this.data.banner;
    var itemIndex = e.currentTarget.dataset.id;
    console.log("itemIndex:" + JSON.stringify(e))
    wx.previewImage({
      current: banner[itemIndex], // 当前显示图片的http链接
      urls: banner // 需要预览的图片http链接列表
    })
  }
//wxml
<view class="addImv">
      <!--这个是已经选好的图片-->
      <view wx:for="{{banner}}" wx:key="key" class="upFile" bindtap="showImageBanner" style="border-radius: 5px" data-id="{{index}}">
        <image class="itemImv" src="{{item}}"></image>
        <view class="closeImv" catchtap="deleteImvBanner" data-id="{{index}}">+</view>
        <!-- <image src="../../resources/images/delect.png" mode="scaleToFill" ></image> -->
      </view>
 
      <!--这个是选择图片-->
      <view class="chooseView" bindtap="chooseBanner" wx:if="{{chooseViewShowBanner}}" style="border-radius: 5px" >
        <!-- <image class="chooseImv" src="../../resources/images/add.png"></image>
         -->
         + 
      </view>
    </view>
//wxss

.container {
    background-color: #F2f2f2;
}

.swiper_box {
    width: 100%;
}

swiper-item image {
    width: 100%;
    display: inline-block;
    overflow: hidden;
}

view.text {
    display: flex;
    align-items: center;
    position: relative;
    padding: 10px 10px 10px 12px;
    font-size: 15px;
    color: #656565;
}

view.text:before {
    position: absolute;
    display: block;
    content: ' ';
    left: -5px;
    width: 2px;
    height: 100%;
    background-color: #09bb07;
}

.line_flag {
    width: 3px;
    height: 100%;
    height: 15px;
    display: inline-block;
    background-color: #f9f027;
}

view.text text {
    margin-left: 10px;
    line-height: 18px;
    font-weight: bold;
}

.venues_box {
    padding: 0 10rpx;
}

.venues_item {
    display: inline-block;
    width: 49%;
    margin: 0 0.5%;
}

.venues_item image{
    width: 100%;
    height: 90px;
}

.choice_box {
    padding: 0 10rpx;
}
.choice_box .choice_list .choice_item{
    margin-bottom: 15px;
}
.choice_box .choice_list image {
    width: 100%;
    height: 200px;
}

.choice_box .choice_list .title {
    font-size: 12px;
    font-weight: bold;
    text-align: center;
    color: #333;
}

.addImv {
  /* background-color: white; */
  border: 1px dashed gray;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 5rpx;
  /* width: 50rpx;
  height: 50rpx; */
}
 
.upImv {
  background-color: white;
  width: 100%;
  margin-top: 5rpx;
}
 
.upImv_text {
  font-size: 30rpx;
  margin-left: 20rpx;
  padding-top: 20rpx;
}
 
/*添加图片*/
 .addImv{
   padding: 20rpx
 }
.addImv .chooseView {
  width: 180rpx;
  height: 180rpx;
  /* margin: 20rpx 20rpx; */
  background-color: #f2f6f9;
  border: 1px dashed lightgray;
  text-align: center;
  line-height: 180rpx;
  /* padding: 0rpx 7rpx; */
  border-radius: 5px;
  margin-left: 40rpx;
}
 
.addImv .chooseImv {
  width: 50rpx;
  height: 50rpx;
}
 
/*已选择的图片*/
 
.addImv .upFile {
  width: 180rpx;
  height: 180rpx;
  position: relative;
  /* padding: 0rpx 7rpx; */
  margin-left: 40rpx;
  border: 1px solid #c0ccda;
}
 
.addImv .upFile .itemImv {
  width: 180rpx;
  height: 180rpx;
  /* padding: 0rpx 7rpx; */
}
 
.addImv .upFile .closeImv {
  position: absolute;
  right: 0rpx;
  top: 0rpx;
  width: 25rpx;
  height: 25rpx;
  transform:rotate(45deg);
  color: red;

}

微信地图api 

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

wxml

<!--index.wxml-->
<view class='view'>
  <map longitude="{{longitude}}" latitude="{{latitude}}" markers="{{markers}}" covers="{{covers}}" show-location>
    <cover-view>
    经度:{{longitude}}
    </cover-view>
     <cover-view>
    纬度:{{latitude}}
    </cover-view>
    <cover-view>
    速度:{{speed}}
    </cover-view>
    <cover-view>
    精度:{{accuracy}}
    </cover-view>
  </map>
</view>

js

const app = getApp()
Page({
  data: {
    longitude: 116.4965075,
    latitude: 40.006103,
    speed: 0,
    accuracy: 0,
    markers: [
      {
        id: 0,
        latitude: 22.26606,
        longitude: 113.54302,
        // alpha:0,
        callout: {
          content: " text \n 12000元/㎡",
          padding: 5,
          display: 'ALWAYS',
          textAlign: 'center',
          // borderRadius: 5,
          // borderColor:'#ff0000',
          // borderWidth: 2,
        }
      },
      {
        id:1,
        latitude: 22.26666,
        longitude: 113.54342,
        callout: {
          content: " text123 \n 12000元/㎡",
          padding: 5,
          display: 'ALWAYS',
          textAlign: 'center',
        }
      }]
  },
  //事件处理函数
  bindViewTap: function () {

  },
  onShow: function () {
    var that = this
    wx.showLoading({
      title: "定位中",
      mask: true
    })
    wx.getLocation({
      type: 'gcj02',
      altitude: true,//高精度定位
      //定位成功,更新定位结果
      success: function (res) {
        var latitude = res.latitude
        var longitude = res.longitude
        var speed = res.speed
        var accuracy = res.accuracy

        that.setData({
          longitude: longitude,
          latitude: latitude,
          speed: speed,
          accuracy: accuracy
        })
        console.log(res)
      },
      //定位失败回调
      fail: function () {
        wx.showToast({
          title: "定位失败",
          icon: "none"
        })
        wx.getSetting({
          success: function (res) {
            var statu = res.authSetting;
            if (!statu['scope.userLocation']) {
              //也可以检测到没有权限直接跳转授权也
             //  wx.navigateTo({
                //      url: './../setSetting/setSetting',
                    })//
              wx.showModal({
                title: '是否授权当前位置',
                content: '需要获取您的地理位置,请确认授权,否则地图功能将无法使用',
                success: function (tip) {
                  console.log(tip)
                  if (tip.confirm == true) {
                    wx.navigateTo({
                      url: './../setSetting/setSetting',
                    })
                  }
                }
              })
            }
          },
          fail: function (res) {
            console.log(res)
            wx.showToast({
              title: '调用授权窗口失败',
              icon: 'success',
              duration: 1000
            })
          }
        })
    

      

      },

      complete: function () {
        //隐藏定位中信息进度
        wx.hideLoading()
        console.log("定位失败")
      }

    })
  },
})

wxss
.view {
  width: 100%;
  height: 100vh;
}
 
map {
  width: 100%;
  height: 100%;
}
//授权失败引导跳转
setSetting.wxml
<button type='primary' open-type="openSetting">  授权登录 </button>

打开地图和选择位置 

 wx.openLocation({
          latitude: latitude,
          longitude: longitude,
          scale: 18,
          success: function (res) {
            console.log(res)
          },
          fail: function (res) {
            console.log(res)
          },
          complete:function(res){
            console.log(res)
          }
        })
       
   wx.chooseLocation({
          success: function(res) {
            console.log(res)
          },
           fail: function (res) {
            console.log(res)
          },
          complete: function (res) {
            console.log(res)
          }
        })

支付(支付其实不难 大多是服务端实现)

小程序调用登录接口获取code,传递给商户服务器用来获取用户的openID
通过openID和订单信息 请求服务端接口得到wx.requestPayment需要的五个参数信息调起支付

wx.requestPayment({
   "timeStamp": "",
   "nonceStr": "",
   "package": "",
   "signType": "MD5",
   "paySign": "",
   "success":function(res){
   },
   "fail":function(res){
   }
})

请求接口封装

until.js
// 网络请求
const request = function(url, method, data, msg, succ, fail, com) {
  // 小程序顶部显示Loading
  wx.showNavigationBarLoading();
  if (msg != "") {
    wx.showLoading({
      title: msg
    })
  }
  wx.request({
    url: url,
    data: data,
    header: {
      'content-type': 'application/x-www-form-urlencoded'
   
    },
    method: method,
    success: res => {
      if (succ) succ(res);
    },
    fail: err => {
      if (fail) fail(err);
    },
    complete: com => {
      wx.hideNavigationBarLoading();
      if (msg != "") {
        wx.hideLoading();
      }
      console.log(url + ' 返回的data:', com.data);
    }
  })
}
module.exports = request;

//
var util = require("../../utils/util.js")

let that = this
 util.request('test.php', 'get', { id: 1 } , '正在加载数据', res=> {
    	that.setData({
            list_data:res.data
        })
    },err=> {
      wx.showToast({
        title: '加载数据失败',
        icon:"none"
      })
    })

wx.authorize(用户拒绝短期间内不会再弹起授权请求,通过openSetting的方式)

// 可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.record" 这个 scope
wx.getSetting({
  success(res) {
    if (!res.authSetting['scope.record']) {
      wx.authorize({
        scope: 'scope.record',
        success () {
          // 用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问
          wx.startRecord()
        }
      })
    }
  }
})


wx.authorize是授权用的
wx.getSetting是判断是否已经授权用的
wx.openSetting是打开授权列表用的

wx.getSetting 回调结果例如 res['scope.userLocation'] 没授权为null  授权了是true

boolean scope.userInfo
是否授权用户信息,对应接口 wx.getUserInfo

boolean scope.userLocation
是否授权地理位置,对应接口 wx.getLocation, wx.chooseLocation

boolean scope.address
是否授权通讯地址,对应接口 wx.chooseAddress

boolean scope.invoiceTitle
是否授权发票抬头,对应接口 wx.chooseInvoiceTitle

boolean scope.invoice
是否授权获取发票,对应接口 wx.chooseInvoice

boolean scope.werun
是否授权微信运动步数,对应接口 wx.getWeRunData

boolean scope.record
是否授权录音功能,对应接口 wx.startRecord

boolean scope.writePhotosAlbum
是否授权保存到相册 wx.saveImageToPhotosAlbum, wx.saveVideoToPhotosAlbum

boolean scope.camera
是否授权摄像头,对应<camera /> 组件

保存图片


wx.downloadFile({
  url: 'https://example.com/123',     //仅为示例,并非真实的资源
  success: function (res) {
    // 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下载到了想要的内容
    if (res.statusCode === 200) {
      wx.saveImageToPhotosAlbum({
        filePath: res.tempFilePath,
        success(res) {
          wx.showToast({
            title: '保存图片成功!',
          })
        },
        fail(res) {
          wx.showToast({
            title: '保存图片失败!',
          })
        }
      })
    }
  }
})

wx.createSelectorQuery()

demo01
const query = wx.createSelectorQuery()
query.select('#the-id').boundingClientRect()
query.selectViewport().scrollOffset()
query.exec(function(res){
  res[0].top       // #the-id节点的上边界坐标
  res[1].scrollTop // 显示区域的竖直滚动位置
})



demo02
wx.createSelectorQuery().select('#the-id').fields({
      dataset: true,
      size: true,
      scrollOffset: true,
      properties: ['scrollX', 'scrollY']
    }, function(res){
      res.dataset    // 节点的dataset
      res.width      // 节点的宽度
      res.height     // 节点的高度
      res.scrollLeft // 节点的水平滚动位置
      res.scrollTop  // 节点的竖直滚动位置
      res.scrollX    // 节点 scroll-x 属性的当前值
      res.scrollY    // 节点 scroll-x 属性的当前值
    }).exec()
  }

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值