Vue 在ios微信中开发公众号的疑难杂症(一)

2,410 阅读4分钟

1. 老生常谈微信授权

微信授权这个东西吧,全部让后端做,后端不高兴,全是前端做的话,但是微信上有文档说明有些数据要放在服务器上发起与存储。所以我和后台商量了一下就我们两个人结合,我前端发请求取请求微信的code。我拿code去请求用户的数据(code换取access_token,access_Token获取appId,appId获取用户数据)这些都放在后端去做

<1>用户什么时候去授权,该怎么去授权(路由钩子)

首先明确一点,新用户访问公众号的第三方网页肯定是要授权。这个授权我的做法是在需要访问的菜单上(路由)加了一个requireAuthor,然后使用路由的钩子函数beforeEach去判断哪个菜单要授权,同时呢还要看本地是否有这个用户的缓存数据,是不是有code。有这个用户但是没有code,说明这个用户授权过期了,需要重新授权,有code,但是没有用户信息,那说明这是一个新用户。

import rotuer from './index'
import store from '../store/store'
import {getWechatAuthore} from '../api'

rotuer.beforeEach((to, from, next) => {
  let wxcode = getulrparam("code");
  let users = store.getters.getStore;
  let uri = encodeURIComponent("http://XXX.cn");
  if (to.meta.requireAuth) {
    if (wxcode == null && users == null) {
      location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=3&redirect_uri=${uri}&response_type=code&scope=snsapi_userinfo&state=1&connect_redirect=1#wechat_redirect`;
    } else {
      if (wxcode !== null && users == null) {
        getWechatAuthore(wxcode).then(res => {
          store.commit("setStore", res)
        });
        next();
      }
      if (users !== null && wxcode == null) {
        next();
      }
      next()
    }
    next();
  } else {
    next();
  }
  // next()
});

function getulrparam(name) {
  let reg = new RegExp("(|&)" + name + "=([^&]*)(&|$)");
  let r = window.location.search.substring(1).match(reg);
  if (r != null) return unescape(r[2]);
  return null
}
 

2 使用vant的File,但是这个东西没有校验如何解决(vee-validate)

第一次使用有赞的东西,觉得样式挺好的。写完以后我发现这个完善资料这个组件里面要校验的东西太多了,我不能自己一个一个去校验吧,不大现实。去网上找了一下,说是有vee-validate这个插件可以解决,我装上以后发现按照网上的说法来做根本行不通。所以我去官网上看了一下,人家现在是3.X的版本了,里面的api完全变了。可以说变得更简单了,新的版本采用了观察者模式,只不过一开始被网上的2.X的教程误导了。如果你觉得这个框架校验的不够全面,那就自己定义,这里我自己定义的校验手机号,身份证,体重身高的范围值的校验

// 手机号码验证
extend('mobile', {
  message: () => `请输入正确的手机号码`,
  validate: value => value.length === 11 && /^(((13[0-9]{1})|(14[57]{1})|(15[012356789]{1})|(17[03678]{1})|(18[0-9]{1})|(19[89]{1})|(16[6]{1}))+\d{8})$/.test(value)
});
extend('idCard',{
  message:()=> `请输入正确的身份证号码`,
  validate:value => value.length === 18 && /^[1-9][0-9]{5}([1][9][0-9]{2}|[2][0][0|1][0-9])([0][1-9]|[1][0|1|2])([0][1-9]|[1|2][0-9]|[3][0|1])[0-9]{3}([0-9]|[X])$/.test(value)
})
extend('number',{
  message:()=> `请输入正确数字`,
  validate:value =>  value*1 < 500 && /^\+?[1-9][0-9]*$/.test(value)
})

然后在mainjs中引用这个规则文件,然后再需要使用校验的地方要

    <ValidationObserver ref="form">
      <van-cell-group>

        <!--用户名-->
        <ValidationProvider rules="required" name="用户名" v-slot="{errors}">
          <van-field
            v-model="userInfoEdite.userName"
            required
            clearable
            label="用户名"
            right-icon="question-o"
            placeholder="请输入用户名"
            :error-message="errors[0]"
          />
        </ValidationProvider>
        <!--身份证号-->
        <ValidationProvider name="身份证号" rules="required|idCard" v-slot="{errors}">
          <van-field
            v-model="userInfoEdite.identityCard"
            label="身份证号"
            placeholder="身份证号"
            required
            :error-message="errors[0]"
          />
        </ValidationProvider>
      </van-cell-group>
    </ValidationObserver>
  

然后就是vue的语法,this.$refs.form.validate()这是一个promise,你可以写箭头函数来拿到校验以后的结果,返回boolean值。

3 解决输入框问题

在ios里面键盘是可以自动滑动,这样保证输入框始终在键盘上方,但是在Android就不行,把整个样式都搞乱。问我同学他们公司怎么搞得,然后因为他们使用的是jq,所以方式放在这里肯定是不行了,在网上看到有人加了一段代码,我把它封装成一个包,然后引入这个包就可以了

export default function inputUp() {
  //安卓机型,自动上滑露出输入框
  if(/Android/.test(navigator.appVersion)) {
    window.addEventListener("resize", function() {
      if(document.activeElement.tagName=="INPUT" || document.activeElement.tagName=="TEXTAREA") {
        document.activeElement.scrollIntoView();
      }
    })
  }

}

4 在ios版本中的微信中url总是显示第一次的值

一开始使用vue-router的hash 模式,觉得是不是hash模式微信浏览器获取不到#后面的值,所以修改成history模式,调试发现还是显示的是www.xxx.com,因为要监听路由的变化我去同步底部导航的状态,加上我的路由表设计的有点问题,导致我的tab不能正常切换。以为是vant的tab组件的问题,问了问别人,说确实回失效,换成原生就好了,所以我用原生写了,但还是切换失效,所以我去找路由表,觉得嵌套的有问题,所以这个看自己的路由表和路由挂载的地方,那有什么办法解决这个url不变呢,有一个很简单的办法就是刷新一次页面,但是不能使用this.$router.go(0);这样会一直刷新页面,无限刷新,然后我又强制刷新路由。这个bug一直没解决,所以没办法我只能去掉这个tab切换。

5 滚动问题

这个滚动问题,只会出现在safari与微信浏览器中,一个是首次加载页面会出现划不动的现象,网上有说加一个样式,说的是解决ios滑动会出现卡顿的现象,但是没有解决,我以为是vant的问题,我换成mui的loadeMore还是会出现这个问题,可这个在chrome和Android 里面完全是好使的哇,心态要崩溃了,没办法,只能去网上找了一个插件,但是这个插件上拉完成以后,会让元素跑到最上面隐藏一部分,但是通过ios自带的下拉反弹能够看到,这个问题去掉插件就是好的,和客户商量了一下,暂时先这样用。

2019/11/18(更新,滚动问题)

在查了几天的资料后,我觉得应该是这样的:我的页面结构

    <div class="searchResult" :style="{height:hei + 'px'}">
      <div class="van-list-wrap">
        <mt-loadmore :bottom-method="onLoad" :bottom-all-loaded="allLoaded" :auto-fill="false" ref="loadmore"
                     @bottom-status-change="handleBottomChange">
          <div class="item" v-for="(item,index) in dataList" :key="index">
            <div class="name" @click.once="getRecordDetails(item.examinationRecordId)">
              <div class="itemList">
                <p><span>姓名:</span>{{item}}</p>
                <p><span>日期:</span>{{item}}</p>
                <p><span>项目:</span>{{item}}</p>
              </div>
            </div>
            <p v-if="item.fileName">{{item}}
              <van-button plain type="info" @click="pdfPreview(item.accessUrl)">查看附件
              </van-button>
            </p>
            <div class="onePx"></div>
          </div>
          <div slot="bottom" class="mint-loadmore-bottom">
            <span v-show="bottomStatus !== 'loading'" :class="{ 'rotate': bottomStatus === 'drop' }">↓</span>
            <span v-show="bottomStatus === 'loading'">Loading...</span>
          </div>
        </mt-loadmore>
      </div>
      <van-loading type="spinner" color="#fff"/>
    </div>

基本上的结构是子元素无限高度,父元素固定高度,并设置overflow:scroll,我的bug是首次加载会滚动,当路由跳转到其他页面,然后再回到这个路由页面滚动就失效了。我查了一下,路由复用的时候,不会重新加载页面,也就是说我的数据还没返回,他又不重新渲染,导致我子元素的高度为0。这也就是网上说的overflow:scroll在ios中失效的原因。解决的办法:第一个就是刷新一次页面,重新渲染,这个在我使用的场景上还可以,所以就使用这个。第二个就是给子元素设置一个min-height;style="height: calc(100%+.5rem)"

6 打生产包放在nginx里面会出现404以及使用history页面刷新一次会报404,开发环境刷新报404

我在开发的时候一共会出现这三种情况。第一种的出现的原因是因为assetsPublicPath我是用的绝对路径,这样肯定是不行的,所以改成“./”.第二种vue-router上也说了,使用history会出现重定向,在host路径是找不到资源的,所以才会报404,解决办法就是在nginx中加上一段配置

try_files $uri $uri/ /index.html;

这样就重定向到首页,让在首页这个位置去匹配路径。开发环境刷新报404,是因为springboot加filter把路径拦截掉了,所以我改了一个路径名,结果刷新就不再报404了。