项目背景:

公司为了实现小程序与H5页面共同覆盖,全面推广。特此想将已有的小程序进行快速改造上线(二周内),研发出H5版本。目前公司前端技术较为薄弱,现有的技术解决方案还停留在JSP。

问题:

如何将目前已经上线运行的原生小程序(40多个页面)快速转化为原生H5页面,实现快速上线,是采用我们较为熟悉的JSP还是引用目前最热门的前后端分离VUE框架呢???

想法:

1)采用熟练的JSP框架,每人一天可以改造2个页面左右,计划投入2人,风险最小;

2)采用主流分布式Vue框架,时间未知,风险未知;

首先自我介绍下,本人是一名JAVA开发工程师,平时喜欢研究相关主流技术和挑战自己。对此我还是比较倾向于第二种解决方案,但是第二种解决方案无疑是最复杂,最耗时,最未知,风险最大。公司内没有人愿意承接。于是我抱着学习和研究的态度以及对主流技术的向往,我找到我们领导我是这样说的:我还是比较建议公司采用第二种方案。1)这无疑是给我们进行敲门砖及学习的机会;2)这是公司提升前端技术能力与主流技术看齐的机会。最后公司同意了我建议,采用方案二,有我来承接此事,进行牵头负责。

中间心酸过程忽略,刚接下来第一天就后悔了,VUE用都没用过,还怎么玩。于是我花了大量的时间,看了大量文献,我这里使用到是Vue 2 + Vant 2 + axios + router。

  (1)VUE官方技术文档:

  https://v2.cn.vuejs.org/v2/guide/

  https://cli.vuejs.org/zh/guide/creating-a-project.html

(2)引用了Vant 2组件:

   https://youzan.github.io/vant/v2/#/zh-CN/toast

(3)同时也参考很多成熟开源VUE框架:

若依(也是从这个项目中进行借鉴与参考):http://doc.ruoyi.vip/ruoyi/

于是我花费了3天时间终于完成了VUE项目框架搭建及第一个小程序页面转H5页面。心想如果是这样的进度,指定时间完成是不可能的了,有没有什么方法可以快速将小程序组件替换成VUE呢,报着这个想法就开干,也是网上找了很多案例都不是很齐全,没办法我只能自己进行编写工具方法,废话不多说之前上干货。

首先要想编写工具方法必须要知道小程序和VUE有哪些特性,以及哪些是等价效果。这里我进行了简单梳理:

页面事件替换:

view 替换 div

image替换img

bindinput=替换v-on:input=

bindtap=替换@click=

<rich-text nodes="{{detail.prizeDetailContent}}"></rich-text>替换<div class="fuwenben" v-html="detail.prizeDetailContent"></div>

Js替换:

e.detail.value替换e.target.value

app.globalData.替換this.$globalData.(globalData这里是需要在main.js定义替换的全局变量)

wx.showLoading({title: "加载中",mask: true,});

替代写法

this.$toast.loading({ message: '加载中...',forbidClick: true, duration: 0,});(这里是引用了Vant 2)

wx.getStorageSync替代写法localStorage.getItem

wx.setStorageSync替代写法localStorage.setItem

wx.navigateTo替换window.location.href=" "

wx.redirectTo替换window.open();

wx.hideLoading();替换this.$toast.clear();(这里是引用了Vant 2)

样式替换:

//100rpx -> 5rem
rpx替换rem(考虑到移动端兼容引入rem计量单位)
等等,我这里不一一列举了。其次介绍下实现步骤及原理:
VUE各个文件目录含义说明:

具体步骤如下:

(1)VUE采用的是单页面设计思路,所有js,html,css都在一个页面内完成,对此我们需要先将小程序指定文件夹下面的内容进行粘贴过来。

(2)进入“replace”目录,将复制完成后的代码,粘贴到“replace.vue” 点击“replaceUtil.js” 右键,在集成终端中打开,运行代码“node .\replaceUtil.js”

以上两步完成绝大部分的小程序转VUE特性功能点,个别较为复杂的可能需要人工进行修改调整。(列入wx.request这些目前我们的写法是人工进行修改改为axios,当然也可以进行二次封装减少改动地方欢迎大家进行尝试,这里注意为了去wx划防止误导,选择了手工修改调整)

具体后台请求接口方面我们采用的axios具体写法如下:

1、 使用axios组件完成后台请求,第一步“service”目录下新建“.js”

2、 引用js。

3、调用方式

以上就是我对VUE转H5相关理解和具体实现思路,欢迎大家进行评论和指导!!!

相关源码如下:

(1)核心替换代码replaceUtil.js

const fs = require("fs");
let fileName = "replace.vue"; // 需要替换字符的文件名 fs.readFile(`${__dirname}/${fileName}`, "utf8", (err, data) => {
console.log(__dirname);
console.log(fileName);
if (err) {
console.log("readFile error");
console.log(err);
} console.log("readFile sussce");
// 替换字符
let rs = changeWxToVue(data, ["label", "rpx", "if", "for", "tap", "labjs"]);
// console.log(rs)
fs.writeFile(`${__dirname}/${fileName}`, rs, "utf8", (err) => {
if (err) {
console.log("writeFile error");
}
});
}); /**
*
* @param {*} data vue文件字符
* @param {*} changeArr 数组格式,需要替换的字符,以数组格式传递;
* ['label']:只替换view、text、block标签
* ['label','rpx']:替换view、text、block标签 和 rpx,rpx的数值需要是基准为750px的标准设计稿,100rpx->50px
* ['for']:for标签替换不包括key,否则正则表达式太长了
* @returns
*/
function changeWxToVue(data, changeArr) {
for (let i = 0; i < changeArr.length; i++) {
if (changeArr[i] == "label") {
// 替换view -> div, text -> span
data = data.replace(/<(\/(view)|view.*)>/g, (a) => {
return a.replace(/view/g, "div");
});
data = data.replace(/<(\/(text)|text.*)>/g, (a) => {
return a.replace(/text/g, "span");
});
data = data.replace(/<(\/(block)|block.*)>/g, (a) => {
return a.replace(/template/g, "span");
});
}
if (changeArr[i] == "rpx") {
// 替换100rpx -> 5rem
data = data.replace(/(\d*)rpx/g, (num) => {
return (parseInt(num) / 20).toFixed(2).toString() + "rem";
});
}
if (changeArr[i] == "if") {
// 替换wx:if -> v-if
data = data.replace(
/(wx:if|wx:elif|wx:else)="{{(((?![-=]).)*)}}"/g,
(a, b, c) => {
console.log(a,b,c); c = c.replace(/(^\s*)|(\s*$)/g, "");
let vue = "";
switch (b) {
case "wx:if":
vue = "v-if";
break;
case "wx:elif":
vue = "v-else-if";
break;
case "wx:else":
vue = "v-else";
break;
}
return `${vue}="${c}"`;
}
);
} if (changeArr[i] == "for") {
// 替换wx:for="{{list}}" wx:for-item="item1" wx:for-index="index1" -> v-for=""
let forRegArr = [
/\swx:for="{{(((?![-=]).)*)}}"([^key].*)wx:for-item="(((?!-).)*)"([^key].*)wx:for-index="(((?![-=]).)*)"/g,
/\swx:for="{{(((?![-=]).)*)}}"([^key].*)wx:for-index="(((?!-).)*)"([^key].*)wx:for-item="(((?![-=]).)*)"/g,
/\swx:for="{{(((?![-=]).)*)}}"/g,
];
data = data.replace(forRegArr[0], (a, b, c, d, e, f, g, h, i, j, k) => {
// console.log('a-',a,'\nb-',b,'\nc-',c,'\nd-',d,'\ne-',e,'\nf-',f,'\ng-',g,'\nh-',h,'\ni-',i,'\nj-',j,'\nk-',k);
if (e) {
if (h) {
return ` v-for="(${e}, ${h}) in ${b}" `;
} else {
return ` v-for="${e} in ${b}" `;
}
}
});
data = data.replace(forRegArr[1], (a, b, c, d, e, f, g, h, i, j, k) => {
// console.log('a-',a,'\nb-',b,'\nc-',c,'\nd-',d,'\ne-',e,'\nf-',f,'\ng-',g,'\nh-',h,'\ni-',i,'\nj-',j,'\nk-',k);
if (h) {
if (e) {
return ` v-for="(${h}, ${e}) in ${b}" `;
} else {
return ` v-for="${h} in ${b}" `;
}
}
});
data = data.replace(forRegArr[2], (a, b) => {
return ` v-for="item in ${b}" `;
});
}
if (changeArr[i] == "tap") {
// bindtap || catchtap -> @click
data = data.replace(
/(bindtap|bind:tap|catchtap)="(((?!-).)*)"/g,
(a, b, c) => {
return `@click="${c}"`;
}
); // bindinput -> v-on:input=
data = data.replace(/(bindinput)="(((?!-).)*)"/g, (a, b, c) => {
return `v-on:input="${c}"`;
});
}
if (changeArr[i] == "data") {
// data-index="{{index}}" -> data-index="index"
data = data.replace(
/data-(((?!-).)*)="{{(((?!-).)*)}}"/g,
(a, b, c, d) => {
return `data-${b}="${d}"`;
}
);
}
if (changeArr[i] == "labjs") {
// e.detail.value -> e.target.value
data = data.replace(/e.detail.value/g, "e.target.value");
// app.globalData. -> this.$globalData.
data = data.replace(/app.globalData./g, "this.$globalData.");
// wx.getStorageSync -> localStorage.getItem
data = data.replace(/wx.getStorageSync/g, "localStorage.getItem");
// wx.setStorageSync -> localStorage.setItem
data = data.replace(/wx.setStorageSync/g, "localStorage.setItem");
// wx.hideLoading -> localStorage.setItem
data = data.replace(/wx.setStorageSync/g, "localStorage.setItem");
// wx.hideLoading -> this.$toast.clear
data = data.replace(/wx.hideLoading/g, "this.$toast.clear"); data = data.replace(/wx:key=\"\*this\"/g, "");
data = data.replace(
/wx:for=["|']\s*\{\{([^\}]+)\}\}\s*["|']/g,
($0, $1) => 'v-for="(item, index) in ' + $1 + '"'
);
data = data.replace(
/wx:for-items=["|']\s*\{\{([^\}]+)\}\}\s*["|']/g,
($0, $1) => 'v-for="(item, index) in ' + $1 + '"'
);
data = data.replace(
/wx:key=["|']([^"|']+)["|']/g,
($0, $1) => ':key="' + $1 + '"'
);
// if
data = data.replace(
/wx:if=["|']\s*\{\{([^\}]+)\}\}\s*["|']/g,
($0, $1) => 'v-if="' + $1 + '"'
);
// elif
data = data.replace(
/wx:elif=["|']\s*\{\{([^\}]+)\}\}\s*["|']/g,
($0, $1) => 'v-else-if="' + $1 + '"'
);
// else
data = data.replace(/wx:else/g, "v-else"); data = data.replace(/<view/g, "<div");
data = data.replace(/\/view>/g, "/div>");
data = data.replace(/<text/g, "<span");
data = data.replace(/\/text>/g, "/text>");
data = data.replace(/<image([^>]+)/g, ($0, $1) => "<img " + $1 + "/");
data = data.replace(/<input([^>]+)/g, ($0, $1) => "<input " + $1 + "/"); data = data.replace(/<\/image>/g, "");
data = data.replace(/<\/input>/g, "");
data = data.replace(
/<icon([^>]+)/g,
($0, $1) => '<i style="display:inline-block" ' + $1 + "/>"
);
data = data.replace(
/bind([^=|\s]+)=["|']([^"|'|\s]+)["|']/g,
($0, $1, $2) => "@" + $1 + '="' + $2 + '"'
);
data = data.replace(/navigator/g, "router-link");
data = data.replace(/\"\/images/g, '"../../assets');
data = data.replace(/this.data./g, "this.");
data = data.replace(/that.data./g, "this.");
data = data.replace(/..\/..\/utils\/wxml\/common.wxml/g, "../../utils/vue/common.vue");
data = data.replace(/..\/..\/utils\/wxss\/common.wxss/g, "../../utils/css/common.css"); // 变量
// data = data.replace(/data-([^=|\s]+)=["|']\{\{([^\}]+)\}\}["|']/g, ($0,$1,$2)=> ':data-'+$1+'="'+$2+'"')
data = data.replace(
/([^\s|=]+)=["|']\{\{([^\}]+)\}\}["|']/g,
($0, $1, $2) => ":" + $1 + '="' + $2 + '"'
); // 变量轮播图替换
data = data.replace(/<swiper-item/g, "<van-swipe-item");
data = data.replace(/\/swiper-item>/g, "/van-swipe-item>");
data = data.replace(/<swiper/g, "<van-swipe");
data = data.replace(/\/swiper>/g, "/van-swipe>");
data = data.replace(/:autoplay=\"autoplay\"/g, ":autoplay=\"interval\""); }
}
return data;
}

(2)axios.js:

/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
import axios from "axios";
import { Toast } from "vant";
import router from "../router";
import globalData from "../utils/global.js";
import qs from 'qs'; axios.defaults.baseURL = '';
axios.defaults.timeout = 30000;
axios.defaults.withCredentials = true;
axios.defaults.headers["X-Requested-With"] = "XMLHttpRequest";
axios.defaults.headers["token"] = localStorage.getItem("token") || "";
axios.defaults.headers.post["Content-Type"] =
"application/x-www-form-urlencoded;charset=UTF-8"; // 请求拦截器
axios.interceptors.request.use(
(config) => {
// config 请求的所有信息
// console.log(config);
// 设置请求头
if (config.method === "post" && !!config.data && config.data !== "") {
config.headers = {
Accept: "*/*",
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
};
if(config.url === '/pages/sri/order/uploadImg'){
config.headers["Content-Type"] = "multipart/form-data"
} else {
config.data = qs.stringify(config.data, {arrayFormat:'comma'})
}
} // if (config.method === "put" && !!config.params && config.params !== "") {
// config.headers = {
// Accept: "*/*",
// "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
// };
// } // if (config.method === "delete") {
// if (!!config.params && !!config.params.data) {
// config.headers = {
// Accept: "*/*",
// "Content-Type": "application/json;charset=UTF-8",
// };
// config.data = config.params;
// config.params = "";
// }
// } return config; // 将配置完成的config对象返回出去 如果不返回 请求讲不会进行
},
(err) => {
// 请求发生错误时的相关处理 抛出错误
console.log("服务端请求异常!");
return Promise.reject(err);
}
); // 响应拦截器
axios.interceptors.response.use(
(res) => {
return res;
},
(err) => {
console.log("服务端响应异常!");
return Promise.reject(err);
}
); export default axios;
const fs = require("fs");
let fileName = "replace.vue"; // 需要替换字符的文件名
fs.readFile(`${__dirname}/${fileName}`, "utf8", (err, data) => {
  console.log(__dirname);
  console.log(fileName);
  if (err) {
    console.log("readFile error");
    console.log(err);
  }
  console.log("readFile sussce");
  // 替换字符
  let rs = changeWxToVue(data, ["label", "rpx", "if", "for", "tap", "labjs"]);
  // console.log(rs)
  fs.writeFile(`${__dirname}/${fileName}`, rs, "utf8", (err) => {
    if (err) {
      console.log("writeFile error");
    }
  });
});
/**
 *
 * @param{*}data vue文件字符
 * @param{*}changeArr 数组格式,需要替换的字符,以数组格式传递;
 * ['label']:只替换view、text、block标签
 * ['label','rpx']:替换view、text、block标签 和 rpx,rpx的数值需要是基准为750px的标准设计稿,100rpx->50px
 * ['for']:for标签替换不包括key,否则正则表达式太长了
 * @returns
 */
function changeWxToVue(data, changeArr) {
  for (let i = 0; i < changeArr.length; i++) {
    if (changeArr[i] == "label") {
      // 替换view -> div, text -> span
      data = data.replace(/<(\/(view)|view.*)>/g, (a) => {
        return a.replace(/view/g, "div");
      });
      data = data.replace(/<(\/(text)|text.*)>/g, (a) => {
        return a.replace(/text/g, "span");
      });
      data = data.replace(/<(\/(block)|block.*)>/g, (a) => {
        return a.replace(/template/g, "span");
      });
    }
    if (changeArr[i] == "rpx") {
      // 替换100rpx -> 5rem
      data = data.replace(/(\d*)rpx/g, (num) => {
        return (parseInt(num) / 20).toFixed(2).toString() + "rem";
      });
    }
    if (changeArr[i] == "if") {
      // 替换wx:if -> v-if
      data = data.replace(
        /(wx:if|wx:elif|wx:else)="{{(((?![-=]).)*)}}"/g,
        (a, b, c) => {
          console.log(a,b,c);
          c = c.replace(/(^\s*)|(\s*$)/g, "");
          let vue = "";
          switch (b) {
            case "wx:if":
              vue = "v-if";
              break;
            case "wx:elif":
              vue = "v-else-if";
              break;
            case "wx:else":
              vue = "v-else";
              break;
          }
          return `${vue}="${c}"`;
        }
      );
    }
    if (changeArr[i] == "for") {
      // 替换wx:for="{{list}}" wx:for-item="item1" wx:for-index="index1" -> v-for=""
      let forRegArr = [
        /\swx:for="{{(((?![-=]).)*)}}"([^key].*)wx:for-item="(((?!-).)*)"([^key].*)wx:for-index="(((?![-=]).)*)"/g,
        /\swx:for="{{(((?![-=]).)*)}}"([^key].*)wx:for-index="(((?!-).)*)"([^key].*)wx:for-item="(((?![-=]).)*)"/g,
        /\swx:for="{{(((?![-=]).)*)}}"/g,
      ];
      data = data.replace(forRegArr[0], (a, b, c, d, e, f, g, h, i, j, k) => {
        // console.log('a-',a,'\nb-',b,'\nc-',c,'\nd-',d,'\ne-',e,'\nf-',f,'\ng-',g,'\nh-',h,'\ni-',i,'\nj-',j,'\nk-',k);
        if (e) {
          if (h) {
            return ` v-for="(${e}, ${h}) in ${b}" `;
          } else {
            return ` v-for="${e} in ${b}" `;
          }
        }
      });
      data = data.replace(forRegArr[1], (a, b, c, d, e, f, g, h, i, j, k) => {
        // console.log('a-',a,'\nb-',b,'\nc-',c,'\nd-',d,'\ne-',e,'\nf-',f,'\ng-',g,'\nh-',h,'\ni-',i,'\nj-',j,'\nk-',k);
        if (h) {
          if (e) {
            return ` v-for="(${h}, ${e}) in ${b}" `;
          } else {
            return ` v-for="${h} in ${b}" `;
          }
        }
      });
      data = data.replace(forRegArr[2], (a, b) => {
        return ` v-for="item in ${b}" `;
      });
    }
    if (changeArr[i] == "tap") {
      // bindtap || catchtap -> @click
      data = data.replace(
        /(bindtap|bind:tap|catchtap)="(((?!-).)*)"/g,
        (a, b, c) => {
          return `@click="${c}"`;
        }
      );
      // bindinput -> v-on:input=
      data = data.replace(/(bindinput)="(((?!-).)*)"/g, (a, b, c) => {
        return `v-on:input="${c}"`;
      });
    }
    if (changeArr[i] == "data") {
      // data-index="{{index}}" -> data-index="index"
      data = data.replace(
        /data-(((?!-).)*)="{{(((?!-).)*)}}"/g,
        (a, b, c, d) => {
          return `data-${b}="${d}"`;
        }
      );
    }
    if (changeArr[i] == "labjs") {
      // e.detail.value -> e.target.value
      data = data.replace(/e.detail.value/g, "e.target.value");
      // app.globalData. -> this.$globalData.
      data = data.replace(/app.globalData./g, "this.$globalData.");
      // wx.getStorageSync -> localStorage.getItem
      data = data.replace(/wx.getStorageSync/g, "localStorage.getItem");
      // wx.setStorageSync -> localStorage.setItem
      data = data.replace(/wx.setStorageSync/g, "localStorage.setItem");
      //  wx.hideLoading -> localStorage.setItem
      data = data.replace(/wx.setStorageSync/g, "localStorage.setItem");
      //  wx.hideLoading -> this.$toast.clear
      data = data.replace(/wx.hideLoading/g, "this.$toast.clear");
      data = data.replace(/wx:key=\"\*this\"/g, "");
      data = data.replace(
        /wx:for=["|']\s*\{\{([^\}]+)\}\}\s*["|']/g,
        ($0, $1) => 'v-for="(item, index) in ' + $1 + '"'
      );
      data = data.replace(
        /wx:for-items=["|']\s*\{\{([^\}]+)\}\}\s*["|']/g,
        ($0, $1) => 'v-for="(item, index) in ' + $1 + '"'
      );
      data = data.replace(
        /wx:key=["|']([^"|']+)["|']/g,
        ($0, $1) => ':key="' + $1 + '"'
      );
      // if
      data = data.replace(
        /wx:if=["|']\s*\{\{([^\}]+)\}\}\s*["|']/g,
        ($0, $1) => 'v-if="' + $1 + '"'
      );
       // elif
       data = data.replace(
        /wx:elif=["|']\s*\{\{([^\}]+)\}\}\s*["|']/g,
        ($0, $1) => 'v-else-if="' + $1 + '"'
      );
       // else
       data = data.replace(/wx:else/g, "v-else");
      data = data.replace(/<view/g, "<div");
      data = data.replace(/\/view>/g, "/div>");
      data = data.replace(/<text/g, "<span");
      data = data.replace(/\/text>/g, "/text>");
      data = data.replace(/<image([^>]+)/g, ($0, $1) => "<img " + $1 + "/");
      data = data.replace(/<input([^>]+)/g, ($0, $1) => "<input " + $1 + "/");
      data = data.replace(/<\/image>/g, "");
      data = data.replace(/<\/input>/g, "");
      data = data.replace(
        /<icon([^>]+)/g,
        ($0, $1) => '<i style="display:inline-block" ' + $1 + "/>"
      );
      data = data.replace(
        /bind([^=|\s]+)=["|']([^"|'|\s]+)["|']/g,
        ($0, $1, $2) => "@" + $1 + '="' + $2 + '"'
      );
      data = data.replace(/navigator/g, "router-link");
      data = data.replace(/\"\/images/g, '"../../assets');
      data = data.replace(/this.data./g, "this.");
      data = data.replace(/that.data./g, "this.");
      data = data.replace(/..\/..\/utils\/wxml\/common.wxml/g, "../../utils/vue/common.vue");
      data = data.replace(/..\/..\/utils\/wxss\/common.wxss/g, "../../utils/css/common.css");
            // 变量
      // data = data.replace(/data-([^=|\s]+)=["|']\{\{([^\}]+)\}\}["|']/g, ($0,$1,$2)=> ':data-'+$1+'="'+$2+'"')
      data = data.replace(
        /([^\s|=]+)=["|']\{\{([^\}]+)\}\}["|']/g,
        ($0, $1, $2) => ":" + $1 + '="' + $2 + '"'
      );
      // 变量轮播图替换
      data = data.replace(/<swiper-item/g, "<van-swipe-item");
      data = data.replace(/\/swiper-item>/g, "/van-swipe-item>");
      data = data.replace(/<swiper/g, "<van-swipe");
      data = data.replace(/\/swiper>/g, "/van-swipe>");
      data = data.replace(/:autoplay=\"autoplay\"/g, ":autoplay=\"interval\"");
    }
  }
  return data;
}
 

如何将原生微信小程序页面改成原生VUE框架的H5页面的更多相关文章

  1. 微信小程序学习笔记(二)--框架-全局及页面配置

    描述和功能 框架提供了自己的视图层描述语言 WXML 和 WXSS,以及基于 JavaScript 的逻辑层框架,并在视图层与逻辑层间提供了数据传输和事件系统,让开发者能够专注于数据与逻辑. 响应的数 ...

  2. 微信小程序-06-详解介绍.js 逻辑层文件-注册页面

    上一篇介绍的是 app.js 逻辑层文件中注册程序,对应的每个分页面都会有的 js 文件中 page() 函数注册页面 微信小程序-06-详解介绍.js 逻辑层文件-注册页面 宝典官方文档: http ...

  3. 第一章 “我要点爆”微信小程序云开发之项目建立与我的页面功能实现

    第一章 “我要点爆”微信小程序云开发之项目建立与我的页面功能实现 开发环境搭建 使用自己的AppID新建小程序项目,后端服务选择小程序·云开发,点击新建,完成项目新建. 新建成功后跳转到开发者工具界面 ...

  4. 微信小程序从零开始开发步骤(六)4种页面跳转的方法

    用法:用于页面跳转,相当于html里面的<a></a>标签. API教程:https://mp.weixin.qq.com/debug/wxadoc/dev/component ...

  5. Taro -- 原生微信小程序转taro

    微信小程序转Taro  (转发https://nervjs.github.io/taro/docs/taroize.html) Taro 可以将你的原生微信小程序应用转换为 Taro 代码,进而你可以 ...

  6. 微信小程序裁剪图片成圆形

    代码地址如下:http://www.demodashi.com/demo/14453.html 前言 最近在开发小程序,产品经理提了一个需求,要求微信小程序换头像,用户剪裁图片必须是圆形,也在gith ...

  7. 原生微信小程序数据渲染

    一直在写vue,第一次接触微信小程序,还是原生,最开始做的时候真的很闹心啊啊啊啊啊啊啊啊啊啊啊啊!!所以最近大概更新的都是微信小程序原生的内容了~~么么哒!!一定会继续努力的!!tips:在小程序项目 ...

  8. 如何在原生微信小程序中实现数据双向绑定

    官网:https://qiu8310.github.io/minapp/ 作者:Mora 在原生小程序开发中,数据流是单向的,无法双向绑定,但是要实现双向绑定的功能还是蛮简单的! 下文要讲的是小程序框 ...

  9. 微信小程序苹果手机调用camera原生组件拍照后不退出

    最近做微信小程序时,用到小程序的原生组件camera时,踩到一个bug. 在给camera设置样式position:absolute;绝对定位后,IOS调用camera原生组件拍照后退不出来. 不使用 ...

随机推荐

  1. go程序添加远程调用tcpdump功能

    最近开发的telemetry采集系统上线了.听起来高大上,简单来说就是一个grpc/udp服务端,用户的机器(路由器.交换机)将它们的各种统计数据上报采集.整理后交后端的各类AI分析系统分析.目前华为 ...

  2. HDLBits->Circuits->Multiplexers->Mux256to1v

    Verilog切片语法 题目要求如下 Create a 4-bit wide, 256-to-1 multiplexer. The 256 4-bit inputs are all packed in ...

  3. SAP Using Text Modules in Adobe Forms

    In this demo we will create an adobe form which displays text in two different languages (English or ...

  4. 基于springBoot项目如何配置多数据源

    前言 有时,在一个项目中会用到多数据源,现在对自己在项目中多数据源的操作总结如下,有不到之处敬请批评指正! 1.pom.xml的依赖引入 <dependency> <groupId& ...

  5. HTML入门,基础知识

    初识HTML HTML: 超文本标记语言 一.HTML的基本结构 根控制标记(头) ​ 头控制标记(头) ​ 标题 标题标记 ​ 头控制标记(尾) ​ 网页显示区域(一般要实现的代码都在这里写) &l ...

  6. GaussDB(for MySQL) :Partial Result Cache,通过缓存中间结果对算子进行加速

    摘要:华为云数据库高级内核技术专家详解GaussDB(for MySQL)Partial Result Cache特性,如何通过缓存中间结果对算子进行加速? 本文分享自华为云社区<GaussDB ...

  7. 零基础学Java(1)初识Java程序

    前言 就国内来说,Java毫无疑问是后端语言中的No.1没有之一,所以今天我们也来0基础学习Java!!! Java的好处(针对测试工程师) 面试加分->涨薪 大多数公司服务端用的都是Java, ...

  8. 深入浅出理解SVM支持向量机算法

      支持向量机是Vapnik等人于1995年首先提出的,它是基于VC维理论和结构风险最小化原则的学习机器.它在解决小样本.非线性和高维模式识别问题中表现出许多特有的优势,并在一定程度上克服了" ...

  9. 微信小程序接口请求/form-data/单文件、多文件上传

    1.普通的微信请求封装 1 const http = (options) =>{ 2 return new Promise((resolve,reject) => { 3 wx.reque ...

  10. docker多段构建nessus镜像

    1.构建基础镜像,主要做安装和获取注册号: FROM ubuntu:16.04 ADD Nessus-8.11.0-debian6_amd64.deb /tmp/Nessus-8.11.0-debia ...