支付宝生活号h5网页开发

前言

前一段时间,我负责了公司的一个支付宝生活号h5网页开发的项目,主要是用来采集用户的数据的。到现在也已经接近尾声了,在开发的过程中也遇见了不少的坑坑洼洼,所以我就想着总结一下这个项目的一些问题和解决思路,希望对后面有需要做支付宝生活号h5网页开发的程序员有或多或少的帮助吧。

概述

首先,这个项目前端原本是有代码,但是原本的代码是微信公众号h5网页端和支付宝生活号h5网页端混在一起写的,而且原本的代码是经过了很多次的二次开发,代码冗余度很高,很多都是无用的代码,代码规范差,代码复用性很差,而且使用到的技术有些已经过时了,从而导致了项目难以维护。所以经过了一番讨论,决定不使用原来的代码,重写一套针对支付宝生活号h5网页的代码,后面要是微信有公众号的h5网页,就写一套针对微信公众号h5网页的代码。这样也方便后面需要进行二次开发的同事。

技术的选型以及项目的架构

  • 这次开发的主要是一个spa单页面h5网页,公司前端主要用到的技术是vue,所以首选的是vue全家桶,但是以前项目使用的是vue-cli2,但是总所周知,vue-cli3已经出来了有一段时间了,所以脚手架方面选用的是vue-cli3。

  • ui框架方面,选用的是mint-ui。但是使用到mint-ui的组件并不是很多,主要是使用了它里面的DatetimePicker,Button,Actionsheet,Loadmore,Picker这些组件,所以这里需要使用到按需加载,减少打包的体积。

  • 自定义组件。很多组件需要根据项目的实际需要去进行定制实现的,比如input、textArea、loading、select。而且使用自己定义的组件还可以解决不少的问题,不用去修改第三方ui框架这么困难。

  • 移动端少不了的肯定就是滚动问题。一开始是打算用浏览器自带的滚动条实现滚动的,但是后面发现浏览器自带的滚动动画太过生硬了,用户体验不好,最后使用了better-scroll这个移动端的滚动库,滚动的体验明显提升了不少。

  • 然后移动端还会有一个致命的东西就是点击后会有300ms的延迟,这里使用了fastclick这个库来解决这个问题。

  • 调试方面,由于手机浏览器没有像谷歌浏览器那样的开发者面板,出现错误很难排查,所以这里使用vconsole这个库,所有的输出,网络请求等等都会在vconsole这个控制面板中看得见。

  • 发送请求方面,主要是用到了axios这个库进行网络请求,这里使用了axios的拦截器统一添加一个loading状态,提高用户体验

  • 模块化封装。项目中我根据不同的功能封装不同的工具类方法,比如请求方面封装一个http请求类,校验身份证,手机号码的,封装一个校验类。

  • 组件化。项目在开发的时候,需要把一个页面拆分成不同的组件,方便去管理,同时也为了提高代码的复用性。

  • 项目目录结构如下图

    1、public下的东西到时候打包的时候会直接复制过去,不做处理

    2、src是主要写代码的地方,src的目录结构如下

    由于这个项目是有2个页面,一个是支付宝生活号h5网页,一个是支付宝生活号消息模板推送的页面,所以这个项目会有2个入口
    index就是支付宝生活号h5网页的入口,query是支付宝生活号消息模板推送的网页入口,common是放置2个入口的所用到的一些公共东西,比如input组件,校验身份证等通用方法,通用css样式,通用图片等等

    3、vue.config.js是配置webpack相关内容的,相关配置如下


const isDev = process.env.NODE_ENV == 'development'
module.exports = {
    publicPath:isDev?'/':'/Integration-html',
    devServer: {
        // 自动打开浏览器
        open: true,
        port:9000,
        disableHostCheck: true,
        proxy: { // 配置请求代理
            '/integration': {
                target: 'http://192.168.1.75:8080',
                changOrigin: true
            }
        },
    },
    // 配置多页面
    pages: {
        // 主页面
        index: {
            // page 的入口
            entry: 'src/index/main.js',
            // 模板来源
            template: 'public/index.html',
            // 在 dist/index.html 的输出
            filename: 'index.html',
            // 当使用 title 选项时,
            // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
            title: 'xxxx',
            // 在这个页面中包含的块,默认情况下会包含
            // 提取出来的通用 chunk 和 vendor chunk。
            chunks: ['chunk-vendors', 'chunk-common', 'index']
        },
        // 副页面,生活号消息推送点击进来的页面
        query: {
            // page 的入口
            entry: 'src/query/main.js',
            // 模板来源
            template: 'public/query.html',
            // 在 dist/index.html 的输出
            filename: 'query.html',
            // 当使用 title 选项时,
            // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
            title: '办卡进度查询',
            // 在这个页面中包含的块,默认情况下会包含
            // 提取出来的通用 chunk 和 vendor chunk。
            chunks: ['chunk-vendors', 'chunk-common', 'query']
        },
    }
}

开发技术点

  • 设置支付宝生活号菜单。首先需要进入支付宝生活号服务后台,找到自定义菜单,然后添加主菜单,添加完成后会让你选择点击这个菜单后需要做什么操作,这里我选择的是跳转到网页,然后你需要设置调转网页的地址。

  • 支付宝jsapi调试。支付宝并没有像微信那样有微信web开发者工具提供给开发者调试h5网页,而且这里需要使用到支付宝提供的一些jsapi接口,这部分东西必须在支付宝上才能调试,所以想要调试需要把前端代码放在服务器中才能去调试。但是这样太麻烦了,所以我向公司申请了一个外网地址,让这个外网地址指向我的电脑ip地址。然后在支付宝生活号服务后台设置一下点击菜单所需要跳转的地址,然后我们在本地使用vue脚手架把项目跑起来,vue脚手架就会给我们起一个服务器,然后我们修改代码后就可以在支付宝生活号h5网页哪里手动刷新就可以看见效果了,不用每次打包放到服务器上这么麻烦。

  • 屏幕自适应。移动端首先需要解决的就是不同手机屏幕自适应,这里使用的是rem+flex布局,rem是根据html元素的font-size的大小进行计算的,打个比方:html元素的font-size是16px,那么1rem就是等于16px,这里需要解决的是在不同屏幕下设置html元素的font-size的大小,从而达到自适应。代码如下


!function (n) {
  var e = n.document, t = e.documentElement, i = 750, d = i / 100, o = "orientationchange" in n ? "orientationchange" : "resize", a = function () {
    var n = t.clientWidth || 375;
    n > 750 && (n = 750), t.style.fontSize = n / d + "px"
  };
  a();
  e.addEventListener && (n.addEventListener(o, a, !1), e.addEventListener("DOMContentLoaded", a, !1))
}(window);

这里使用立即执行函数是为了不造成变量的全局污染,orientationchange这个事件是旋转屏幕时候触发的。这里是按照iphone6的设计稿来设置的,rem的基准是100,这样可以方便计算。这里需要注意的是,你可能需要在body下设置一下你的默认字体大小,因为html的font-size会对那些没有设置font-size的元素造成影响。

  • 设置支付宝生活号h5网页的标题。项目需求是需要h5网页端的标题需要跟页面的功能对应,比如登录页面就需要把标题设置成登录,信息填写页面需要把标题设置成信息填写。支付宝的jsapi中有一个设置标题栏的方法,但是需要在每个路由页面下添加AlipayJSBridgeReady事件的监听,等待jsapi加载完成后才能去设置标题,这样做的问题在于不方便管理,页面一多就混乱。所以这里我换了一种思路,支付宝生活号网页的标题实际上就是html的title标签中的文字,所以,在填写路由的时候,我在每个路由下添加一个meta对象,meta对象中填写一个tiltle,这个title就是对应的支付宝生活号h5网页标题,这样我们可以轻松知道每个路由页面的作用是什么。然后在主入口文件中设置全局的路由守卫beforeEach,在进入每个路由前获取meta标签的信息,动态的设置html中的title标签内容,这样就不用再每个路由页面下调用jsapi设置表一栏的接口了,因为这是需要损耗性能的,而且也不易于管理

  • 调用手机摄像头选取照片。这里主要是拍摄身份证证件的,所以需要做的是当用户横放手机拍摄的时候,获取的照片原样显示,当用户竖放手机的时候,需要把照片旋转过来横放,方便用户查看。然后就是上传图片,由于上传的是base64图片,安卓下没有太大的影响,但是苹果下很容易会抱413这个状态码,就是post请求参数过长。解决方法有2个,一个是降低图片的质量因子,然后使用canvas再把图片体积减少,虽然可能只是减少1-4k左右,但是还是有作用的。二是post请求参数本来是没有限制,但是服务器默认会有限制的,所以可以在服务器上设置取消对post请求参数的限制。这个项目是用到了nginx和tomcat,这2个服务器都会限制post请求参数大小,所以这2个服务器需要同时设置取消对post请求参数的限制。下面这段代码主要是解决怎么使用canvas压缩图片大小,竖着的图片横着放


//dom结构
<div ref="content" class="z-photo photo flex-row flex-center" @click="photo('zimg')">
  <img v-show="userMessage.zimg" ref="zimg" :src="userMessage.zimg" />
  <p v-if="!userMessage.zimg" class="photo-msg">点击拍摄身份证个人信息面</p>
</div>

// 加载图片
loadImage(src) {
  const ref = this.side;
  // 新建一个Image对象是因为需要获取当前拍照的图片的宽和高
  let img = new Image();
  img.src = src;
  const self = this;
  img.onload = function() {
    const w = img.width;
    const h = img.height;
    const quality = 0.3; //图像质量
    const canvas = document.createElement("canvas");
    canvas.width = w;
    canvas.height = h;
    const drawer = canvas.getContext("2d");
    drawer.drawImage(img, 0, 0, w, h);
    const base64 = canvas.toDataURL("image/jpeg", quality);
    self.handelPic(self.$refs[ref], img.height, img.width);
    self.setUserMessage({ key: ref, val: base64 });
  };
},
// 将竖着的照片横放
handelPic(dom, h, w) {
  try {
    if (h > w) {
      //竖
      // 竖放的照片需要旋转90度横着放
      dom.style.transform = "rotate(-90deg)";
      dom.style.width = `${this.ch}px`;
      dom.style.height = `${this.cw}px`;
    } else {
      //横
      dom.style.transform = "rotate(0)";
      dom.style.width = `${this.cw}px`;
      dom.style.height = `${this.ch}px`;
    }
  } catch (error) {
    this.$toast(error.toString());
  }
},

这里我说一下把竖着的照片横着放的思路:首先需要创建一个Imaged对象,然后把base64字符串挂载到Image对象的src属性下。监听onload事件,然后获取图片的宽和搞,如果高大于宽,那么图片就是竖着的图片,反之则是横着的图片。竖着的图片需要把img元素旋转90度,然后把img元素的宽设置成图片容器(即包裹img元素的那个div)的高,img元素的高设置成图片容器的宽。横着的图片则不用旋转,把img元素的宽设置成图片容器的宽,img元素的高设置成图片容器的高。

  • 然后这里要说一下苹果的自带bug。input元素type=password和type=text。当有2个输入框,一个是type=text。紧接着下一个是type=password的情况下,type=text的输入框会输入不了中文。导致的原因是type=text的输入框紧挨着type=password这个输入框,这里的紧挨着不是指2个input元素紧挨着,是指type=text输入框和type=password输入框之间没有任何输入框。所以这里需要在type=text输入框和type=password输入框之间再加一个type=text的输入框,这个输入框使用style="height:0;border:none;padding:0;width:0;"来进行隐藏,切记不能使用display:none或 visibility: hidden对该标签进行隐藏,否则还是解决不了这个bug。

  • 苹果手机input标签需要长按才能获取焦点。虽然使用了fastclick这个库来解决移动端300ms的延迟,但是苹果手机上input标签还是需要长按才能获取焦点。要解决这个问题有2个。一是修改fastclick的源码,判断点击的是否为input标签,若果是就让input标签获取焦点。二是在input标签上添加一个点击事件,点击input标签后就自动获取焦点。这里显然采用第二种方案是比较简单的。综合上面2个问题,我把自己自定义的组件代码放在下面供参考吧

<template>
  <div class="input-box">
    <div v-if="start || label" class="flex-row title" :style="{'width':width}">
      <span v-if="start" class="start">*</span>
      <span v-if="label">{{label}}</span>
    </div>
    <input
      @click="handelClick"
      v-if="type"
      :maxlength="maxLength"
      ref="input"
      :placeholder="placeholder"
      :value="value"
      @input="handelChange"
      class="input"
      autocomplete="off"
      :type="type"
    />
    <!-- 苹果手机下,如果type=text 后面紧跟着一个 type=password 的input标签,会导致前面一个type=text的input标签输入不了中文,所以这里需要使用额外的input标签进行隔离,该input标签必须是type="text",并且不能使用display:none或 visibility: hidden对该标签进行隐藏 -->
    <input type="text" style="height:0;border:none;padding:0;width:0;">
    <i v-if="icon" :class="isHiden?'icon-hide':'icon-show'" class="iconfont" @click.stop="toggle"></i>
    <i v-if="clearable&&value" @click.stop="clear" class="mintui mintui-field-error close"></i>
  </div>
</template>

<script>
export default {
  props: {
    label: {
      type: String,
      default: ""
    },
    start: {
      type: Boolean,
      default: false
    },
    value: {
      type: String,
      default: ""
    },
    placeholder: {
      type: String,
      default: ""
    },
    clearable: {
      type: Boolean,
      default: false
    },
    maxLength: {
      type: String
    },
    width: {
      type: String,
      default: "2rem"
    },
    icon: {
      type: Boolean,
      default: false
    }
  },
  model: {
    prop: "value",
    event: "inputChange"
  },
  data() {
    return {
      isHiden: true
    };
  },
  methods: {
    handelChange(e) {
      this.$emit("inputChange", e.target.value);
    },
    // 苹果手机因为fastClick的缘故,需要长按input才能获取焦点
    handelClick(e) {
      e.target.focus()
    },
    clear() {
      this.$emit("inputChange", "");
      this.$refs.input.value = "";
    },
    toggle() {
      this.isHiden = !this.isHiden;
    },
    getFocus() {
      this.$refs.input.focus();
    }
  },
  computed: {
    type() {
      let type = this.isHiden && this.icon ? "password" : "text";
      return type;
    }
  }
};
</script>


<style lang="less" scoped>
.input-box {
  display: flex;
  flex-direction: row;
  width: 100%;
  align-items: center;
  height: 100%;
  padding: 0.15rem;
  .title {
    color: #7b7b7b;
    text-align: left;
    font-size: 0.3rem;
    .start {
      color: red;
      margin-right: 0.1rem;
    }
  }
  .input {
    flex: 1;
    border: none;
    padding-left: 10px;
    font-size: 0.31rem;
    min-height: 0.7rem;
  }
  .input::-webkit-input-placeholder {
    color: #b3b3b3;
    font-size: 0.3rem;
  }
  .input:-moz-placeholder {
    color: #b3b3b3;
    font-size: 0.3rem;
  }
  .input::-moz-placeholder {
    color: #b3b3b3;
    font-size: 0.3rem;
  }
  .input:-ms-input-placeholder {
    color: #b3b3b3;
    font-size: 0.3rem;
  }
}
</style>

  • 支付宝网页授权登录。这里的登录流程我就不多说了,采用的是oauth2,现在业界非常流行的。不熟悉的可以查看文档。这里我要说的主要有2点。一是授权回跳的地址需要在支付宝生活号服务者后台设置授权回调地址。二是获取回跳回来的url上面的auth_code,由于项目时使用hash路由模式的,所以auth_code这个参数是在#前面的,不能简单地通过this.$route.query获取,需要自己手动解析获取,这里贴上解析获取auth_code的代码

// 解析请求栏参数,主要用于网页授权后回调地址带hash#,获取hash#前面的参数
// http://localhost:8080/?code=12313123&a=444#/photograph  => {code:12313123,a:444}
export const getParam = (key) => {
    let href = location.href.split('#')[0]  // http://localhost:8080/?code=12313123&a=444
    let queryString = href.split('?')[1] // code=12313123&a=444
    if (!queryString) {
        return false
    }
    let query = queryString.split('&')
    let obj = {}
    for (let i = 0; i < query.length; i++) {
        let arr = query[i].split('=')
        obj[arr[0]] = arr[1]
    }
    if (key) {
        return obj[key]
    }
    return obj
}

  • 数据缓存策略。由于项目是需要采集用户数据的,所以会涉及到大量的数据字典,比如用户需要选择性别,人员类别,户口性质等等,这些都是通过发送请求去后台获取的。但是要是用户每点一次就去后台获取数据明显就已经降低了用户体验,而且这些数据基本上是不变动的,或者说不会突发性的变动,所以我就把这些数据缓存在sessionStorage中,当需要获取的数据已经有缓存了,就使用缓存的数据,没有则发送请求,然后把请求的数据缓存起来。也就是说用户每次打开应用的时候,这些数据只会发送一次请求去后台获取,当用户关闭应用的时候,这些数据就会被清空。这样也可以很好的处理数据字典中的数据发生变动的问题。这里还有一个问题就是存储在sessionStorage中的数据是以key-val的形式存在,所以我们需要保证的是key的唯一性,不然就可能会存在数据不正确的情况。项目中,我是以请求地址加上请求参数作为key的,这样就可以保证每一份数据对应唯一的key。当然这里还有很多数据缓存的策略,比如你可以使用第三方数据缓存策略库lru-cache。或者你也可以利用localstorage实现时间更加长久的缓存,你只需要为每一份数据添加一个过期时间,然后在获取数据的时候检查这个时间是否已经过期了吗,过期则去后台获取数据重新缓存,没过期则继续使用。这里我不建议使用localstorage去永久缓存这些数据,虽然有些后台数据变动不大,但是我们也要防止后台数据会变动的情况。
  • 骨架屏。vue单页面在启动的时候,首页会出现一段时间的白屏,原因就是在于index.html在刚下载下来的时候body只有一个div标签,页面的内容需要等js下载完成并执行,生成页面显示的内容才会有内容显示出来。特别是在网络慢的情况下,骨架屏就能缓解用户等待的焦虑。骨架屏的原理主要是在div标签中插入不同的内容,然后根据地址栏的地址显示不同的内容,等到真正需要显示的内容生成出来,骨架屏的内容就会被干掉。骨架屏的实现可以使用vue-skeleton-webpack-plugin这个插件来进行实现。但是这个项目一进去就是首页,所以只需要实现首页的骨架屏即可,所以我是直接在index.html中编写骨架屏的,没有使用到其他插件实现。但是如果你的项目在打包编译的时候会对index.html进行某些操作,就不建议直接在index.html中编写骨架屏,因为可能会改变你编写的内容,导致骨架屏出现问题。这里可以使用自定义webpack插件,利用html-webpack-plugin插件提供的生命周期钩子函数,往index.html中插入内容。代码示例如下
let MyPlugin = function (options) {
     this.template = options.template;
   }
   
   MyPlugin.prototype.apply = function (compiler) {
     // console.log(compiler);
     console.log('我们的插件被执行了');
     // 先指定自己怎么编译,根据别人的编译结果操作
     compiler.plugin('compilation', compilation => {
         
         compilation.assets['./tjx.txt'] = {
             size:function () {
                 return 'abc'.length;
             },
             source:function () {
               return 'abc'
             }
           }
         
         
         	// 别人编译的入口
             compilation.plugin('html-webpack-plugin-before-html-processing',(htmlData,callback) => {
                 // html-webpack-plugin中间插入行为的地方
                 htmlData.html = htmlData.html.replace(`<div id="app"></div>`,`
                   <div id="app">
                     <div style="background-color:red;height:300px;display:none;" id="default" >
                         我是默认的骨架屏
                     </div>
                     <div style="background-color:red;height:300px;display:none;" id="user" >
                         我是user的骨架屏
                     </div>
                     <div style="background-color:red;height:300px;display:none;" id="login" >
                         我是login的骨架屏
                     </div>
                   </div>
                   <script>
                         var hash = window.location.hash;
                         var path = window.location.pathname;
                         if (path === '/login' || hash === '#/login') {
                           document.getElementById('login').style.display = 'block';
                         } else if (path === '/user' || hash === '#/user') {
                           document.getElementById('user').style.display = 'block';
                         }
                   </script>
                   `);
                 // 不论如何两个参数,错误在前
                 callback(null,htmlData);
   
             });
   
     });
   }
   module.exports = MyPlugin;

在这个项目中,我是参考了饿了么前端的做法,在index.html中实现首页的骨架屏,不同的区域用不同的颜色表示,基本都是以灰色做主调,只是灰度深浅不一样。代码如下

  <div id="app">
    <style>
      #skeleton-screen {
        height: 100vh;
        width: 100vw;
        position: fixed;
        top: 0;
        left: 0;
        background-color: #f3f3f3;
      }

      #skeleton-screen .banner {
        width: 100%;
        height: 4rem;
        position: relative;
        background-color: #EEEEEE;
      }

      #skeleton-screen .avatar {
        position: absolute;
        top: 40%;
        left: 50%;
        transform: translate(-50%, -50%);
        height: 1.5rem;
        width: 1.5rem;
        background-color: #F6F6F6;
        border-radius: 50%;
      }

      #skeleton-screen .options {
        width: 100%;
        height: 1.8rem;
        background-color: #ffffff;
        margin-top: 5px;
        display: flex;
        flex-direction: row;
        align-items: center;
        justify-content: space-around;
      }

      #skeleton-screen .options .item {
        width: 18%;
        height: 70%;
        text-align: center;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
      }

      #skeleton-screen .options .item .inner-item-img {
        width: 80%;
        height: 70%;
        background-color: #F6F6F6;
      }

      #skeleton-screen .options .item .inner-item-title {
        margin-top: 0.2rem;
        width: 100%;
        height: 0.25rem;
        background-color: #EEEEEE;
      }

      #skeleton-screen .notice-banner {
        background-color: #ffffff;
        margin-top: 5px;
        padding-bottom: 0.2rem;
        display: flex;
        flex-direction: column;
        align-items: center;
      }

      #skeleton-screen .notice-banner .title-1 {
        width: 70%;
        background-color: #EEEEEE;
        height: 0.3rem;
        margin: 10px 0;
      }

      #skeleton-screen .notice-banner .title-2 {
        width: 90%;
        background-color: #EEEEEE;
        height: 0.2rem;
        margin: 10px 0;
      }

      #skeleton-screen .notice-banner .img {
        background-color: #F6F6F6;
        width: 90%;
        height: 5rem;
      }
    </style>
    <div id="skeleton-screen">
      <div class="banner">
        <div class="avatar"></div>
      </div>
      <div class="options">
        <div class="item">
          <div class="inner-item-img"></div>
          <div class="inner-item-title"></div>
        </div>
        <div class="item">
          <div class="inner-item-img"></div>
          <div class="inner-item-title"></div>
        </div>
        <div class="item">
          <div class="inner-item-img"></div>
          <div class="inner-item-title"></div>
        </div>
        <div class="item">
          <div class="inner-item-img"></div>
          <div class="inner-item-title"></div>
        </div>
      </div>
      <div class="notice-banner">
        <div class="title-1"></div>
        <div class="img"></div>
        <div class="title-2"></div>
      </div>
    </div>
  </div>

总结

移动端的开发需要考虑的问题有很多。一是需要考虑不同的机型,特别是安卓,国内使用安卓手机的比例占了70%左右,华为有华为的,小米有小米的,这些不同的机型长宽高不一致,各种特性都不一致,所以在样式上需要有所考虑。苹果来来去去也就是那几款手机。二是操作系统上的兼容。目前手机操作系统主要分安卓和苹果的。这2个操作系统上的一些表现还是会有很大的差异,样式风格上也会有所不一样。这里需要注意的是苹果操作系统上还是会有不少的坑,就比如上面提及的input标签type=text不能输入中文的问题,input标签需要长按才能获取焦点等等这些问题。这也是为什么我会去自定义一些组件,而不是完全使用mint-ui这个ui框架的组件,因为你要去修改这些第三方组件库的东西是比较困难的。三是需要考虑用户手机性能的问题。不同的手机性能是不一样的,同一种动画,在一种手机上可能就会表现的很流畅,但是在另一种手机上就会卡顿。所以手机上的动画我不建议做的太过于复杂,有必要的时候可以开启GPU硬件加速,GPU加速不能滥用,否则会引起手机耗电快,容易发热。四是用户体验。现在用手机的大多数是一些年轻人,他们在视觉效果上的追求还是有点高的,要是视觉效果做的不好是很难吸引他们去关注你的应用的。跟用户交互方面,首先要保证响应速度,一般要是超过了5s的响应速度,那么就基本意味着失去了这个用户了。

Vue.js 是一个流行的前端框架,而H5指的是使用HTML5、CSS3和JavaScript技术开发的移动网站。在使用Vue.js进行H5开发时,如果需要集成支付宝手机网站支付,通常需要进行以下步骤: 1. 引入支付宝SDK:首先需要在你的项目中引入支付宝提供的JSAPI支付SDK。你可以通过script标签将其引入到你的HTML页面中。 2. 设置支付参数:在Vue组件的data中定义支付参数,这些参数可能包括订单、支付金额等,需要根据支付宝的要求进行设置。 3. 调用支付宝支付接口:使用支付宝提供的API来初始化支付请求,并在用户触发支付时调用。 4. 处理支付结果:支付宝会返回支付结果,你需要在回调函数中处理这些结果,更新页面上的支付状态。 以下是一个简单的代码实例,展示了如何在Vue组件中集成支付宝支付功能: ```javascript <template> <div> <!-- 支付按钮 --> <button @click="doPayment">支付宝支付</button> </div> </template> <script> export default { name: 'PaymentPage', data() { return { // 支付配置参数 alipayConfig: { out_trade_no: '订单', // 订单 total_amount: '支付金额', // 支付金额,单位为元 subject: '商品名称', // 商品描述 // ... 其他必填参数 } }; }, methods: { // 支付函数 doPayment() { const alipay = new Alipay({ sandbox: true, // 在沙箱环境中测试 appid: 'APPID', // 应用ID // ... 其他配置参数 }); // 调用支付接口 alipay.tradePay({ ...this.alipayConfig, success: (res) => { console.log('支付成功', res); // 处理支付成功逻辑 }, fail: (err) => { console.log('支付失败', err); // 处理支付失败逻辑 } }); } } }; </script> ``` 在上述代码中,我们创建了一个按钮,当点击这个按钮时,会调用`doPayment`方法来执行支付宝的支付流程。`Alipay`是支付宝提供的JavaScript API对象,用于创建支付宝支付实例。你需要根据实际情况填写订单、支付金额等参数,并在支付成功或失败后进行相应的处理。 请注意,上述代码是一个简化的示例,实际开发中需要严格遵循支付宝官方文档的要求来配置SDK和处理支付流程。同时,还需要在支付宝开放平台注册应用并获取相应的APPID和其他安全配置参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值