vue3微信公众号商城项目实战系列开发环境准备

Posted 屏风马

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue3微信公众号商城项目实战系列开发环境准备相关的知识,希望对你有一定的参考价值。

项目忙完,这次上新,写一个前端系列,采用vue3来开发一个微信公众号商城。

前言:

1. 微信公众号商城本质也是一个网站,由一个个网页组成,只不过这些网页运行在手机端,能响应手指的点击、长按、拖拽等操作。

2. 既然是网页,当然可以用3件套(js+html+css)来写,但象vue这样的前端框架比3件套更高效,或者现实一点说,会一个前端框架能有更多的工作机会。

3. 目前流行的前端框架有 Angular、React、Vue(按首字母顺序排名),Vue的主流版本有Vue2和Vue3 ,本系列用的是Vue3

4.Vue3 可用 javascript(弱类型) 或 typescript(强类型) 做脚本语言,本系列用 javascript

5. Vue3官网地址:https://cn.vuejs.org/ ,

6. Vue3的开发工具官方推荐 vscode,见下图,官方下载链接:https://code.visualstudio.com/

7. 开发vue3项目时,在开发环境运行需要安装 nodejs,官网地址及安装步骤如下,项目开发完成编译后的代码部署到服务器时不需要在服务器上安装nodejs ,

也就是说Web服务器不需要安装任何其他软件,原因后面再具体讲。

 点击LTS版本开始下载

下载之后安装到本机,一直点"Next"按钮就可以了,如下图:

安装完成后在本机目录可以看到,如下图:

 

在地址栏输入"cmd"后回车,快速打开命令窗口:

此时的命令行路径就是刚才的路径,避免输入cd命令切换目录,见下图:

输入 "node -v" 和 "npm -v" 查看版本,见下图:

 

vue之微信公众号开发

最近使用vue开发了一个购物类的微信公众号项目,将遇到的问题及大致的流程都给记录一下。

使用的是vue+vuex+vue-router+axios,样式用的是YDUI。

项目是需要做一个扫码之后通过微信openid做用户标识,然后让用户能够购买商品的小型购物网站,开始是仿照的慕课上某老师的回龙观项目,后来就加入了许多东西。

正文之前写说句感慨,没有系统学习vue就直接做vue项目简直是一直折磨。还有就是基础知识学的不扎实导致遇到一些问题浪费大量时间也不一定能搞出来。

首先先来看vue-router文件:

import Vue from ‘vue‘
import Router from ‘vue-router‘

import goodsDetail from ‘@/components/goodsDetail‘
import goodsList from ‘@/components/goodsList‘
import Mine from ‘@/components/mine‘
import mainPage from ‘@/components/mainPage‘
import submitOrder from ‘@/components/submitOrder‘
import confirmbuy from ‘@/components/confirmbuy‘
import skip from ‘@/components/skip‘
import subuserinfo from ‘@/components/subuserinfo‘

Vue.use(Router)
const router = new Router({
  // mode: ‘history‘,
  routes: [
    {
      path: ‘/‘,
      component: mainPage,
      name: ‘mainPage‘,
      children: [
        {
          path: ‘/‘,
          component: goodsList,
          name: ‘goodsList‘
        },
        {
          path: ‘/Mine‘,
          component: Mine,
          name: ‘Mine‘
        }
      ]
    },
    {
      path: ‘/skip‘,
      component: skip,
      name: ‘skip‘
    },
    {
      path: ‘/goodsDetail‘,
      component: goodsDetail,
      name: ‘goodsDetail‘
    },
    {
      path: ‘/submitOrder‘,
      name: ‘submitOrder‘,
      component: submitOrder
    },
    {
      path: ‘/confirmbuy‘,
      name: ‘confirmbuy‘,
      component: confirmbuy
    },
    {
      path: ‘/subuserinfo‘,
      name: ‘subuserinfo‘,
      component: subuserinfo
    }
  ]
})
export default router

贴vuerouter代码的目的主要是为了展示一下目录结构,这里面是点击了购物车组件之后跳转到提交界面,因为我最开始做的时候,把订单提交组件放到了购物车组件的子组件中,导致了样式发生了很low的错误,需要通过z-index去设置组件的显示级别,后来就都弄成兄弟组件就好了。

mainjs中主要是一些公共方法,下面是一段封装了axios请求,并能够排序进行md5校验的代码,

import axios from ‘axios‘
import querystring from ‘querystring‘
import crypto from ‘crypto‘

Vue.use(YDUI)
// Vue.use(axios)
Vue.config.productionTip = false
Vue.prototype.$domain = ‘http://xianghuali.cn‘  //接口域名/ip
Vue.prototype.$http = function (options) {
  var defaultParam = {
    url: ‘‘,
    method: ‘post‘,
    baseURL: `http://sbf.zzcyi.cn`,
    transformRequest: [function (data) {
      var q = querystring.stringify(data)
      return q
    }],
    // headers: {‘Content-Type‘: ‘application/x-www-form-urlencoded‘},
    params: {},
    data: {},
    timeout: 10000,
    responseType: ‘json‘
  }
  var ajaxParam = {}
  for (var k in defaultParam) {
    ajaxParam[k] = options[k] ? options[k] : defaultParam[k]
  }
  console.log(ajaxParam)
  if (ajaxParam.url === ‘‘) {
    alert(‘请传入请求URL‘)
    return null
  }
  return axios(ajaxParam)
}
Vue.prototype.$md5 = function (str) {
  var md5 = crypto.createHash(‘md5‘)
  md5.update(str)
  return md5.digest(‘hex‘)
}

我使用vuex主要就是为了缓存一些全局参数,例如用户添加的商品数据等信息。其实使用vue做公众号并没有与做pc端有很大的区别,主要是有一些需要主要的地方。

首先是微信请求之后的回调路径,因为我没搞清楚本地调试ip+端口怎么通过微信验证,并且能够回跳回来,所以在开始做支付之后就写上了服务器地址,下面是微信获取用户openid的代码,

function GetOpenId (that, wxappid) {//wxappid是微信公众号后台的appid
  var code = getQueryString(‘code‘)
  var redirecturl = encodeURIComponent(`${that.$domain}/index.html`) //这里是回调地址,可以看到我在组件中调这个方法的时候,把vue的this对象传递了尽量,然后把vue原型链上挂载的地址显示出来
  var imei = window.location.href.split(‘?‘)[1].split(‘#‘)[0].replace(‘imei=‘, ‘‘)
  if (!code && !window.sessionStorage.getItem(‘openidobj‘)) {//如果没有code,并且sessionstorage中没有用户的openid,就跳转到微信授权页,然后回跳回来走else if
    window.location.href = ‘http://open.weixin.qq.com/connect/oauth2/authorize?appid=‘ + wxappid + ‘&redirect_uri=‘ + redirecturl + ‘&response_type=code&scope=snsapi_userinfo&state=‘ + imei + ‘#wechat_redirect‘
  } else if (code && !window.sessionStorage.getItem(‘openidobj‘)) {//请求接口获取openid
    that.$http({
      url: `${that.$domain}/WxPay/QryWebAccessToken?code=${code}`,
      method: ‘get‘
    }).then((res) => {
      if (res.data.openid) {
        window.sessionStorage.setItem(‘openidobj‘, res.data.openid)
        that.$http({
          method: ‘post‘,
          url: `${that.$domain}/WxPay/GetWxUserInfo`,
          data: {
            openid: res.data.openid
          }
        }).then((res) => {
          if (res.data.status === ‘ok‘) {
            window.sessionStorage.setItem(‘wxuserinfo‘, res.data.memo)
            that.$router.replace(‘/‘)
          } else {
            that.$dialog.toast({mes: res.data.memo})
          }
        })
      }
    })
  } else {
    that.$http({
      method: ‘post‘,
      url: `${that.$domain}/WxPay/GetWxUserInfo`,
      data: {
        openid: window.sessionStorage.getItem(‘openidobj‘)
      }
    }).then((res) => {
      if (res.data.status === ‘ok‘) {
        window.sessionStorage.setItem(‘wxuserinfo‘, res.data.memo)
        that.$router.replace(‘/‘)
      } else {
        that.$dialog.toast({mes: res.data.memo})
      }
    })
  }
}

这里牵扯到一个问题就是界面需要加载进来,然后跳转到微信,然后在跳回来,如果直接显示页面会让用户体验很不好,参考了网上的做法,做了一个等待页,专门用来显示给用户并获取用户信息的,获取信息之后在跳回来进行后面的操作。

其实我感觉vue与之前我们习惯的dom操作最大的区别就是,vue没有直接对父子兄弟元素进行操作的方法,而是通过传值,flag,通过函数改变变量来间接的操作目标元素。开始不习惯的时候感觉做起来很吃力,写多了之后也就习惯了,只要能记得变量要及时清除重新赋值即可。项目中使用的微信支付,主要是掉后台接口,没有什么要记录的。下面说一下socket以及百度地图,

首先是socket,因为需要通过socket与设备通讯,所以在界面一进来就要建立一个长连接,参考上面vue-router中的路由配置,这里就是在用户逗留时间最多的商品列表组件goodsList的父组件mainPage中创建的,mainPage.vue代码如下

<template>
  <div>
    <v-header></v-header>
    <div class="tab">
      <div class="tab-item">
        <router-link to="/" replace>商品</router-link>
      </div>
      <div class="tab-item">
        <router-link to="/Mine" replace>订单</router-link>
      </div>
    </div>
    <keep-alive>
      <router-view />
    </keep-alive>
  </div> 
</template>

<script>
import header from ‘./header‘
import ‘../../static/boundleProto‘
// import ‘../../static/CySocket‘
import {GetOpenId} from ‘../../static/common‘

import {CySocket} from ‘../../static/CySocket‘
import {GetSignature} from ‘../../static/common‘
import Vue from ‘vue‘
export default {
  name: ‘mainPage‘,
  components: {
    ‘v-header‘: header
  },
  created () {
    // var imei=‘ZZCY5ccf7fdf754c‘;
    this.$http({
      url: `${this.$domain}/Home/QryConfig`,
      method: ‘get‘
    }).then((res) => {
      // GetOpenId(this,res.data.WxAppId)
      this.formatdate()
      var that=this;
      this.$store.state.refundTimeRange=res.data.refundTimeRange
      if(!window.sessionStorage.getItem(‘wxuserinfo‘)){
        var t=setInterval(function(){
          if(window.sessionStorage.getItem(‘wxuserinfo‘)){
            that.creatsocket(res.data.ServerIpEp);
            clearInterval(t)
          }
        },10)
      }else{
        that.creatsocket(res.data.ServerIpEp);
      }
    })
  },
  beforeRouteEnter (to, from, next){
    next(vm=> {
      if(!window.sessionStorage.getItem("wxuserinfo")){
        next("/skip");
      }
    })
  },
  methods: {
    //实例化socket
    creatsocket(serverIp){
      var wxuserinfo=JSON.parse(window.sessionStorage.getItem(‘wxuserinfo‘)).LoginNo
      if(!wxuserinfo){
          this.$dialog.toast({mes: ‘获取参数错误‘});
      };
      var that=this
      Vue.prototype.cySocket = new CySocket({
        server:`ws://${serverIp}`,
        autoReconnect: true,
        openSocket: function() { //连接socket后立即发送登录包
            var user = new window.proto.SocketCmd.CmdHeader();
            user.setCmdcode("0202"); //命令号
            user.setIdentity(wxuserinfo); //客户端标识
            user.setTimetoken(new Date().format("yyyy-MM-dd hh:mm:ss")); //命令时间
            this.sendMsg(user.serializeBinary());
            var imei=window.sessionStorage.getItem(‘imei‘);
            //查询设备状态
            if(!imei||!wxuserinfo){
              that.$dialog.toast({mes: ‘出现异常···请重新扫码‘});
            }else{
              var qrydevice = new window.proto.SocketCmd.CmdHeader();
              qrydevice.setCmdcode("0203");
              qrydevice.setIdentity(wxuserinfo);
              qrydevice.setOppositeid(imei);
              qrydevice.setTimetoken(new Date().format("yyyy-MM-dd hh:mm:ss.S")); //命令时间
              this.sendMsg(qrydevice.serializeBinary());
              var time_=0;
              var t=setInterval(function(){
                time_+=1;
                if(that.$store.state.socketbacksocket){
                  clearInterval(t)
                }else if(time_>=1000){
                  clearInterval(t)
                }
              },10)
            }
        },
        receiveMsg: function(data) {
            var commBk = window.proto.SocketCmd.ComCmdBkPb.deserializeBinary(data);
            var msg = "";
            switch (commBk.getCmdcode()) {
            case "0202": //客户端登录
                msg = "登录返回:" + commBk.toString();
                break;
            case "0103":
                msg = "状态查询返回:" + commBk.toString();
                if(commBk){
                  that.$store.state.socketbacksocket=true
                }
              break;
            case "0104": //控制返回消息
                var lockBk = window.proto.SocketCmd.OpenLockBkPb.deserializeBinary(data);
                msg = "控制开锁返回:" + lockBk.toString();
                that.$store.state.deviceState = true
                if(that.$store.state.opendoorfrom == ‘mineorder‘){
                  that.$http({
                    method: ‘post‘,
                    url: `${that.$domain}/WxPay/TxUpdateOrderState`,
                    data: {
                      orderId: that.$store.state.orderId,
                      state: ‘SUCCESSU‘
                    }
                  }).then((res) => {
                  })
                }
                that.$dialog.toast({mes: ‘开锁成功‘});
                break;
            case "0105": 
                msg = "补货开大门返回:" + commBk.toString();
                break;
            }
        }
      });
      Vue.prototype.cySocket.init();
    },
  //格式化时间 formatdate(){ Date.prototype.format
= Date.prototype.format||function (fmt) { var o = { "M+": this.getMonth() + 1, //月份 "d+": this.getDate(), // "h+": this.getHours(), //小时 "m+": this.getMinutes(), // "s+": this.getSeconds(), // "q+": Math.floor((this.getMonth() + 3) / 3), //季度 "S": this.getMilliseconds() //毫秒 }; if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); for (var k in o) if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); return fmt; } } } } </script> <style> @import "../common/index.css"; .tab{ display:flex; width:100%; height:40px; line-height:40px; border-bottom: 1px solid rgba(7,17,27,0.1); } .tab .tab-item{ flex:1; text-align:center; } .tab .tab-item a{ display:block; font-size:14px; color:rgb(77,85,93); } .tab .tab-item a:hover , .tab .tab-item a.router-link-exact-active{ font-size:14px; color:#f01414; } </style>

其中socket这部分因为要传bype,而之前做的项目已经被bype传伤了,所以后台大佬用google巨佬们开源的protobuffer封装了前后台及硬件c的protobuf代码,不用拼bype可以直接传~~~~,因为使用了vue的keep-alive组件,所以组件可以缓存,socket在切换了之后也不会断,暂时没有研究不使用keep-alive组件,切换兄弟组件之后上个组件注销会不会导致socket断开。其他子组件发送socket只需要将数据塞到挂载在vue原型链上的cysocket对象就行了

  opendoor(){
      var imei=window.sessionStorage.getItem(‘imei‘);
      var wxuserinfo=JSON.parse(window.sessionStorage.getItem(‘wxuserinfo‘)).LoginNo
      var boxInfo = new window.proto.SocketCmd.OpenLockPb();
      boxInfo.setCmdcode("");//从这里开始
      boxInfo.setIdentity(wxuserinfo);
      boxInfo.setOppositeid(imei);
      boxInfo.setOrderid(this.orderId);
      boxInfo.setLockstatus(this.lockstate);
      boxInfo.setTimetoken(new Date().format("yyyy-MM-dd hh:mm:ss.S"));//命令时间  //到这里结束,都是自己定义的参数,因为是protobuffer封装过的,所以可以直接传了···
      this.cySocket.sendMsg(boxInfo.serializeBinary());
      this.$store.state.opendoorfrom=‘suborder‘
    },

其实这段socket代码并没有前端太多事,编译ptobuf我也不懂,以后有时间,学习了后端之后再去研究一下,js操作二进制数据可以参考我的另一篇博客

下面是微信jsapi获取用户坐标并在百度地图中显示出来,

首先是算签名的公共方法,并传进去callback获取用户坐标

function GetSignature (that, callback) {
  that.$http({
    url: `${that.$domain}/WxPay/QryWxSignature?url=${window.location.href.split(‘#‘)[0]}`,
    method: ‘get‘
  }).then((data) => {
    AppId = data.data.appId
    Timestamp = data.data.timestamp
    Signature = data.data.signature
    Noncestr = data.data.nonceStr
    wx.config({
      beta: true,
      debug: false,
      appId: AppId,
      timestamp: Timestamp,
      nonceStr: Noncestr,
      signature: Signature,
      jsApiList: [
        ‘checkJsApi‘,
        ‘onMenuShareTimeline‘,
        ‘onMenuShareAppMessage‘,
        ‘onMenuShareQQ‘,
        ‘onMenuShareWeibo‘,
        ‘hideMenuItems‘,
        ‘showMenuItems‘,
        ‘hideAllNonBaseMenuItem‘,
        ‘showAllNonBaseMenuItem‘,
        ‘translateVoice‘,
        ‘startRecord‘,
        ‘stopRecord‘,
        ‘onRecordEnd‘,
        ‘playVoice‘,
        ‘pauseVoice‘,
        ‘stopVoice‘,
        ‘uploadVoice‘,
        ‘downloadVoice‘,
        ‘chooseImage‘,
        ‘previewImage‘,
        ‘uploadImage‘,
        ‘downloadImage‘,
        ‘getNetworkType‘,
        ‘openLocation‘,
        ‘getLocation‘,
        ‘hideOptionMenu‘,
        ‘showOptionMenu‘,
        ‘closeWindow‘,
        ‘scanQRCode‘,
        ‘chooseWXPay‘,
        ‘openProductSpecificView‘,
        ‘addCard‘,
        ‘chooseCard‘,
        ‘openCard‘,
        ‘openWXDeviceLib‘,
        ‘closeWXDeviceLib‘,
        ‘configWXDeviceWiFi‘,
        ‘getWXDeviceInfos‘,
        ‘sendDataToWXDevice‘,
        ‘startScanWXDevice‘,
        ‘stopScanWXDevice‘,
        ‘connectWXDevice‘,
        ‘disconnectWXDevice‘,
        ‘getWXDeviceTicket‘,
        ‘WeixinJSBridgeReady‘,
        ‘onWXDeviceBindStateChange‘,
        ‘onWXDeviceStateChange‘,
        ‘onScanWXDeviceResult‘,
        ‘onReceiveDataFromWXDevice‘,
        ‘onWXDeviceBluetoothStateChange‘
      ]
    })
    wx.ready(function (res) {
      // alert(‘调用微信jsapi返回的状态1:‘ + JSON.stringify(res))
      if (callback) callback()
      wx.error(function (res) {
        // alert(‘调用微信jsapi返回的状态2:‘ + JSON.stringify(res))
      })
    })
  })
}

然后是在地图组件map中调用该方法,并在获取到坐标之后实例化地图

<template>
    <div id="mymap">

    </div>
</template>
<script>
import {GetSignature} from ‘../../static/common‘
import wx from ‘weixin-js-sdk‘
import Vue from ‘vue‘
export default{
    name:‘maps‘,
    data() {
        return{
            lng_:null,
            lat_:null
        }
    },
    created () {
        // GetSignature(this)
    },
    mounted() {
        this.$nextTick(function () {
            var that=this;
        //校验签名并获取坐标 GetSignature(
this,function(){ wx.getLocation({ type: ‘gcj02‘, // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入‘gcj02‘ success: function (res) { var latitude = res.latitude // 纬度,浮点数,范围为90 ~ -90 var longitude = res.longitude // 经度,浮点数,范围为180 ~ -180。 var lng = longitude var lat = latitude var xpi = 3.14159265358979324 * 3000.0 / 180.0 var x = lng var y = lat var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * xpi) var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * xpi) lng = z * Math.cos(theta) + 0.0065 lat = z * Math.sin(theta) + 0.006 that.$store.state.lng = lng that.$store.state.lat = lat var map = new BMap.Map("mymap",{enableMapClick:true}); // 初始化地图,设置中心点坐标和地图级别 var point; var marker; point=new BMap.Point(that.$store.state.lng,that.$store.state.lat) map.centerAndZoom(point, 16); var movemarkerIcon = new BMap.Icon("/reserve/static/img/moveicon.png", new BMap.Size(36,36),{ imageSize: new BMap.Size(36,36) }); var movemarker; map.enableDragging(); //地图拖拽 getneardevice() // 添加带有定位的导航控件 var navigationControl = new BMap.NavigationControl({ // 靠左上角位置 anchor: BMAP_ANCHOR_TOP_LEFT, // LARGE类型 type: BMAP_NAVIGATION_CONTROL_LARGE, // 启用显示定位 enableGeolocation: true }); map.addControl(navigationControl); //地图拖动事件 // map.addEventListener("dragend",getneardevice); // 添加定位控件 var geolocationControl = new BMap.GeolocationControl(); geolocationControl.addEventListener("locationSuccess", function(e){ // 定位成功事件 that.$store.state.lng = e.point.lng; that.$store.state.lat = e.point.lat; that.lng_ = e.point.lng that.lat_ = e.point.lat point=new BMap.Point(e.point.lng,e.point.lat) map.centerAndZoom(point, 16); getneardevice() }); geolocationControl.addEventListener("locationError",function(e){ // 定位失败事件 that.$dialog.toast({mes: e.message,timeout:500}); }); map.addControl(geolocationControl); // map.enableScrollWheelZoom(true); function attribute(){ var p = movemarker.getPosition(); //获取marker的位置 getneardevice(p.lng,p.lat); } //获取设备 function getneardevice(lng,lat){ map.clearOverlays(); that.$dialog.loading.open(‘正在加载点位数据‘); point=new BMap.Point(that.$store.state.lng,that.$store.state.lat) marker = new BMap.Marker(point);// 创建标注 if(lng&&lat){ that.lng_ = lng that.lat_ = lat movemarker = new BMap.Marker(new BMap.Point(lng,lat),{icon:movemarkerIcon});// 创建标注 }else{ that.lng_ = that.$store.state.lng that.lat_ = that.$store.state.lat movemarker = new BMap.Marker(point,{icon:movemarkerIcon});// 创建标注 } map.addOverlay(marker); // 将标注添加到地图中 map.addOverlay(movemarker); // 将可移动点 movemarker.enableDragging() movemarker.addEventListener("dragend",attribute); that.$http({ method: ‘get‘, url: `${that.$domain}/ProductModule/QryNearbyImeiInfo?lng=${that.lng_}&lat=${that.lat_}` }).then((res) => { that.$dialog.loading.close(); if(res.data){ var myIcon = new BMap.Icon("/reserve/static/img/mapicon.png", new BMap.Size(36,36),{ imageSize: new BMap.Size(36,36) }); for(var i=0;i<res.data.length;i++){ var point_=new BMap.Point(res.data[i].ImeiLongitude,res.data[i].ImeiLatitude) var marker_ = new BMap.Marker(point_,{icon:myIcon});// 创建标注 marker_.imei=res.data[i].ImeiMac map.addOverlay(marker_); //点击坐标点事件 marker_.addEventListener("click",function(e){ that.$store.state.imei=e.target.imei; window.sessionStorage.setItem(‘imei‘,e.target.imei) that.$http({ method: ‘get‘, url: `${that.$domain}/ApiDevice/QryImeiInfo?imeiMac=${e.target.imei}` }).then((res) => { if(res.data.data[0].ImeiStatusNo==‘On‘){ if(res.data.data[0].ImeiIsPreOrder==‘Y‘){ if(JSON.parse(window.sessionStorage.getItem(‘wxuserinfo‘)).UserInfo.IsApprove){ that.$router.push(‘/goodsList‘) }else{ that.$router.push(‘/statement‘) } }else{ that.$dialog.toast({mes: ‘该设备未开启预订功能‘,timeout:500}); } }else{ that.$dialog.toast({mes: ‘该设备已离线‘,timeout:500}); } }) }) } } }) } } }) }) }) }, methods: { getlng(){ return this.$store.state.lng }, getlat(){ return this.$store.state.lat },
    //坐标转换 getTrasSite(longitude,latitude){
var lng = longitude var lat = latitude var xpi = 3.14159265358979324 * 3000.0 / 180.0 var x = lng var y = lat var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * xpi) var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * xpi) lng = z * Math.cos(theta) + 0.0065 lat = z * Math.sin(theta) + 0.006 // var x = lng - 0.0065, y = lat - 0.006; // var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * xpi); // var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * xpi); // lng = z * Math.cos(theta); // lat = z * Math.sin(theta); return{ lng:lng, lat:lat } } } } </script> <style lang="scss" scoped> #mymap{ width: 100vw; height: 100vh; } </style>

其中获取设备是类似摩拜的那种需求。

在手机端需要面对的一个问题就是,用户点击home键而不去点你设置好的按钮,那么路由就会非常乱,现在有几种处理方法,但是都不是很完美,

首先是vue-router的replace方法,这个方法与push方法的不同就在于push是向浏览器地址栈中一直添加,[a,b,c,d],这样子,也可能是[a,b,c,d,a,a,a,a]这样,而replace是将当前的路径替换,但是并不是消除,例如[a,b,c],下一个路由你用this.$router.replace(‘/d‘),路由就变成了[a,b,d],暂时没找到方法清除路径记录的,可能js中有这个方法,下去有时间再研究一下。

然后是vuerouter的导航守卫。分别使用beforeRouteEnter和beforeRouteLeave来监听,其中需要注意的就是beforeRouteEnter中没有this对象,因为这时候组件还没有开始创建,可以在回调方法中访问:

beforeRouteEnter (to, from, next) {
//两个方法都可以在这里进行判断,如果离开要去的路由或者路由来源不是自己想要的,就进行中断或者跳转
if(from.path == ‘‘||to.path == ‘‘) { next(vm=>{ //这里的vm就是this,在这里可以进行一些操作 }) } next() },

具体内容参考官方文档   https://router.vuejs.org/zh-cn/advanced/navigation-guards.html。

--END

整篇文章并没有太多高技术含量的内容,但是因为当初并没有系统学习vue,只是看了看官网文档,看了点视频就开始做项目了,导致很多东西都不懂,做项目很吃力。以后学习如果有时间还是要系统的学习。

再此做记录备忘,以及给和我一样遇到同样问题的人一些帮助

 





以上是关于vue3微信公众号商城项目实战系列开发环境准备的主要内容,如果未能解决你的问题,请参考以下文章

vue3微信公众号商城项目实战系列创建一个vue3项目

7天搞定Node.js微信公众号开发

微信公众号开发的开发环境要求和准备工作

13ABPZero系列教程之拼多多卖家工具 微信公众号开发前的准备

一分钟开始持续集成之旅系列之:微信公众号服务器端应用(以 Java 后端为基础)

微信公众号开发之准备工作