zhangdaren
zhangdaren
  • 发布:2019-06-20 15:23
  • 更新:2024-03-29 21:03
  • 阅读:73086

miniprogram-to-uniapp使用指南(各种小程序项目转换为uni-app项目)

分类:uni-app

工具现在支持npm全局库、HBuilderX插件两种方式使用,任君选择,HBuilderX插件地址:https://ext.dcloud.net.cn/plugin?id=2656

一、它是谁?

【miniprogram-to-uniapp】转换微信小程序”项目为uni-app项目(新版本工具已经支持各种小程序转换)。

二、它的原理是什么?

最初是学了半节课堆和栈,觉得词法分析挺有意思的,再加上转换小程序插件时,发现这些繁琐的操作完全可以使用程序来完成。
核心是使用Babel获取AST(词法分析),然后或使用Babel自带函数增删,或正则分析替换等等操作。
可能有的朋友觉得,这种为啥不是纯正则分析? 纯正则可以解决一部分问题,对于标签与标签内容,其实正则是很难进行区分的哈。

三、它能做哪些事情?

  • 支持微信、QQ、头条/抖音、支付宝/钉钉和百度等小程序转换到 uni-app 项目
  • 支持有/无云开发的小程序项目转换为 uni-app 项目(cloudfunctions 目录将被忽略,uni-app 结合小程序云开发见:使用 uni-app 进行微信小程序云开发经验分享)
  • 支持解析 TypeScript 小程序项目
  • 支持解析使用 npm 模块的小程序项目
  • 支持解析 include 标签
  • 支持解析 template 标签
  • 支持解析 Behavior 文件为 mixins 文件
  • 支持.js', .wxml 和*.wxss 文件进行相应转换,并做了大量的优化
  • 支持识别 App、Page、Component、VantComponent、Behavior 和纯 Javascript 文件的转换
  • 修复变量名与函数重名的情况
  • 合并使用 require 导入的 wxs 文件
  • setData() polyfill
  • 搜索未在 data 声明,而直接在 setData()里使用的变量,并修复
  • 使用jyf-parser替换 wxParse(感谢网友 “爱瑞巴勒康忙北鼻” 的建议)
  • 因 uni-app 会将所有非 static 目录的资源文件删除,因此将所有资源文件移入 static 目录,并修复所有能修复到的路径(目前 uni 编译时会将非 static 目录的文件复制一份到 static 目录,但并不完全,因此本功能仍保留)

四、它还有哪些不支持转换?

  • 不支持转换反编译后的小程序项目
  • 不支持转换使用 uni-app 编译的小程序项目
  • 不支持转换使用 redux 开发的小程序(代表为:网易云信小程序 DEMO)
  • 不支持转换使用 wxpage 开发的小程序(https://github.com/tvfe/wxpage)
  • 不支持转换使用腾讯 omi 开发的小程序(https://github.com/Tencent/omi)
  • 不支持转换小程序抽象节点 componentGenerics
  • 不支持 component 里的 pageLifetimes 生命周期,请手动绕过
  • 不支持使用 js 系统关键字作为函数或变量名(如 default、import、return、switch 等)
  • 不支持以\$开头的变量名称,如 Page({data:{$data:{name:"hello"}}}) ,刚好\$data 是 vue 内置变量,so 不支持,需手动修复
  • 不支持以动态绑定的函数<input @input="test{{index+1}}">,需手动修复
  • 更多,请参照miniprogram to uniapp 工具答疑

五、怎么使用?

第一步

在命令行里,运行【 npm install miniprogram-to-uniapp -g 】进行安装,因为这个包是工具,要求全局都能使用,所以需要-g进行全局安装。
如果运行npm报错,请先安装Node.js,下载地址:https://nodejs.org/zh-cn/

第二步

继续在命令行里,运行【 wtu -V 】,执行结果如下:

显示版本号,说明已经安装成功了。(wtu -> 取自wx to uni之意,后面都用这个全局命令)

第三步

在命令行里,输入【wtu -i "你的小程序项目路径"】
注意 -i 前面和后面都有空格!!!
注意 -i 前面和后面都有空格!!!
注意 -i 前面和后面都有空格!!!
如:【wtu -i "E:\zpWork\Project_self\miniprogram-to-uniapp\test\test-wx-to-uni"】 ,回车后即可以在源项目同及目录得到一个后缀为_uni的目录,即转换成功。

转换前:

转换后:

转换后的项目文件对比(左边是小程序项目,右边是Uni-app项目目录):

第四步

将转换后的xxx_uni项目导入到hbuilder X,
点击菜单 运行--> 运行到小程序模拟器-->微信开发者工具!(如果是使用了vant的项目,请运行到H5,vant项目转换后仅支持H5和app)
点击菜单 运行--> 运行到小程序模拟器-->微信开发者工具!(如果是使用了vant的项目,请运行到H5,vant项目转换后仅支持H5和app)
点击菜单 运行--> 运行到小程序模拟器-->微信开发者工具!(如果是使用了vant的项目,请运行到H5,vant项目转换后仅支持H5和app)
重要的话说三遍!
然后查看转换后的项目运行到小程序,是否可以正常运行无报错!
(因为这种转换非100%,所以至少需要保证 小程序-->uniapp-->小程序仍然能正常运行,再考虑运行到其他小程序或app),
如有报错,请根据miniprogram to uniapp 工具答疑 进行修改,保证无报错,然后再运行到其他平台。

工具升级

因为工具更新比较频繁,安装后,可以使用如下命令进行升级:
npm update miniprogram-to-uniapp -g

注意:

  1. 遇到问题请参考文档:miniprogram to uniapp 工具答疑
  2. github上面的只是源代码。 日常使用,"仅"需要运行【 npm install miniprogram-to-uniapp -g 】进行安装才行,无需下载工具源码。
  3. 每次转换时都会将输出目录清空,请注意代码保存。
  4. 后续会有版本更新,请及时关注并更新~~,可以关注QQ群:780359397 获取最新信息

对于使用有疑问或建议,可以加入QQ群:780359397 进行讨论。

<a target="_blank" href="http://shang.qq.com/wpa/qunwpa?idkey=6cccd111e447ed70ee0c17672a452bf71e7e62cfa6b427bbd746df2d32297b64"><img border="0" src="http://pub.idqqimg.com/wpa/images/group.png" alt="小程序转uni-app讨论群" title="小程序转uni-app讨论群"></a>

因为有朋友使用本工具导致自己文件被删,在此表示抱歉!

this.setData()代码出处:https://ask.dcloud.net.cn/article/35020,在些表示感谢~

转换工具源码:https://github.com/zhangdaren/miniprogram-to-uniapp ,欢迎star和建议~

如有遇到bug或问题,欢迎评论、给出改进建议,感谢~~

21 关注 分享
z***@qq.com m***@gmail.com 7***@qq.com orageBeardApe 邓琪昌 bzliukai 我要 撇横横 8***@qq.com g***@126.com DigitalYu jinjidecj ai666 9***@qq.com heck b***@126.com 2***@qq.com Dlog_帅 灯下等雪 aliang888 876

要回复文章请先登录注册

zhangdaren

zhangdaren (作者)

回复 4***@qq.com :
格式不对?应该是哪样?你这个应该是使用了vant,是的,vant转换就是这么个样子。仅支持h5和app。感谢使用和支持。
2020-04-29 09:39
4***@qq.com

4***@qq.com

转出的格式不对呀,Page是个啥呢
<template>
<!--index.wxml-->
<view class="container">
<view class="bg-sear">
<view class="scrolltop">
<view class="section" @tap="toSearchPage">
<image src="/static/images/icon/search.png" class="search-img"></image>
<text class="placeholder">搜索</text>
</view>
</view>
</view>

<view class="content">
<!-- swiper -->
<swiper :autoplay="autoplay" :indicator-color="indicatorColor" :interval="interval" :duration="duration" :indicator-active-color="indicatorActiveColor" circular="true" class="pic-swiper" indicator-dots previous-margin="20rpx" next-margin="20rpx">
<block v-for="(item, index) in indexImgs" :key="index">
<swiper-item class="banner-item">
<view class="img-box">
<image :src="item.imgUrl" :data-prodid="item.relation" @tap="toProdPage" class="banner"></image>
</view>
</swiper-item>
</block>
</swiper>
<!-- end swiper -->

<view class="cat-item">
<view class="item" @tap="toClassifyPage" data-sts="1">
<image src="/static/images/icon/newProd.png"></image>
<text>新品推荐</text>
</view>
<view class="item" @tap="toClassifyPage" data-sts="2">
<image src="/static/images/icon/timePrice.png"></image>
<text>限时特惠</text>
</view>
<view class="item" @tap="toClassifyPage" data-sts="3">
<image src="/static/images/icon/neweveryday.png"></image>
<text>每日疯抢</text>
</view>
<view class="item" @tap="toCouponCenter">
<image src="/static/images/icon/newprods.png"></image>
<text>领优惠券</text>
</view>
</view>

<!-- 消息播放 -->
<view class="message-play" @tap="onNewsPage">
<image src="/static/images/icon/horn.png" class="hornpng"></image>
<swiper vertical="true" autoplay="true" duration="1000" class="swiper-cont">
<block v-for="(item, index) in news" :key="index">
<swiper-item class="items">{{item.title}}</swiper-item>
</block>
</swiper>
<text class="arrow"></text>
</view>

</view>

<block v-for="(item, id) in taglist" :key="id">
<!-- 每日上新 -->
<view class="up-to-date" v-if="item.style==2">
<view class="title">
<text>{{item.title}}</text>
<view class="more-prod-cont" @tap="toClassifyPage" data-sts="0" :data-id="item.id" :data-title="item.title">
<text class="more">查看更多</text>
<!-- <text class='arrow'></text> -->
</view>
</view>
<view class="item-cont">
<block v-for="(prod, prodId) in item.prods" :key="prodId">
<view class="prod-item" @tap="toProdPage" :data-prodid="prod.prodId">
<view>
<view class="imagecont">
<image :src="prod.pic" class="prodimg"></image>
</view>
<view class="prod-text">{{prod.prodName}}</view>
<view class="price">
<text class="symbol">¥</text>
<text class="big-num">{{wxs.parsePrice(prod.price)[0]}}</text>
<text class="small-num">.{{wxs.parsePrice(prod.price)[1]}}</text>
</view>
</view>
</view>
</block>

</view>
</view>

<!-- 商城热卖 -->
<view class="hot-sale" v-if="item.style==1">
<view class="title">
<text>{{item.title}}</text>
<view class="more-prod-cont" @tap="toClassifyPage" data-sts="0" :data-id="item.id" :data-title="item.title">
<text class="more">更多</text>
<text class="arrow"></text>
</view>
</view>
<view class="hotsale-item-cont">
<block v-for="(prod, prodId) in item.prods" :key="prodId">
<view class="prod-items" @tap="toProdPage" :data-prodid="prod.prodId">
<view class="hot-imagecont">
<image :src="prod.pic" class="hotsaleimg"></image>
</view>
<view class="hot-text">
<view class="hotprod-text">{{prod.prodName}}</view>
<view class="prod-info">{{prod.brief}}</view>
<view class="prod-text-info">
<view class="price">
<text class="symbol">¥</text>
<text class="big-num">{{wxs.parsePrice(prod.price)[0]}}</text>
<text class="small-num">.{{wxs.parsePrice(prod.price)[1]}}</text>
</view>
<!-- <view class='singal-price'>
<text>¥</text>
<text>{{prod.oriPrice}}</text>
</view> -->
<image src="/static/images/tabbar/basket-sel.png" class="basket-img"></image>
</view>
</view>
</view>
</block>
</view>
</view>

<!-- 更多宝贝 -->
<view class="more-prod" v-if="item.style==0">
<view class="title">{{item.title}}</view>
<view class="prod-show">
<block v-for="(prod, prodId) in item.prods" :key="prodId">
<view class="show-item" @tap="toProdPage" :data-prodid="prod.prodId">
<view class="more-prod-pic">
<image :src="prod.pic" class="more-pic"></image>
</view>
<view class="prod-text-right">
<view class="prod-text more">{{prod.prodName}}</view>
<view class="prod-info">{{prod.brief}}</view>
<view class="b-cart">
<view class="price">
<text class="symbol">¥</text>
<text class="big-num">{{wxs.parsePrice(prod.price)[0]}}</text>
<text class="small-num">.{{wxs.parsePrice(prod.price)[1]}}</text>
</view>
<!-- <view class='go-to-buy'>立即购买</view> -->
<image src="/static/images/tabbar/basket-sel.png" class="basket-img"></image>
</view>
</view>
</view>
</block>
</view>
</view>
</block>
</view>
</template>

<script module="wxs" lang="wxs" src="../../wxs/number.wxs"></script>


<script>

global['__wxRoute'] = 'pages/index/index';
//index.js
//获取应用实例
var http = require("../../utils/http.js");
var config = require("../../utils/config.js");
const app = getApp()

Page({
data: {
indicatorDots: true,
indicatorColor: '#d1e5fb',
indicatorActiveColor: '#1b7dec',
autoplay: true,
interval: 2000,
duration: 1000,
indexImgs: [],
seq: 0,
news: [],
taglist: [],
sts: 0,
},
//事件处理函数
bindViewTap: function() {
wx.navigateTo({
url: '../logs/logs'
})
},
onLoad: function() {
this.getAllData();

},

// 页面滚动到指定位置指定元素固定在顶部
onPageScroll: function(e) { //监听页面滚动
this.setData({
scrollTop: e.scrollTop
})
},

toProdPage: function(e) {
var prodid = e.currentTarget.dataset.prodid;
if (prodid) {
wx.navigateTo({
url: '/pages/prod/prod?prodid=' + prodid,
})
}
},

toCouponCenter: function() {
wx.showToast({
icon:"none",
title: '该功能未开源'
})
},

// 跳转搜索页
toSearchPage: function() {
wx.navigateTo({
url: '/pages/search-page/search-page',
})
},

//跳转商品活动页面
toClassifyPage: function(e) {
var url = '/pages/prod-classify/prod-classify?sts=' + e.currentTarget.dataset.sts;
var id = e.currentTarget.dataset.id;
var title = e.currentTarget.dataset.title;
if (id) {
url += "&tagid=" + id + "&title=" + title;
}
wx.navigateTo({
url: url
})
},

//跳转公告列表页面
onNewsPage: function() {
wx.navigateTo({
url: '/pages/recent-news/recent-news',
})
},

onShow: function() {
wx.getSetting({
success(res) {
if (!res.authSetting['scope.userInfo']) {
wx.navigateTo({
url: '/pages/login/login',
})
}
}
})


},
getAllData() {
http.getCartCount(); //重新计算购物车总数量
this.getIndexImgs();
this.getNoticeList();
this.getTag();
},
//加载轮播图
getIndexImgs() {
//加载轮播图
var params = {
url: "/indexImgs",
method: "GET",
data: {},
callBack: (res) => {
this.setData({
indexImgs: res,
seq: res
});
}
};
http.request(params);
},
getNoticeList() {
// 加载公告
var params = {
url: "/shop/notice/topNoticeList",
method: "GET",
data: {},
callBack: (res) => {
this.setData({
news: res,
});
}
};
http.request(params);
},


// 加载商品标题分组列表
getTag() {
var params = {
url: "/prod/tag/prodTagList",
method: "GET",
data: {},
callBack: (res) => {
this.setData({
taglist: res,
});
for (var i = 0; i < res.length; i++) {
this.getTagProd(res[i].id, i);
}
}
};
http.request(params);
},

getTagProd(id, index) {
var param = {
url: "/prod/prodListByTagId",
method: "GET",
data: {
tagId: id,
size: 6
},
callBack: (res) => {
var taglist = this.data.taglist;
taglist[index].prods = res.records

this.setData({
taglist: taglist,
});
}
};
http.request(param);
},

/**
* 页面相关事件处理函数--监听用户下拉动作
*/
// onPullDownRefresh: function () {
// wx.request({
// url: '',
// data: {},
// method: 'GET',
// success: function (res) { },
// fail: function (res) { },
// complete: function (res) {
// wx.stopPullDownRefresh();
// }
// })
// },

onPullDownRefresh: function() {

// wx.showNavigationBarLoading() //在标题栏中显示加载

//模拟加载
var ths = this;
setTimeout(function() {

ths.getAllData();

// wx.hideNavigationBarLoading() //完成停止加载

wx.stopPullDownRefresh() //停止下拉刷新

}, 100);

},

/**
* 跳转至商品详情
*/
showProdInfo: function(e) {
let relation = e.currentTarget.dataset.relation;
if (relation) {
wx.navigateTo({
url: 'pages/prod/prod',
})
}
}
})
export default global['__wxComponents']['pages/index/index'];
</script>
<style>
@import "./index.css";
</style>
2020-04-22 18:05
zhangdaren

zhangdaren (作者)

回复 7***@qq.com :
工具为Npm全局包,依赖node,所以mac和windows都能使用。
安装时,请使用cmd或终端。
2020-03-28 22:59
7***@qq.com

7***@qq.com

Mac 上能正常使用吗
2020-03-28 08:46
乘风破浪_

乘风破浪_

回复 zhangdaren :
谢谢
2020-03-23 15:42
zhangdaren

zhangdaren (作者)

回复 乘风破浪_ :
首先,点击提示那行,定位到具体文件,然后右键---验证文档语法(如果没这菜单,请工具--插件安装,安装ESlint的两个插件),然后就会有提示哪行有问题,一般来说是代码语法报错了,如果自己无法解决可以贴上来。
目前遇到的有,多余引号、v-if=""空,重复变量、重复的函数等等。
2020-03-20 10:55
乘风破浪_

乘风破浪_

请问转过的项目 在Hbuilder 运行到微信小程序报错 怎么解决?
15:04:09.674 请注意运行模式下,因日志输出、sourcemap以及未压缩源码等原因,性能和包体积,均不及发行模式。若要正式发布,请点击发行菜单或使用cli发布命令进行发布
15:04:09.675 正在编译中...
15:04:31.547 Module build failed (from ./node_modules/@dcloudio/vue-cli-plugin-uni/packages/vue-loader/lib/loaders/templateLoader.js):
15:04:31.547 语法错误: Unexpected token, expected ";" (1:18956)
2020-03-19 15:07
8***@qq.com

8***@qq.com

回复 8***@qq.com :
是我自己弄错了,已经解决了
2020-03-12 12:21
8***@qq.com

8***@qq.com

运行 wtu -V 报错 修改了power shell还是报下面的错是什么原因
无法加载文件 C:\Users\zwzh\AppData\Roaming\npm\wtu.ps1,因为在此系统上禁止运行脚本。
2020-03-12 12:17
zhangdaren

zhangdaren (作者)

回复 1***@qq.com :
因为我发现使用uni开发时,老是要在template与style跳上跳下,很影响开发效率,而样式非常多的时候,页面会非常长,所以提取出来了。如果大家有需要,可以再弄个参数进行配置。
2020-03-11 12:48