From 76827aedfe3bbd7b655b1092dcb0c1b7a75397d7 Mon Sep 17 00:00:00 2001
From: RyRh <3123294924@qq.com>
Date: Thu, 20 Aug 2026 18:29:49 +0800
Subject: [PATCH] =?UTF-8?q?=E9=A6=96=E6=AC=A1=E6=8F=90=E4=BA=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
App.vue | 20 +
README.md | 87 +
app.css | 230 +
index.html | 20 +
main.js | 28 +
manifest.json | 70 +
package.json | 12 +
pages.json | 54 +
pages/index/index.css | 828 +
pages/index/index.vue | 532 +
pages/product-detail/product-detail.css | 327 +
pages/product-detail/product-detail.vue | 303 +
pages/products/products.css | 500 +
pages/products/products.vue | 760 +
sitemap.json | 9 +
transform.log | 40 +
uni.scss | 76 +
uni_modules/mp-html/README.md | 193 +
uni_modules/mp-html/changelog.md | 129 +
.../mp-html/components/mp-html/mp-html.vue | 498 +
.../mp-html/components/mp-html/node/node.vue | 576 +
.../mp-html/components/mp-html/parser.js | 1335 ++
uni_modules/mp-html/package.json | 76 +
.../static/app-plus/mp-html/js/handler.js | 1 +
.../app-plus/mp-html/js/uni.webview.min.js | 1 +
.../static/app-plus/mp-html/local.html | 1 +
uni_modules/p-f-unicom/1.jpg | Bin 0 -> 80482 bytes
uni_modules/p-f-unicom/README.md | 188 +
uni_modules/p-f-unicom/changelog.md | 2 +
uni_modules/p-f-unicom/index.js | 369 +
uni_modules/p-f-unicom/package.json | 84 +
uni_modules/zp-mixins/changelog.md | 14 +
uni_modules/zp-mixins/index.js | 52 +
uni_modules/zp-mixins/index.ts | 31 +
uni_modules/zp-mixins/lifecycle/index.js | 2 +
.../zp-mixins/lifecycle/pageLifetimes.js | 39 +
uni_modules/zp-mixins/methods/clone.js | 10 +
uni_modules/zp-mixins/methods/dataset.js | 21 +
uni_modules/zp-mixins/methods/escape.js | 36 +
uni_modules/zp-mixins/methods/event.js | 10 +
uni_modules/zp-mixins/methods/getTabBar.js | 19 +
uni_modules/zp-mixins/methods/index.js | 8 +
uni_modules/zp-mixins/methods/relation.js | 10 +
.../zp-mixins/methods/selectComponent.js | 196 +
uni_modules/zp-mixins/methods/setData.js | 90 +
uni_modules/zp-mixins/package.json | 86 +
uni_modules/zp-mixins/readme.md | 107 +
uni_modules/zp-mixins/utils/_set.js | 26 +
uni_modules/zp-mixins/utils/debounce.js | 17 +
.../dev/.automator/mp-weixin/.automator.json | 0
.../.sourcemap/mp-weixin/common/main.js.map | 1 +
.../mp-weixin/common/runtime.js.map | 1 +
.../.sourcemap/mp-weixin/common/vendor.js.map | 1 +
.../mp-weixin/pages/index/index.js.map | 1 +
.../product-detail/product-detail.js.map | 1 +
.../mp-weixin/pages/products/products.js.map | 1 +
unpackage/dist/dev/mp-weixin/app.js | 4 +
unpackage/dist/dev/mp-weixin/app.json | 39 +
unpackage/dist/dev/mp-weixin/app.wxss | 3 +
unpackage/dist/dev/mp-weixin/common/main.js | 152 +
unpackage/dist/dev/mp-weixin/common/main.wxss | 208 +
.../dist/dev/mp-weixin/common/runtime.js | 158 +
unpackage/dist/dev/mp-weixin/common/vendor.js | 12756 ++++++++++++++++
.../dist/dev/mp-weixin/pages/index/index.js | 664 +
.../dist/dev/mp-weixin/pages/index/index.json | 5 +
.../dist/dev/mp-weixin/pages/index/index.wxml | 1 +
.../dist/dev/mp-weixin/pages/index/index.wxss | 724 +
.../pages/product-detail/product-detail.js | 444 +
.../pages/product-detail/product-detail.json | 4 +
.../pages/product-detail/product-detail.wxml | 1 +
.../pages/product-detail/product-detail.wxss | 283 +
.../dev/mp-weixin/pages/products/products.js | 866 ++
.../mp-weixin/pages/products/products.json | 4 +
.../mp-weixin/pages/products/products.wxml | 1 +
.../mp-weixin/pages/products/products.wxss | 446 +
.../dist/dev/mp-weixin/project.config.json | 36 +
unpackage/dist/dev/mp-weixin/sitemap.json | 9 +
77 files changed, 24937 insertions(+)
create mode 100644 App.vue
create mode 100644 README.md
create mode 100644 app.css
create mode 100644 index.html
create mode 100644 main.js
create mode 100644 manifest.json
create mode 100644 package.json
create mode 100644 pages.json
create mode 100644 pages/index/index.css
create mode 100644 pages/index/index.vue
create mode 100644 pages/product-detail/product-detail.css
create mode 100644 pages/product-detail/product-detail.vue
create mode 100644 pages/products/products.css
create mode 100644 pages/products/products.vue
create mode 100644 sitemap.json
create mode 100644 transform.log
create mode 100644 uni.scss
create mode 100644 uni_modules/mp-html/README.md
create mode 100644 uni_modules/mp-html/changelog.md
create mode 100644 uni_modules/mp-html/components/mp-html/mp-html.vue
create mode 100644 uni_modules/mp-html/components/mp-html/node/node.vue
create mode 100644 uni_modules/mp-html/components/mp-html/parser.js
create mode 100644 uni_modules/mp-html/package.json
create mode 100644 uni_modules/mp-html/static/app-plus/mp-html/js/handler.js
create mode 100644 uni_modules/mp-html/static/app-plus/mp-html/js/uni.webview.min.js
create mode 100644 uni_modules/mp-html/static/app-plus/mp-html/local.html
create mode 100644 uni_modules/p-f-unicom/1.jpg
create mode 100644 uni_modules/p-f-unicom/README.md
create mode 100644 uni_modules/p-f-unicom/changelog.md
create mode 100644 uni_modules/p-f-unicom/index.js
create mode 100644 uni_modules/p-f-unicom/package.json
create mode 100644 uni_modules/zp-mixins/changelog.md
create mode 100644 uni_modules/zp-mixins/index.js
create mode 100644 uni_modules/zp-mixins/index.ts
create mode 100644 uni_modules/zp-mixins/lifecycle/index.js
create mode 100644 uni_modules/zp-mixins/lifecycle/pageLifetimes.js
create mode 100644 uni_modules/zp-mixins/methods/clone.js
create mode 100644 uni_modules/zp-mixins/methods/dataset.js
create mode 100644 uni_modules/zp-mixins/methods/escape.js
create mode 100644 uni_modules/zp-mixins/methods/event.js
create mode 100644 uni_modules/zp-mixins/methods/getTabBar.js
create mode 100644 uni_modules/zp-mixins/methods/index.js
create mode 100644 uni_modules/zp-mixins/methods/relation.js
create mode 100644 uni_modules/zp-mixins/methods/selectComponent.js
create mode 100644 uni_modules/zp-mixins/methods/setData.js
create mode 100644 uni_modules/zp-mixins/package.json
create mode 100644 uni_modules/zp-mixins/readme.md
create mode 100644 uni_modules/zp-mixins/utils/_set.js
create mode 100644 uni_modules/zp-mixins/utils/debounce.js
create mode 100644 unpackage/dist/dev/.automator/mp-weixin/.automator.json
create mode 100644 unpackage/dist/dev/.sourcemap/mp-weixin/common/main.js.map
create mode 100644 unpackage/dist/dev/.sourcemap/mp-weixin/common/runtime.js.map
create mode 100644 unpackage/dist/dev/.sourcemap/mp-weixin/common/vendor.js.map
create mode 100644 unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map
create mode 100644 unpackage/dist/dev/.sourcemap/mp-weixin/pages/product-detail/product-detail.js.map
create mode 100644 unpackage/dist/dev/.sourcemap/mp-weixin/pages/products/products.js.map
create mode 100644 unpackage/dist/dev/mp-weixin/app.js
create mode 100644 unpackage/dist/dev/mp-weixin/app.json
create mode 100644 unpackage/dist/dev/mp-weixin/app.wxss
create mode 100644 unpackage/dist/dev/mp-weixin/common/main.js
create mode 100644 unpackage/dist/dev/mp-weixin/common/main.wxss
create mode 100644 unpackage/dist/dev/mp-weixin/common/runtime.js
create mode 100644 unpackage/dist/dev/mp-weixin/common/vendor.js
create mode 100644 unpackage/dist/dev/mp-weixin/pages/index/index.js
create mode 100644 unpackage/dist/dev/mp-weixin/pages/index/index.json
create mode 100644 unpackage/dist/dev/mp-weixin/pages/index/index.wxml
create mode 100644 unpackage/dist/dev/mp-weixin/pages/index/index.wxss
create mode 100644 unpackage/dist/dev/mp-weixin/pages/product-detail/product-detail.js
create mode 100644 unpackage/dist/dev/mp-weixin/pages/product-detail/product-detail.json
create mode 100644 unpackage/dist/dev/mp-weixin/pages/product-detail/product-detail.wxml
create mode 100644 unpackage/dist/dev/mp-weixin/pages/product-detail/product-detail.wxss
create mode 100644 unpackage/dist/dev/mp-weixin/pages/products/products.js
create mode 100644 unpackage/dist/dev/mp-weixin/pages/products/products.json
create mode 100644 unpackage/dist/dev/mp-weixin/pages/products/products.wxml
create mode 100644 unpackage/dist/dev/mp-weixin/pages/products/products.wxss
create mode 100644 unpackage/dist/dev/mp-weixin/project.config.json
create mode 100644 unpackage/dist/dev/mp-weixin/sitemap.json
diff --git a/App.vue b/App.vue
new file mode 100644
index 0000000..614f749
--- /dev/null
+++ b/App.vue
@@ -0,0 +1,20 @@
+
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..da0fa79
--- /dev/null
+++ b/README.md
@@ -0,0 +1,87 @@
+# miniprogram-to-uniapp 转换说明
+
+## 0x00 转换模式
+根据转换模式,转换后的项目使用相应的工具打开,目前有两种模式:
+
+### HBuilder X 模式
+转换后的目录(以_uni结尾的目录), 需使用HBuilder X导入,进行运行和调试。
+如果项目使用了npm模块,需先使用npm install等命令进行安装,然后再运行
+
+### Vue-cli 模式
+转换后的目录(以_vue-cli结尾的目录), 需使用命令行安装依赖、运行和打包。
+详见文档:https://uniapp.dcloud.io/quickstart-cli.html#%E8%BF%90%E8%A1%8C%E3%80%81%E5%8F%91%E5%B8%83uni-app
+
+注:
+上述两种项目类型,可以相互转换。
+[uni-app HBuilderX 工程与 vue-cli 工程相互转换](https://ask.dcloud.net.cn/article/35750)
+
+
+## 0x01 调试建议
+如果您想转换小程序为uni-app项目,并发布为App,
+建议运行到H5平台,因为H5平台速度快,而且与App平台贴合度更高。
+只有当强依赖硬件时,才使用真机调试,这样可以节约时间!
+
+
+## 0x02 常见问题
+### 1.命令行提示:“'wtu'不是内部或外部命令, 也不是可运行的程序”
+一般是node未安装在默认目录导致的,参照文章 [解决“npm不是内部或外部命令“](https://www.cnblogs.com/ldq678/p/10291824.html) 解决。
+
+
+### 2.PowerShell里提示:无法加载文件 XXXXXXXXX.ps1,因为在此系统上禁止运行脚本。
+以管理员身份运行`powershell`,执行
+```
+set-executionpolicy remotesigned
+```
+输入 y 即可
+或者,在PowerShell输入 `cmd` 后回车也行
+
+
+### 3.setData为什么没有转换?需要我手动改吗?那我有100多个页面怎么改呀?
+`setData`函数已内置,在main.js通过mixin全局混入,所以不用转换,可直接使用`setData`函数!!!
+
+
+### 4.命令行报错:"cannot read property ‘某某某’ of undefined"
+报错解释:有代码“`xx.某某某`”,但xx的值是undefined,因此,需要进报错的页面,调试调试,为啥xx为undefined,相应的调试代码即可。
+常见原因:可能接口跨域,可能真的没值,也可能没声明变量,也可能是工具转换问题等。
+
+
+### 5.为什么我运行到H5或app时,拿不到小程序用户的信息?为什么登录失败?
+转换后的uni-app项目,如需运行到其他小程序、H5和App时,登录和支付功能均需“重新对接”,需要增加 “新” 接口!
+
+
+### 6.跨域问题:为什么我的接口都没有返回数据呀?
+控制台有“CORS”、“Access-Control-Allow-Origin”等关键字时,不要犹豫,果断判断是因为跨域,导致访问接口失败。
+跨域,前端老生常谈,有N种解决办法,最简单的办法是运行到“内置浏览器”。
+PS: 仅仅 H5 平台存在跨域问题!发布后上传到服务器无此问题!
+
+
+### 7.Vant项目怎么转换呀?
+
+Vant项目比较常见的报错是:代码``转到后,运行会报错,因为uni-app不支持在class里面写函数)
+
+由于Vant的一些语法uni-app并不支持,因此需要特殊处理一下,这里分享三种方案,可以根据自己的情况进行选择。
+
+#### 方案一:【替换Vant组件】
+转换前,将vant组件全部用别的组件库替换掉再转换。
+
+#### 方案二:【替换Vant组件】
+转换后,将vant组件使用uview1.x替换掉同功能组件。
+
+#### 方案三:【不替换Vant组件】
+转换后,按uniapp引入小程序组件文档重新引入vant组件(小程序自定义组件支持:
+https://uniapp.dcloud.io/tutorial/miniprogram-subject.html#%E5%B0%8F%E7%A8%8B%E5%BA%8F%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6%E6%94%AF%E6%8C%81)
+
+
+### 8.小程序转换为uni-app项目后,还能转换成其他小程序项目吗?
+当然可以,必须可以!
+小程序转换为uni-app项目后,就是uni-app项目了,uni-app项目能做啥就能做啥,
+能再次生成为各种小程序、发布H5和App。
+
+
+### 9.uni-app生成的小程序项目,还能再转换回uni-app项目吗?
+不能。不支持这种项目的转换!
+
+
+### 其他
+- 因各种原因,本工具并非100%完美转换!有问题实属正常!
+- 如遇运行报错,请在https://github.com/zhangdaren/miniprogram-to-uniapp,将详细情况提交Issue!
diff --git a/app.css b/app.css
new file mode 100644
index 0000000..af12b00
--- /dev/null
+++ b/app.css
@@ -0,0 +1,230 @@
+/* 全局样式 - 印美达 Inkreach 微信小程序 */
+page {
+ --color-primary: #ff6800;
+ --color-primary-light: #fff0e5;
+ --color-primary-dark: #e55a00;
+ --color-secondary: #f26522;
+ --color-dark: #121212;
+ --color-text-primary: #333333;
+ --color-text-secondary: #666666;
+ --color-text-tertiary: #999999;
+ --color-bg-page: #f5f5f5;
+ --color-bg-card: #ffffff;
+ --color-border: #eeeeee;
+ --color-tag-bg: #f2f2f2;
+ --color-success: #52c41a;
+ --color-warning: #faad14;
+
+ --radius-sm: 8rpx;
+ --radius-md: 12rpx;
+ --radius-lg: 20rpx;
+ --radius-xl: 32rpx;
+
+ --spacing-xs: 8rpx;
+ --spacing-sm: 16rpx;
+ --spacing-md: 24rpx;
+ --spacing-lg: 32rpx;
+ --spacing-xl: 48rpx;
+
+ font-size: 28rpx;
+ color: var(--color-text-primary);
+ background-color: var(--color-bg-page);
+ font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif;
+}
+
+/* 通用样式 */
+.container {
+ min-height: 100vh;
+ background-color: var(--color-bg-page);
+}
+
+.flex-row {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.flex-col {
+ display: flex;
+ flex-direction: column;
+}
+
+.flex-center {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.flex-between {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.flex-1 {
+ flex: 1;
+}
+
+.flex-wrap {
+ display: flex;
+ flex-wrap: wrap;
+}
+
+/* 文字样式 */
+.text-primary {
+ color: var(--color-primary);
+}
+.text-secondary {
+ color: var(--color-text-secondary);
+}
+.text-tertiary {
+ color: var(--color-text-tertiary);
+}
+.text-white {
+ color: #ffffff;
+}
+
+.text-bold {
+ font-weight: 600;
+}
+.text-center {
+ text-align: center;
+}
+
+.text-sm {
+ font-size: 24rpx;
+}
+.text-md {
+ font-size: 28rpx;
+}
+.text-lg {
+ font-size: 32rpx;
+}
+.text-xl {
+ font-size: 40rpx;
+}
+.text-xxl {
+ font-size: 56rpx;
+}
+
+/* 间距 */
+.mt-xs {
+ margin-top: 8rpx;
+}
+.mt-sm {
+ margin-top: 16rpx;
+}
+.mt-md {
+ margin-top: 24rpx;
+}
+.mt-lg {
+ margin-top: 32rpx;
+}
+.mt-xl {
+ margin-top: 48rpx;
+}
+
+.mb-xs {
+ margin-bottom: 8rpx;
+}
+.mb-sm {
+ margin-bottom: 16rpx;
+}
+.mb-md {
+ margin-bottom: 24rpx;
+}
+.mb-lg {
+ margin-bottom: 32rpx;
+}
+
+.p-sm {
+ padding: 16rpx;
+}
+.p-md {
+ padding: 24rpx;
+}
+.p-lg {
+ padding: 32rpx;
+}
+
+.px-md {
+ padding-left: 24rpx;
+ padding-right: 24rpx;
+}
+.px-lg {
+ padding-left: 32rpx;
+ padding-right: 32rpx;
+}
+
+/* 按钮 */
+.btn-primary {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background-color: var(--color-primary);
+ color: #ffffff;
+ font-size: 28rpx;
+ font-weight: 500;
+ padding: 20rpx 48rpx;
+ border-radius: var(--radius-lg);
+ border: none;
+ line-height: 1.5;
+}
+
+.btn-primary::after {
+ border: none;
+}
+
+.btn-outline {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background-color: transparent;
+ color: var(--color-primary);
+ font-size: 28rpx;
+ font-weight: 500;
+ padding: 20rpx 48rpx;
+ border-radius: var(--radius-lg);
+ border: 2rpx solid var(--color-primary);
+ line-height: 1.5;
+}
+
+.btn-outline::after {
+ border: none;
+}
+
+/* 卡片 */
+.card {
+ background-color: var(--color-bg-card);
+ border-radius: var(--radius-md);
+ padding: 24rpx;
+ box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
+}
+
+/* 标签 */
+.tag {
+ display: inline-flex;
+ align-items: center;
+ padding: 4rpx 16rpx;
+ border-radius: var(--radius-sm);
+ font-size: 20rpx;
+ background-color: var(--color-tag-bg);
+ color: var(--color-text-secondary);
+}
+
+.tag-primary {
+ background-color: var(--color-primary-light);
+ color: var(--color-primary);
+}
+
+/* 分割线 */
+.divider {
+ width: 100%;
+ height: 1rpx;
+ background-color: var(--color-border);
+}
+
+/* 安全区底部 */
+.safe-bottom {
+ padding-bottom: env(safe-area-inset-bottom);
+}
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..c3ff205
--- /dev/null
+++ b/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main.js b/main.js
new file mode 100644
index 0000000..5016b80
--- /dev/null
+++ b/main.js
@@ -0,0 +1,28 @@
+import App from './App';
+
+// 全局mixins,用于实现setData等功能,请勿删除!';
+import zpMixins from '@/uni_modules/zp-mixins/index.js';
+
+// #ifndef VUE3
+import Vue from 'vue';
+
+Vue.use(zpMixins);
+
+Vue.config.productionTip = false;
+App.mpType = 'app';
+const app = new Vue({
+ ...App
+});
+app.$mount();
+// #endif
+
+// #ifdef VUE3
+import { createSSRApp } from 'vue';
+export function createApp() {
+ const app = createSSRApp(App);
+ app.mixin(zpMixins);
+ return {
+ app
+ };
+}
+// #endif
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000..210f49a
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,70 @@
+{
+ "name": "inkreach-miniprogram",
+ "appid": "",
+ "description": "",
+ "versionName": "1.0.0",
+ "versionCode": "100",
+ "transformPx": false,
+ "app-plus": {
+ "usingComponents": true,
+ "nvueStyleCompiler": "uni-app",
+ "compilerVersion": 3,
+ "splashscreen": {
+ "alwaysShowBeforeRender": true,
+ "waiting": true,
+ "autoclose": true,
+ "delay": 0
+ },
+ "modules": {},
+ "distribute": {
+ "android": {
+ "permissions": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ]
+ },
+ "ios": {},
+ "sdkConfigs": {}
+ }
+ },
+ "quickapp": {},
+ "mp-weixin": {
+ "appid": "wxd0e6eff3c220337b",
+ "setting": {
+ "urlCheck": false
+ },
+ "usingComponents": true,
+ "permission": {
+ "scope.userLocation": {
+ "desc": "你的位置信息将用于小程序位置接口的效果展示"
+ }
+ },
+ "plugins": {}
+ },
+ "mp-alipay": {
+ "usingComponents": true
+ },
+ "mp-baidu": {
+ "usingComponents": true
+ },
+ "mp-toutiao": {
+ "usingComponents": true
+ },
+ "uniStatistics": {
+ "enable": false
+ },
+ "vueVersion": "2"
+}
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..60775bd
--- /dev/null
+++ b/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "inkreach-miniprogram",
+ "version": "1.0.0",
+ "description": "",
+ "main": "main.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "dependencies": {},
+ "license": "ISC"
+}
\ No newline at end of file
diff --git a/pages.json b/pages.json
new file mode 100644
index 0000000..b6fbd88
--- /dev/null
+++ b/pages.json
@@ -0,0 +1,54 @@
+{
+ "pages": [
+ {
+ "path": "pages/index/index",
+ "style": {
+ "navigationBarTitleText": "印美达 Inkreach",
+ "navigationStyle": "custom",
+ "usingComponents": {}
+ }
+ },
+ {
+ "path": "pages/products/products",
+ "style": {
+ "navigationBarTitleText": "产品中心",
+ "usingComponents": {}
+ }
+ },
+ {
+ "path": "pages/product-detail/product-detail",
+ "style": {
+ "navigationBarTitleText": "产品详情",
+ "usingComponents": {}
+ }
+ }
+ ],
+ "tabBar": {
+ "color": "#999999",
+ "selectedColor": "#FF6800",
+ "backgroundColor": "#ffffff",
+ "borderStyle": "white",
+ "list": [
+ {
+ "pagePath": "pages/index/index",
+ "text": "首页"
+ },
+ {
+ "pagePath": "pages/products/products",
+ "text": "产品"
+ }
+ ]
+ },
+ "style": "v2",
+ "sitemapLocation": "sitemap.json",
+ "lazyCodeLoading": "requiredComponents",
+ "globalStyle": {
+ "navigationBarBackgroundColor": "#ffffff",
+ "navigationBarTextStyle": "black",
+ "navigationBarTitleText": "印美达 Inkreach",
+ "backgroundColor": "#f5f5f5",
+ "backgroundTextStyle": "dark",
+ "enablePullDownRefresh": false
+ },
+ "subPackages": []
+}
\ No newline at end of file
diff --git a/pages/index/index.css b/pages/index/index.css
new file mode 100644
index 0000000..9ddb378
--- /dev/null
+++ b/pages/index/index.css
@@ -0,0 +1,828 @@
+/* 首页样式 - 印美达 Inkreach */
+
+.home {
+ min-height: 100vh;
+ background: #ffffff;
+ overflow-x: hidden;
+}
+
+/* 导航栏 */
+.nav-bar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 1000;
+ background: #ffffff;
+ box-shadow: 0 1rpx 0 rgba(0, 0, 0, 0.05);
+}
+
+.nav-content {
+ height: 88rpx;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 32rpx;
+}
+
+.nav-logo {
+ display: flex;
+ align-items: baseline;
+ gap: 8rpx;
+}
+
+.logo-text {
+ font-size: 32rpx;
+ font-weight: 700;
+ color: #ff6800;
+ font-style: italic;
+}
+
+.logo-cn {
+ font-size: 24rpx;
+ color: #333;
+ font-weight: 500;
+}
+
+.nav-actions {
+ display: flex;
+ align-items: center;
+ gap: 24rpx;
+}
+
+.nav-btn {
+ font-size: 26rpx;
+ color: #333;
+}
+
+.nav-login {
+ font-size: 24rpx;
+ color: #ff6800;
+ border: 2rpx solid #ff6800;
+ padding: 8rpx 24rpx;
+ border-radius: 32rpx;
+}
+
+/* Hero 首屏 */
+.hero {
+ position: relative;
+ padding: 60rpx 32rpx 80rpx;
+ overflow: hidden;
+ background: linear-gradient(180deg, #fff5ee 0%, #ffffff 100%);
+}
+
+.hero-bg {
+ position: absolute;
+ top: -100rpx;
+ right: -200rpx;
+ width: 600rpx;
+ height: 600rpx;
+ background: radial-gradient(circle, rgba(255, 104, 0, 0.06) 0%, transparent 70%);
+ border-radius: 50%;
+}
+
+.hero-content {
+ position: relative;
+ z-index: 2;
+}
+
+.hero-title {
+ display: flex;
+ flex-direction: column;
+ gap: 8rpx;
+}
+
+.hero-title-main {
+ font-size: 72rpx;
+ font-weight: 800;
+ color: #1a1a1a;
+ line-height: 1.2;
+ letter-spacing: 2rpx;
+}
+
+.hero-subtitle {
+ font-size: 30rpx;
+ color: #666;
+ margin-top: 24rpx;
+}
+
+.hero-tags {
+ display: flex;
+ gap: 16rpx;
+ margin-top: 32rpx;
+}
+
+.hero-tag {
+ font-size: 22rpx;
+ color: #ff6800;
+ background: rgba(255, 104, 0, 0.08);
+ padding: 8rpx 20rpx;
+ border-radius: 24rpx;
+ font-weight: 500;
+}
+
+.hero-cta {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background: #ff6800;
+ color: #ffffff;
+ font-size: 30rpx;
+ font-weight: 600;
+ padding: 24rpx 64rpx;
+ border-radius: 48rpx;
+ margin-top: 48rpx;
+ box-shadow: 0 8rpx 24rpx rgba(255, 104, 0, 0.3);
+}
+
+/* 3D插画区 */
+.hero-illustration {
+ position: relative;
+ height: 400rpx;
+ margin-top: 40rpx;
+}
+
+.hero-illust-item {
+ position: absolute;
+}
+
+.hero-illist-tshirt {
+ top: 20rpx;
+ left: 20rpx;
+ transform: rotate(-8deg);
+}
+
+.hero-illist-bag {
+ top: 60rpx;
+ right: 40rpx;
+ transform: rotate(12deg);
+}
+
+.hero-illist-box {
+ bottom: 0;
+ left: 50%;
+ transform: translateX(-50%) rotate(-3deg);
+}
+
+.illust-placeholder {
+ border-radius: 24rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 80rpx;
+}
+
+.illust-placeholder.tshirt {
+ width: 200rpx;
+ height: 220rpx;
+ background: linear-gradient(135deg, #ff6800 0%, #ff8c40 100%);
+}
+
+.illust-placeholder.bag {
+ width: 180rpx;
+ height: 200rpx;
+ background: linear-gradient(135deg, #f26522 0%, #ff8855 100%);
+}
+
+.illust-placeholder.box {
+ width: 240rpx;
+ height: 180rpx;
+ background: linear-gradient(135deg, #ff6800 0%, #ffa040 100%);
+}
+
+/* 通用 section */
+.section-title {
+ font-size: 40rpx;
+ font-weight: 700;
+ color: #1a1a1a;
+ text-align: center;
+ display: block;
+}
+
+.section-subtitle {
+ font-size: 26rpx;
+ color: #999;
+ text-align: center;
+ margin-top: 12rpx;
+ display: block;
+}
+
+.section-title-small {
+ font-size: 28rpx;
+ color: #666;
+ text-align: center;
+ display: block;
+ margin-bottom: 32rpx;
+}
+
+/* 信任指标 */
+.trust-section {
+ padding: 64rpx 32rpx;
+ background: #ffffff;
+}
+
+.trust-grid {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 24rpx;
+}
+
+.trust-card {
+ flex: 1;
+ min-width: 160rpx;
+ background: #fff8f3;
+ border-radius: 16rpx;
+ padding: 28rpx 16rpx;
+ text-align: center;
+}
+
+.trust-number {
+ font-size: 40rpx;
+ font-weight: 700;
+ color: #ff6800;
+ display: block;
+}
+
+.trust-label {
+ font-size: 24rpx;
+ color: #666;
+ margin-top: 8rpx;
+ display: block;
+}
+
+/* 4步流程 */
+.steps-section {
+ padding: 64rpx 32rpx;
+ background: #fafafa;
+}
+
+.steps-list {
+ margin-top: 40rpx;
+}
+
+.step-item {
+ display: flex;
+ align-items: center;
+ padding: 24rpx;
+ background: #ffffff;
+ border-radius: 16rpx;
+ margin-bottom: 16rpx;
+ transition: all 0.3s;
+ border: 2rpx solid transparent;
+}
+
+.step-item.active {
+ border-color: #ff6800;
+ box-shadow: 0 4rpx 16rpx rgba(255, 104, 0, 0.1);
+}
+
+.step-number {
+ font-size: 36rpx;
+ font-weight: 800;
+ color: #ddd;
+ width: 80rpx;
+ flex-shrink: 0;
+}
+
+.step-item.active .step-number {
+ color: #ff6800;
+}
+
+.step-info {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 6rpx;
+}
+
+.step-title {
+ font-size: 30rpx;
+ font-weight: 600;
+ color: #333;
+}
+
+.step-desc {
+ font-size: 24rpx;
+ color: #999;
+}
+
+.step-visual {
+ margin-top: 32rpx;
+}
+
+.step-visual-card {
+ background: #ffffff;
+ border-radius: 20rpx;
+ padding: 48rpx 32rpx;
+ text-align: center;
+ border: 2rpx solid #ff6800;
+}
+
+.step-visual-icon {
+ width: 120rpx;
+ height: 120rpx;
+ border-radius: 50%;
+ background: #fff0e5;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin: 0 auto 24rpx;
+}
+
+.step-visual-emoji {
+ font-size: 56rpx;
+}
+
+.step-visual-text {
+ font-size: 28rpx;
+ color: #666;
+ line-height: 1.6;
+}
+
+/* 全球POD货盘 */
+.catalog-section {
+ padding: 64rpx 0;
+ background: #ffffff;
+}
+
+.catalog-section .section-title {
+ padding: 0 32rpx;
+}
+
+.category-tabs {
+ white-space: nowrap;
+ padding: 24rpx 32rpx;
+}
+
+.cat-tab {
+ display: inline-block;
+ padding: 12rpx 32rpx;
+ margin-right: 16rpx;
+ font-size: 26rpx;
+ color: #666;
+ background: #f5f5f5;
+ border-radius: 32rpx;
+ transition: all 0.3s;
+}
+
+.cat-tab.active {
+ background: #ff6800;
+ color: #ffffff;
+}
+
+.product-preview-grid {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 0 32rpx;
+ gap: 24rpx;
+}
+
+.product-preview-card {
+ width: calc(50% - 12rpx);
+ background: #ffffff;
+ border-radius: 16rpx;
+ overflow: hidden;
+ box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
+}
+
+.product-preview-img {
+ width: 100%;
+ height: 280rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.product-preview-emoji {
+ font-size: 80rpx;
+}
+
+.product-preview-info {
+ padding: 16rpx;
+}
+
+.product-preview-name {
+ font-size: 26rpx;
+ color: #333;
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.product-preview-price {
+ font-size: 28rpx;
+ color: #ff6800;
+ font-weight: 600;
+ margin-top: 8rpx;
+ display: block;
+}
+
+.see-more {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8rpx;
+ padding: 24rpx;
+ font-size: 28rpx;
+ color: #ff6800;
+}
+
+.see-more .arrow {
+ font-size: 24rpx;
+}
+
+/* 平台功能 */
+.features-section {
+ padding: 64rpx 32rpx;
+ background: #fafafa;
+}
+
+.features-grid {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 24rpx;
+ margin-top: 40rpx;
+}
+
+.feature-card {
+ width: calc(50% - 12rpx);
+ background: #ffffff;
+ border-radius: 16rpx;
+ padding: 32rpx 24rpx;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 12rpx;
+}
+
+.feature-icon {
+ width: 80rpx;
+ height: 80rpx;
+ border-radius: 20rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.feature-emoji {
+ font-size: 40rpx;
+}
+
+.feature-title {
+ font-size: 30rpx;
+ font-weight: 600;
+ color: #333;
+}
+
+.feature-desc {
+ font-size: 24rpx;
+ color: #999;
+ line-height: 1.5;
+}
+
+/* 为什么选择 */
+.why-section {
+ padding: 64rpx 32rpx;
+ background: #ffffff;
+}
+
+.why-grid {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 24rpx;
+ margin-top: 40rpx;
+}
+
+.why-card {
+ width: calc(50% - 12rpx);
+ text-align: center;
+ padding: 32rpx 16rpx;
+ background: #fff8f3;
+ border-radius: 16rpx;
+}
+
+.why-icon {
+ width: 72rpx;
+ height: 72rpx;
+ margin: 0 auto 16rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #ffffff;
+ border-radius: 50%;
+}
+
+.why-emoji {
+ font-size: 36rpx;
+}
+
+.why-title {
+ font-size: 28rpx;
+ font-weight: 600;
+ color: #333;
+ display: block;
+ margin-bottom: 8rpx;
+}
+
+.why-desc {
+ font-size: 22rpx;
+ color: #999;
+ display: block;
+}
+
+/* 公司简介 */
+.company-section {
+ padding: 64rpx 32rpx;
+ background: #fafafa;
+}
+
+.company-card {
+ background: #ffffff;
+ border-radius: 20rpx;
+ padding: 40rpx 32rpx;
+ margin-top: 32rpx;
+}
+
+.company-headline {
+ display: flex;
+ flex-direction: column;
+ font-size: 32rpx;
+ font-weight: 600;
+ color: #1a1a1a;
+ line-height: 1.6;
+ margin-bottom: 32rpx;
+}
+
+.company-content {
+ display: flex;
+ flex-direction: column;
+ gap: 24rpx;
+}
+
+.company-block-title {
+ font-size: 26rpx;
+ font-weight: 600;
+ color: #ff6800;
+ display: block;
+ margin-bottom: 8rpx;
+}
+
+.company-block-text {
+ font-size: 24rpx;
+ color: #666;
+ line-height: 1.7;
+}
+
+.company-stats {
+ display: flex;
+ justify-content: space-around;
+ margin-top: 32rpx;
+ padding-top: 32rpx;
+ border-top: 1rpx solid #eee;
+}
+
+.company-stat {
+ text-align: center;
+}
+
+.company-stat-number {
+ font-size: 36rpx;
+ font-weight: 700;
+ color: #ff6800;
+ display: block;
+}
+
+.company-stat-label {
+ font-size: 22rpx;
+ color: #999;
+ margin-top: 4rpx;
+ display: block;
+}
+
+/* 用户案例 */
+.cases-section {
+ padding: 64rpx 0;
+ background: #ffffff;
+}
+
+.cases-section .section-title {
+ padding: 0 32rpx;
+}
+
+.cases-scroll {
+ white-space: nowrap;
+ padding: 32rpx;
+}
+
+.case-card {
+ display: inline-block;
+ width: 480rpx;
+ background: #ffffff;
+ border-radius: 20rpx;
+ overflow: hidden;
+ margin-right: 24rpx;
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
+ vertical-align: top;
+}
+
+.case-image {
+ width: 100%;
+ height: 320rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.case-emoji {
+ font-size: 80rpx;
+}
+
+.case-info {
+ padding: 24rpx;
+}
+
+.case-title {
+ font-size: 28rpx;
+ font-weight: 600;
+ color: #333;
+ display: block;
+ margin-bottom: 12rpx;
+}
+
+.case-tags {
+ display: flex;
+ gap: 8rpx;
+ margin-bottom: 16rpx;
+}
+
+.case-tag {
+ font-size: 20rpx;
+ padding: 4rpx 12rpx;
+ background: #fff0e5;
+ color: #ff6800;
+ border-radius: 8rpx;
+}
+
+.case-metrics {
+ display: flex;
+ gap: 24rpx;
+ padding-top: 16rpx;
+ border-top: 1rpx solid #eee;
+}
+
+.case-metric-value {
+ font-size: 32rpx;
+ font-weight: 700;
+ color: #ff6800;
+ display: block;
+}
+
+.case-metric-label {
+ font-size: 22rpx;
+ color: #999;
+ display: block;
+}
+
+/* 最终CTA */
+.cta-section {
+ position: relative;
+ padding: 80rpx 32rpx;
+ overflow: hidden;
+}
+
+.cta-bg {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: linear-gradient(135deg, #ff6800 0%, #ff8c40 100%);
+}
+
+.cta-content {
+ position: relative;
+ z-index: 2;
+ text-align: center;
+}
+
+.cta-title {
+ display: flex;
+ flex-direction: column;
+ font-size: 48rpx;
+ font-weight: 700;
+ color: #ffffff;
+ line-height: 1.4;
+}
+
+.cta-desc {
+ font-size: 26rpx;
+ color: rgba(255, 255, 255, 0.85);
+ margin-top: 16rpx;
+ display: block;
+}
+
+.cta-input-wrap {
+ display: flex;
+ gap: 16rpx;
+ margin-top: 40rpx;
+ padding: 0 16rpx;
+}
+
+.cta-input {
+ flex: 1;
+ height: 80rpx;
+ background: rgba(255, 255, 255, 0.95);
+ border-radius: 40rpx;
+ padding: 0 32rpx;
+ font-size: 26rpx;
+ color: #333;
+}
+
+.cta-placeholder {
+ color: #ccc;
+}
+
+.cta-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #1a1a1a;
+ color: #ffffff;
+ font-size: 28rpx;
+ font-weight: 600;
+ padding: 0 40rpx;
+ border-radius: 40rpx;
+}
+
+/* 底部 */
+.footer {
+ background: #121212;
+ padding: 48rpx 32rpx;
+ padding-bottom: calc(48rpx + env(safe-area-inset-bottom));
+}
+
+.footer-top {
+ text-align: center;
+ margin-bottom: 40rpx;
+}
+
+.footer-logo {
+ display: flex;
+ align-items: baseline;
+ justify-content: center;
+ gap: 8rpx;
+ margin-bottom: 16rpx;
+}
+
+.footer-logo-en {
+ font-size: 36rpx;
+ font-weight: 700;
+ color: #ff6800;
+ font-style: italic;
+}
+
+.footer-logo-cn {
+ font-size: 28rpx;
+ color: #fff;
+}
+
+.footer-slogan {
+ font-size: 22rpx;
+ color: rgba(255, 255, 255, 0.5);
+}
+
+.footer-links {
+ display: flex;
+ justify-content: space-around;
+ margin-bottom: 40rpx;
+}
+
+.footer-col {
+ display: flex;
+ flex-direction: column;
+ gap: 12rpx;
+}
+
+.footer-col-title {
+ font-size: 26rpx;
+ font-weight: 600;
+ color: #fff;
+ margin-bottom: 8rpx;
+}
+
+.footer-link {
+ font-size: 22rpx;
+ color: rgba(255, 255, 255, 0.5);
+}
+
+.footer-bottom {
+ text-align: center;
+ padding-top: 32rpx;
+ border-top: 1rpx solid rgba(255, 255, 255, 0.1);
+}
+
+.footer-copyright {
+ font-size: 20rpx;
+ color: rgba(255, 255, 255, 0.3);
+}
diff --git a/pages/index/index.vue b/pages/index/index.vue
new file mode 100644
index 0000000..95664d8
--- /dev/null
+++ b/pages/index/index.vue
@@ -0,0 +1,532 @@
+
+
+
+
+
+
+
+ inkreach
+ 印美达
+
+
+ 产品中心
+ 立即开始
+
+
+
+
+
+
+
+
+
+
+
+
+ 一站定制
+ 链通全球
+
+ 从定制设计到生产发货如此简单
+
+ 0库存
+ 1件起订
+ 全球配送
+
+
+ 免费开始
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 全球5000+卖家信赖我们的平台
+
+
+ 1000万+
+ 订单履约
+
+
+ 20+
+ 国家覆盖
+
+
+ 500+
+ 合作工厂
+
+
+ 24H
+ 极速发货
+
+
+
+
+
+
+ 4步开始你的按需定制生意
+
+
+ 01
+
+ 选择产品
+ 从全球POD货盘中选择热销产品
+
+
+
+ 02
+
+ 上传设计
+ 使用在线设计工具创建专属图案
+
+
+
+ 03
+
+ 在线销售
+ 一键上架到Shopify等电商平台
+
+
+
+ 04
+
+ 生产配送
+ 自动生产全球发货履约无忧
+
+
+
+
+
+
+ {{ stepEmoji }}
+
+ {{ stepDesc }}
+
+
+
+
+
+
+ 全球POD货盘
+ 多元化产品选择,满足场景化需求
+
+
+ {{ item.name }}
+
+
+
+
+
+ {{ item.emoji }}
+
+
+
+ {{ item.name }}
+ ¥{{ item.price }}起
+
+
+
+
+ 查看更多产品
+ >
+
+
+
+
+
+ 用强大功能,开启盈利快车道
+
+
+
+ {{ item.emoji }}
+
+
+ {{ item.title }}
+
+ {{ item.desc }}
+
+
+
+
+
+
+ 为什么选择Inkreach?
+
+
+
+ {{ item.emoji }}
+
+
+ {{ item.title }}
+
+ {{ item.desc }}
+
+
+
+
+
+
+ 公司简介
+
+
+ 用科技重新定义服装供应链
+ 让每一个创意,都能高效抵达全球
+
+
+
+ 服务对象与场景
+
+ 服务于数千家跨境独立站、TikTok、TEMU、SHEIN等平台商家,提供从海外生产到末端物流的一站式供应链服务,让电商创业者专注增长,无惧后端履约。
+
+
+
+ 愿景
+
+ 我们坚信,每一个创意都值得被完美呈现。INKREACH将持续深耕智能供应链生态,用科技消除制造壁垒,让全球创业者专注发挥创造力。
+
+
+
+
+
+ {{ item.value }}
+
+ {{ item.label }}
+
+
+
+
+
+
+
+ 用户案例
+
+
+
+ {{ item.emoji }}
+
+
+
+ {{ item.title }}
+
+ {{ tag }}
+
+
+
+ {{ item.roi }}
+ ROI
+
+
+ {{ item.revenue }}
+ 月收入
+
+
+
+
+
+
+
+
+
+
+
+
+ 开始你的POD生意
+ 现在就行动
+
+ 加入成千上万的成功卖家,开始你的定制商品生意
+
+
+ 立即注册
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/product-detail/product-detail.css b/pages/product-detail/product-detail.css
new file mode 100644
index 0000000..664071d
--- /dev/null
+++ b/pages/product-detail/product-detail.css
@@ -0,0 +1,327 @@
+/* 产品详情页样式 */
+.detail-page {
+ min-height: 100vh;
+ background: #f5f5f5;
+ padding-bottom: 140rpx;
+}
+
+/* 图片区 */
+.detail-images {
+ position: relative;
+ background: #ffffff;
+}
+
+.detail-swiper {
+ width: 100%;
+ height: 750rpx;
+}
+
+.swiper-img {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.swiper-emoji {
+ font-size: 160rpx;
+}
+
+.detail-badges {
+ position: absolute;
+ top: 24rpx;
+ left: 24rpx;
+ display: flex;
+ flex-direction: column;
+ gap: 8rpx;
+}
+
+.detail-badge {
+ font-size: 20rpx;
+ padding: 4rpx 12rpx;
+ border-radius: 6rpx;
+}
+
+/* 产品信息 */
+.detail-info-section {
+ background: #ffffff;
+ padding: 32rpx 24rpx;
+ margin-bottom: 16rpx;
+}
+
+.detail-header {
+ display: flex;
+ flex-direction: column;
+ gap: 8rpx;
+}
+
+.detail-name {
+ font-size: 36rpx;
+ font-weight: 600;
+ color: #1a1a1a;
+ line-height: 1.4;
+}
+
+.detail-code {
+ font-size: 24rpx;
+ color: #999;
+}
+
+.detail-price-row {
+ display: flex;
+ align-items: baseline;
+ gap: 8rpx;
+ margin-top: 20rpx;
+}
+
+.detail-price {
+ font-size: 48rpx;
+ font-weight: 700;
+ color: #ff6800;
+}
+
+.detail-price-unit {
+ font-size: 24rpx;
+ color: #ff6800;
+}
+
+.detail-price-original {
+ font-size: 24rpx;
+ color: #ccc;
+ text-decoration: line-through;
+ margin-left: 12rpx;
+}
+
+.detail-meta {
+ display: flex;
+ justify-content: space-between;
+ margin-top: 32rpx;
+ padding-top: 24rpx;
+ border-top: 1rpx solid #f0f0f0;
+}
+
+.meta-item {
+ text-align: center;
+}
+
+.meta-label {
+ font-size: 22rpx;
+ color: #999;
+ display: block;
+ margin-bottom: 8rpx;
+}
+
+.meta-value {
+ font-size: 26rpx;
+ color: #333;
+ font-weight: 500;
+}
+
+/* 通用section */
+.detail-section {
+ background: #ffffff;
+ padding: 32rpx 24rpx;
+ margin-bottom: 16rpx;
+}
+
+.section-label {
+ font-size: 30rpx;
+ font-weight: 600;
+ color: #333;
+ display: block;
+ margin-bottom: 24rpx;
+}
+
+/* 颜色选择 */
+.color-options {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 20rpx;
+}
+
+.color-option {
+ display: flex;
+ align-items: center;
+ gap: 8rpx;
+ padding: 12rpx 20rpx;
+ border-radius: 32rpx;
+ border: 2rpx solid #eee;
+ background: #fafafa;
+}
+
+.color-option.selected {
+ border-color: #ff6800;
+ background: #fff0e5;
+}
+
+.color-dot {
+ width: 32rpx;
+ height: 32rpx;
+ border-radius: 50%;
+ border: 2rpx solid #fff;
+ box-shadow: 0 0 0 1rpx rgba(0, 0, 0, 0.1);
+}
+
+.color-name {
+ font-size: 24rpx;
+ color: #666;
+}
+
+.color-option.selected .color-name {
+ color: #ff6800;
+}
+
+/* 尺码选择 */
+.size-options {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16rpx;
+}
+
+.size-option {
+ min-width: 72rpx;
+ text-align: center;
+ padding: 16rpx 24rpx;
+ font-size: 26rpx;
+ color: #666;
+ background: #f5f5f5;
+ border-radius: 8rpx;
+ border: 2rpx solid transparent;
+}
+
+.size-option.selected {
+ background: #fff0e5;
+ color: #ff6800;
+ border-color: #ff6800;
+}
+
+/* 参数表 */
+.params-table {
+ display: flex;
+ flex-direction: column;
+}
+
+.param-row {
+ display: flex;
+ padding: 16rpx 0;
+ border-bottom: 1rpx solid #f5f5f5;
+}
+
+.param-label {
+ width: 200rpx;
+ font-size: 26rpx;
+ color: #999;
+ flex-shrink: 0;
+}
+
+.param-value {
+ flex: 1;
+ font-size: 26rpx;
+ color: #333;
+}
+
+/* 工艺说明 */
+.craft-info {
+ display: flex;
+ flex-direction: column;
+ gap: 20rpx;
+}
+
+.craft-card {
+ display: flex;
+ align-items: center;
+ gap: 16rpx;
+ padding: 20rpx;
+ background: #fafafa;
+ border-radius: 12rpx;
+}
+
+.craft-icon {
+ width: 64rpx;
+ height: 64rpx;
+ border-radius: 12rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+}
+
+.craft-emoji {
+ font-size: 32rpx;
+}
+
+.craft-name {
+ font-size: 26rpx;
+ font-weight: 600;
+ color: #333;
+ flex-shrink: 0;
+ width: 120rpx;
+}
+
+.craft-desc {
+ flex: 1;
+ font-size: 22rpx;
+ color: #999;
+ line-height: 1.5;
+}
+
+/* 底部操作栏 */
+.detail-bottom-bar {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 120rpx;
+ background: #ffffff;
+ display: flex;
+ align-items: center;
+ padding: 0 24rpx;
+ gap: 16rpx;
+ box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.06);
+ z-index: 100;
+}
+
+.bottom-btn-icon {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 4rpx;
+ width: 80rpx;
+ flex-shrink: 0;
+}
+
+.bottom-icon {
+ font-size: 36rpx;
+}
+
+.bottom-icon-text {
+ font-size: 18rpx;
+ color: #999;
+}
+
+.bottom-btn-cart {
+ flex: 1;
+ height: 80rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #fff0e5;
+ color: #ff6800;
+ font-size: 28rpx;
+ font-weight: 600;
+ border-radius: 40rpx;
+}
+
+.bottom-btn-design {
+ flex: 1;
+ height: 80rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #ff6800;
+ color: #ffffff;
+ font-size: 28rpx;
+ font-weight: 600;
+ border-radius: 40rpx;
+}
diff --git a/pages/product-detail/product-detail.vue b/pages/product-detail/product-detail.vue
new file mode 100644
index 0000000..9a83b38
--- /dev/null
+++ b/pages/product-detail/product-detail.vue
@@ -0,0 +1,303 @@
+
+
+
+
+
+
+
+
+ {{ item.emoji }}
+
+
+
+
+
+ {{ item.text }}
+
+
+
+
+
+
+
+
+ ¥{{ product.price }}
+ 起
+ ¥{{ product.originalPrice }}
+
+
+
+ 起订量
+ {{ product.moq }}件
+
+
+ 生产周期
+ {{ product.leadTime }}
+
+
+ 工艺
+ {{ product.craft }}
+
+
+
+
+
+
+ 颜色选择
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+ 尺码选择
+
+
+ {{ item }}
+
+
+
+
+
+
+ 产品参数
+
+
+ {{ item.label }}
+
+ {{ item.value }}
+
+
+
+
+
+
+ 工艺说明
+
+
+
+ {{ item.emoji }}
+
+
+ {{ item.name }}
+
+ {{ item.desc }}
+
+
+
+
+
+
+
+ {{ isFav ? '❤️' : '🤍' }}
+ 收藏
+
+
+ 💬
+ 客服
+
+
+ 加入清单
+
+
+ 立即定制
+
+
+
+
+
+
+
diff --git a/pages/products/products.css b/pages/products/products.css
new file mode 100644
index 0000000..4f506a6
--- /dev/null
+++ b/pages/products/products.css
@@ -0,0 +1,500 @@
+/* 产品列表页样式 */
+
+.products-page {
+ min-height: 100vh;
+ background: #f5f5f5;
+ display: flex;
+ flex-direction: column;
+}
+
+/* 搜索栏 */
+.search-bar {
+ display: flex;
+ align-items: center;
+ gap: 16rpx;
+ padding: 16rpx 24rpx;
+ background: #ffffff;
+}
+
+.search-input-wrap {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ background: #f5f5f5;
+ border-radius: 32rpx;
+ padding: 0 24rpx;
+ height: 64rpx;
+}
+
+.search-icon {
+ font-size: 28rpx;
+ margin-right: 12rpx;
+}
+
+.search-input {
+ flex: 1;
+ font-size: 26rpx;
+ color: #333;
+}
+
+.search-placeholder {
+ color: #ccc;
+}
+
+.filter-btn {
+ display: flex;
+ align-items: center;
+ gap: 4rpx;
+ padding: 0 16rpx;
+}
+
+.filter-icon {
+ font-size: 28rpx;
+ color: #666;
+}
+
+.filter-text {
+ font-size: 24rpx;
+ color: #666;
+}
+
+/* 国家选择条 */
+.country-bar {
+ white-space: nowrap;
+ background: #ffffff;
+ padding: 16rpx 24rpx;
+ border-bottom: 1rpx solid #eee;
+}
+
+.country-item {
+ display: inline-flex;
+ align-items: center;
+ gap: 6rpx;
+ padding: 8rpx 20rpx;
+ margin-right: 12rpx;
+ border-radius: 24rpx;
+ background: #f5f5f5;
+}
+
+.country-item.active {
+ background: #fff0e5;
+}
+
+.country-flag {
+ font-size: 28rpx;
+}
+
+.country-name {
+ font-size: 22rpx;
+ color: #666;
+}
+
+.country-item.active .country-name {
+ color: #ff6800;
+ font-weight: 500;
+}
+
+/* 已选筛选标签 */
+.active-filters {
+ display: flex;
+ align-items: center;
+ gap: 12rpx;
+ padding: 12rpx 24rpx;
+ background: #ffffff;
+ overflow-x: auto;
+ white-space: nowrap;
+}
+
+.active-filter-tag {
+ display: inline-flex;
+ align-items: center;
+ gap: 8rpx;
+ background: #f2f2f2;
+ border-radius: 8rpx;
+ padding: 6rpx 16rpx;
+ font-size: 22rpx;
+ color: #666;
+ flex-shrink: 0;
+}
+
+.filter-remove {
+ font-size: 20rpx;
+ color: #ccc;
+}
+
+.clear-all {
+ font-size: 22rpx;
+ color: #ff6800;
+ flex-shrink: 0;
+}
+
+/* 主体内容 */
+.content-body {
+ flex: 1;
+ display: flex;
+ overflow: hidden;
+}
+
+/* 左侧分类侧边栏 */
+.sidebar {
+ width: 180rpx;
+ background: #ffffff;
+ border-right: 1rpx solid #eee;
+ height: 100%;
+ flex-shrink: 0;
+}
+
+.sidebar-item {
+ position: relative;
+ padding: 28rpx 20rpx;
+ font-size: 24rpx;
+ color: #666;
+ text-align: center;
+}
+
+.sidebar-item.active {
+ background: #f5f5f5;
+ color: #ff6800;
+ font-weight: 600;
+}
+
+.sidebar-indicator {
+ position: absolute;
+ left: 0;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 6rpx;
+ height: 32rpx;
+ background: #ff6800;
+ border-radius: 0 4rpx 4rpx 0;
+}
+
+.sidebar-promo {
+ margin: 24rpx 16rpx;
+ padding: 20rpx 12rpx;
+ background: linear-gradient(135deg, #ff6800 0%, #ff8c40 100%);
+ border-radius: 12rpx;
+ text-align: center;
+}
+
+.promo-title {
+ font-size: 24rpx;
+ font-weight: 700;
+ color: #fff;
+ display: block;
+}
+
+.promo-desc {
+ font-size: 20rpx;
+ color: rgba(255, 255, 255, 0.9);
+ display: block;
+ margin-top: 4rpx;
+}
+
+/* 右侧产品列表区 */
+.product-list-area {
+ flex: 1;
+ height: 100%;
+}
+
+/* 子分类 */
+.sub-categories {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12rpx;
+ padding: 16rpx 20rpx;
+ background: #ffffff;
+}
+
+.sub-cat-item {
+ font-size: 22rpx;
+ padding: 8rpx 20rpx;
+ border-radius: 24rpx;
+ background: #f5f5f5;
+ color: #666;
+}
+
+.sub-cat-item.active {
+ background: #ff6800;
+ color: #fff;
+}
+
+/* 产品网格 */
+.product-grid {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16rpx;
+ padding: 16rpx 20rpx;
+}
+
+.product-card {
+ width: calc(50% - 8rpx);
+ background: #ffffff;
+ border-radius: 12rpx;
+ overflow: hidden;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
+}
+
+.product-img {
+ width: 100%;
+ height: 300rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+}
+
+.product-emoji {
+ font-size: 80rpx;
+}
+
+.product-badges {
+ position: absolute;
+ top: 12rpx;
+ left: 12rpx;
+ display: flex;
+ flex-direction: column;
+ gap: 4rpx;
+}
+
+.product-badge {
+ font-size: 18rpx;
+ padding: 2rpx 8rpx;
+ border-radius: 4rpx;
+}
+
+.product-info {
+ padding: 16rpx;
+}
+
+.product-name {
+ font-size: 24rpx;
+ color: #333;
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.product-bottom {
+ margin-top: 8rpx;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.product-price {
+ font-size: 30rpx;
+ font-weight: 700;
+ color: #ff6800;
+}
+
+.product-price-unit {
+ font-size: 20rpx;
+ font-weight: 400;
+ margin-left: 2rpx;
+}
+
+/* 分页 */
+.pagination {
+ padding: 24rpx 20rpx;
+ text-align: center;
+}
+
+.page-info {
+ font-size: 22rpx;
+ color: #999;
+ display: block;
+ margin-bottom: 16rpx;
+}
+
+.page-controls {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8rpx;
+}
+
+.page-btn {
+ padding: 8rpx 20rpx;
+ font-size: 22rpx;
+ color: #666;
+ background: #fff;
+ border-radius: 8rpx;
+ border: 1rpx solid #eee;
+}
+
+.page-btn.disabled {
+ color: #ccc;
+}
+
+.page-num {
+ min-width: 48rpx;
+ height: 48rpx;
+ line-height: 48rpx;
+ text-align: center;
+ font-size: 24rpx;
+ color: #666;
+ background: #fff;
+ border-radius: 8rpx;
+ border: 1rpx solid #eee;
+}
+
+.page-num.active {
+ background: #ff6800;
+ color: #fff;
+ border-color: #ff6800;
+}
+
+.page-size {
+ margin-top: 12rpx;
+ font-size: 22rpx;
+ color: #999;
+}
+
+.loading-more {
+ padding: 24rpx;
+ text-align: center;
+ font-size: 24rpx;
+ color: #999;
+}
+
+/* 筛选弹窗 */
+.filter-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.5);
+ z-index: 1000;
+ opacity: 0;
+ visibility: hidden;
+ transition: all 0.3s;
+}
+
+.filter-overlay.show {
+ opacity: 1;
+ visibility: visible;
+}
+
+.filter-drawer {
+ position: fixed;
+ top: 0;
+ right: 0;
+ width: 80%;
+ height: 100%;
+ background: #ffffff;
+ z-index: 1001;
+ transform: translateX(100%);
+ transition: transform 0.3s;
+ display: flex;
+ flex-direction: column;
+}
+
+.filter-drawer.show {
+ transform: translateX(0);
+}
+
+.filter-drawer-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 32rpx 24rpx;
+ border-bottom: 1rpx solid #eee;
+}
+
+.filter-drawer-title {
+ font-size: 32rpx;
+ font-weight: 600;
+ color: #333;
+}
+
+.filter-drawer-close {
+ font-size: 32rpx;
+ color: #999;
+}
+
+.filter-drawer-body {
+ flex: 1;
+ padding: 24rpx;
+}
+
+.filter-group {
+ margin-bottom: 32rpx;
+}
+
+.filter-group-title {
+ font-size: 28rpx;
+ font-weight: 600;
+ color: #333;
+ display: block;
+ margin-bottom: 16rpx;
+}
+
+.filter-options {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12rpx;
+}
+
+.filter-option {
+ padding: 12rpx 24rpx;
+ font-size: 24rpx;
+ color: #666;
+ background: #f5f5f5;
+ border-radius: 8rpx;
+ border: 2rpx solid transparent;
+}
+
+.filter-option.selected {
+ background: #fff0e5;
+ color: #ff6800;
+ border-color: #ff6800;
+}
+
+.filter-price-range {
+ display: flex;
+ align-items: center;
+ gap: 16rpx;
+}
+
+.price-input {
+ flex: 1;
+ height: 64rpx;
+ background: #f5f5f5;
+ border-radius: 8rpx;
+ padding: 0 20rpx;
+ font-size: 24rpx;
+}
+
+.price-divider {
+ color: #ccc;
+}
+
+.filter-drawer-footer {
+ display: flex;
+ gap: 16rpx;
+ padding: 24rpx;
+ border-top: 1rpx solid #eee;
+}
+
+.filter-reset {
+ flex: 1;
+ text-align: center;
+ padding: 24rpx;
+ font-size: 28rpx;
+ color: #666;
+ background: #f5f5f5;
+ border-radius: 12rpx;
+}
+
+.filter-confirm {
+ flex: 1;
+ text-align: center;
+ padding: 24rpx;
+ font-size: 28rpx;
+ color: #fff;
+ background: #ff6800;
+ border-radius: 12rpx;
+}
diff --git a/pages/products/products.vue b/pages/products/products.vue
new file mode 100644
index 0000000..82e07d6
--- /dev/null
+++ b/pages/products/products.vue
@@ -0,0 +1,760 @@
+
+
+
+
+
+
+ 🔍
+
+
+
+ ⚙
+ 筛选
+
+
+
+
+
+
+ {{ item.flag }}
+
+ {{ item.name }}
+
+
+
+
+
+
+ {{ item.label }}
+
+ ✕
+
+ 清除全部
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
+ {{ item.emoji }}
+
+
+ {{ tag.text }}
+
+
+
+
+
+ {{ item.name }}
+
+
+ ¥{{ item.price }}
+ 起
+
+
+
+
+
+
+
+
+
+
+
+ 加载中...
+
+
+
+
+
+
+
+
+
+
+
+ 工艺
+
+
+ {{ item }}
+
+
+
+
+
+ 材质
+
+
+ {{ item }}
+
+
+
+
+
+ 价格区间
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sitemap.json b/sitemap.json
new file mode 100644
index 0000000..e70d9cf
--- /dev/null
+++ b/sitemap.json
@@ -0,0 +1,9 @@
+{
+ "desc": "印美达 Inkreach 小程序",
+ "rules": [
+ {
+ "action": "allow",
+ "page": "*"
+ }
+ ]
+}
diff --git a/transform.log b/transform.log
new file mode 100644
index 0000000..795297a
--- /dev/null
+++ b/transform.log
@@ -0,0 +1,40 @@
+开始转换……
+小程序路径: C:\gs\project\官网小程序demo\官网小程序demo
+搜索到25个文件(含目录),耗时:3ms
+
+开始分析文件
+分析文件信息完成,共5组数据
+开始转换文件组为vue文件
+开始二次遍历及生成vue文件
+write pages.json success!
+write manifest.json success!
+write main.js success!
+write package.json success!
+
+
+统计信息:
+
+Component数量: 0
+Page数量: 3
+支付api数量: 0
+登录api数量: 0
+chooseMedia数量: 0
+getLocation数量: 0
+getRelationNodes数量: 0
+数量: 0
+数量: 0
+数量: 0
+Vant组件: , 数量:0
+
+项目转换完成!
+用时: 1.753s
+工具版本:v2.2.6
+在该小程序项目的同级目录可以看到_uni结尾的项目,即是转换好的uniapp项目,相关日志在该目录里。
+
+使用说明:
+ 1.因各种原因,本工具并非100%完美转换!部分语法仍需人工处理!
+ 2.工具转换原理及说明文档参考:https://l4rz4zwpx7.k.topthink.com/@kmrvzg72lx/
+ 3.如遇运行报错,请添加QQ群(五群:536178289)带图反馈或https://github.com/zhangdaren/miniprogram-to-uniapp提交Issue!
+ 4.转换后请查阅_uni目录或_uni-cli目录里的 README.md 和 transform.log
+
+
diff --git a/uni.scss b/uni.scss
new file mode 100644
index 0000000..a05adb4
--- /dev/null
+++ b/uni.scss
@@ -0,0 +1,76 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+
+/**
+ * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
+ *
+ * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
+ */
+
+/* 颜色变量 */
+
+/* 行为相关颜色 */
+$uni-color-primary: #007aff;
+$uni-color-success: #4cd964;
+$uni-color-warning: #f0ad4e;
+$uni-color-error: #dd524d;
+
+/* 文字基本颜色 */
+$uni-text-color:#333;//基本色
+$uni-text-color-inverse:#fff;//反色
+$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
+$uni-text-color-placeholder: #808080;
+$uni-text-color-disable:#c0c0c0;
+
+/* 背景颜色 */
+$uni-bg-color:#ffffff;
+$uni-bg-color-grey:#f8f8f8;
+$uni-bg-color-hover:#f1f1f1;//点击状态颜色
+$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
+
+/* 边框颜色 */
+$uni-border-color:#c8c7cc;
+
+/* 尺寸变量 */
+
+/* 文字尺寸 */
+$uni-font-size-sm:12px;
+$uni-font-size-base:14px;
+$uni-font-size-lg:16;
+
+/* 图片尺寸 */
+$uni-img-size-sm:20px;
+$uni-img-size-base:26px;
+$uni-img-size-lg:40px;
+
+/* Border Radius */
+$uni-border-radius-sm: 2px;
+$uni-border-radius-base: 3px;
+$uni-border-radius-lg: 6px;
+$uni-border-radius-circle: 50%;
+
+/* 水平间距 */
+$uni-spacing-row-sm: 5px;
+$uni-spacing-row-base: 10px;
+$uni-spacing-row-lg: 15px;
+
+/* 垂直间距 */
+$uni-spacing-col-sm: 4px;
+$uni-spacing-col-base: 8px;
+$uni-spacing-col-lg: 12px;
+
+/* 透明度 */
+$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
+
+/* 文章场景相关 */
+$uni-color-title: #2C405A; // 文章标题颜色
+$uni-font-size-title:20px;
+$uni-color-subtitle: #555555; // 二级标题颜色
+$uni-font-size-subtitle:26px;
+$uni-color-paragraph: #3F536E; // 文章段落颜色
+$uni-font-size-paragraph:15px;
diff --git a/uni_modules/mp-html/README.md b/uni_modules/mp-html/README.md
new file mode 100644
index 0000000..dcfcc2c
--- /dev/null
+++ b/uni_modules/mp-html/README.md
@@ -0,0 +1,193 @@
+## 为减小组件包的大小,默认组件包中不包含编辑、latex 公式等扩展功能,需要使用扩展功能的请参考下方的 插件扩展 栏的说明
+
+## 功能介绍
+- 全端支持(含 `v3、NVUE`)
+- 支持丰富的标签(包括 `table`、`video`、`svg` 等)
+- 支持丰富的事件效果(自动预览图片、链接处理等)
+- 支持设置占位图(加载中、出错时、预览时)
+- 支持锚点跳转、长按复制等丰富功能
+- 支持大部分 *html* 实体
+- 丰富的插件(关键词搜索、内容编辑、`latex` 公式等)
+- 效率高、容错性强且轻量化
+
+查看 [功能介绍](https://jin-yufeng.gitee.io/mp-html/#/overview/feature) 了解更多
+
+## 使用方法
+- `uni_modules` 方式
+ 1. 点击右上角的 `使用 HBuilder X 导入插件` 按钮直接导入项目或点击 `下载插件 ZIP` 按钮下载插件包并解压到项目的 `uni_modules/mp-html` 目录下
+ 2. 在需要使用页面的 `(n)vue` 文件中添加
+ ```html
+
+
+ ```
+ ```javascript
+ export default {
+ data() {
+ return {
+ html: 'Hello World!
'
+ }
+ }
+ }
+ ```
+ 3. 需要更新版本时在 `HBuilder X` 中右键 `uni_modules/mp-html` 目录选择 `从插件市场更新` 即可
+
+- 源码方式
+ 1. 从 [github](https://github.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 或 [gitee](https://gitee.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 下载源码
+ 插件市场的 **非 uni_modules 版本** 无法更新,不建议从插件市场获取
+ 2. 在需要使用页面的 `(n)vue` 文件中添加
+ ```html
+
+ ```
+ ```javascript
+ import mpHtml from '@/components/mp-html/mp-html'
+ export default {
+ // HBuilderX 2.5.5+ 可以通过 easycom 自动引入
+ components: {
+ mpHtml
+ },
+ data() {
+ return {
+ html: 'Hello World!
'
+ }
+ }
+ }
+ ```
+
+- npm 方式
+ 1. 在项目根目录下执行
+ ```bash
+ npm install mp-html
+ ```
+ 2. 在需要使用页面的 `(n)vue` 文件中添加
+ ```html
+
+ ```
+ ```javascript
+ import mpHtml from 'mp-html/dist/uni-app/components/mp-html/mp-html'
+ export default {
+ // 不可省略
+ components: {
+ mpHtml
+ },
+ data() {
+ return {
+ html: 'Hello World!
'
+ }
+ }
+ }
+ ```
+ 3. 需要更新版本时执行以下命令即可
+ ```bash
+ npm update mp-html
+ ```
+
+ 使用 *cli* 方式运行的项目,通过 *npm* 方式引入时,需要在 *vue.config.js* 中配置 *transpileDependencies*,详情可见 [#330](https://github.com/jin-yufeng/mp-html/issues/330#issuecomment-913617687)
+ 如果在 **nvue** 中使用还要将 `dist/uni-app/static` 目录下的内容拷贝到项目的 `static` 目录下,否则无法运行
+
+查看 [快速开始](https://jin-yufeng.gitee.io/mp-html/#/overview/quickstart) 了解更多
+
+## 组件属性
+
+| 属性 | 类型 | 默认值 | 说明 |
+|:---:|:---:|:---:|---|
+| container-style | String | | 容器的样式([2.1.0+](https://jin-yufeng.gitee.io/mp-html/#/changelog/changelog#v210)) |
+| content | String | | 用于渲染的 html 字符串 |
+| copy-link | Boolean | true | 是否允许外部链接被点击时自动复制 |
+| domain | String | | 主域名(用于链接拼接) |
+| error-img | String | | 图片出错时的占位图链接 |
+| lazy-load | Boolean | false | 是否开启图片懒加载 |
+| loading-img | String | | 图片加载过程中的占位图链接 |
+| pause-video | Boolean | true | 是否在播放一个视频时自动暂停其他视频 |
+| preview-img | Boolean | true | 是否允许图片被点击时自动预览 |
+| scroll-table | Boolean | false | 是否给每个表格添加一个滚动层使其能单独横向滚动 |
+| selectable | Boolean | false | 是否开启文本长按复制 |
+| set-title | Boolean | true | 是否将 title 标签的内容设置到页面标题 |
+| show-img-menu | Boolean | true | 是否允许图片被长按时显示菜单 |
+| tag-style | Object | | 设置标签的默认样式 |
+| use-anchor | Boolean | false | 是否使用锚点链接 |
+
+查看 [属性](https://jin-yufeng.gitee.io/mp-html/#/basic/prop) 了解更多
+
+## 组件事件
+
+| 名称 | 触发时机 |
+|:---:|---|
+| load | dom 树加载完毕时 |
+| ready | 图片加载完毕时 |
+| error | 发生渲染错误时 |
+| imgtap | 图片被点击时 |
+| linktap | 链接被点击时 |
+| play | 音视频播放时 |
+
+查看 [事件](https://jin-yufeng.gitee.io/mp-html/#/basic/event) 了解更多
+
+## api
+组件实例上提供了一些 `api` 方法可供调用
+
+| 名称 | 作用 |
+|:---:|---|
+| in | 将锚点跳转的范围限定在一个 scroll-view 内 |
+| navigateTo | 锚点跳转 |
+| getText | 获取文本内容 |
+| getRect | 获取富文本内容的位置和大小 |
+| setContent | 设置富文本内容 |
+| imgList | 获取所有图片的数组 |
+| pauseMedia | 暂停播放音视频([2.2.2+](https://jin-yufeng.gitee.io/mp-html/#/changelog/changelog#v222)) |
+| setPlaybackRate | 设置音视频播放速率([2.4.0+](https://jin-yufeng.gitee.io/mp-html/#/changelog/changelog#v240)) |
+
+查看 [api](https://jin-yufeng.gitee.io/mp-html/#/advanced/api) 了解更多
+
+## 插件扩展
+除基本功能外,本组件还提供了丰富的扩展,可按照需要选用
+
+| 名称 | 作用 |
+|:---:|---|
+| audio | 音乐播放器 |
+| editable | 富文本 **编辑**([示例项目](https://mp-html.oss-cn-hangzhou.aliyuncs.com/editable.zip)) |
+| emoji | 解析 emoji |
+| highlight | 代码块高亮显示 |
+| markdown | 渲染 markdown |
+| search | 关键词搜索 |
+| style | 匹配 style 标签中的样式 |
+| txv-video | 使用腾讯视频 |
+| img-cache | 图片缓存 by [@PentaTea](https://github.com/PentaTea) |
+| latex | 渲染 latex 公式 by [@Zeng-J](https://github.com/Zeng-J) |
+
+从插件市场导入的包中 **不含有** 扩展插件,使用插件需通过微信小程序 `富文本插件` 获取或参考以下方法进行打包:
+1. 获取完整组件包
+ ```bash
+ npm install mp-html
+ ```
+2. 编辑 `tools/config.js` 中的 `plugins` 项,选择需要的插件
+3. 生成新的组件包
+ 在 `node_modules/mp-html` 目录下执行
+ ```bash
+ npm install
+ npm run build:uni-app
+ ```
+4. 拷贝 `dist/uni-app` 中的内容到项目根目录
+
+查看 [插件](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin) 了解更多
+
+## 关于 nvue
+`nvue` 使用原生渲染,不支持部分 `css` 样式,为实现和 `html` 相同的效果,组件内部通过 `web-view` 进行渲染,性能上差于原生,根据 `weex` 官方建议,`web` 标签仅应用在非常规的降级场景。因此,如果通过原生的方式(如 `richtext`)能够满足需要,则不建议使用本组件,如果有较多的富文本内容,则可以直接使用 `vue` 页面
+由于渲染方式与其他端不同,有以下限制:
+1. 不支持 `lazy-load` 属性
+2. 视频不支持全屏播放
+3. 如果在 `flex-direction: row` 的容器中使用,需要给组件设置宽度或设置 `flex: 1` 占满剩余宽度
+
+纯 `nvue` 模式下,[此问题](https://ask.dcloud.net.cn/question/119678) 修复前,不支持通过 `uni_modules` 引入,需要本地引入(将 [dist/uni-app](https://github.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 中的内容拷贝到项目根目录下)
+
+## 立即体验
+
+
+## 问题反馈
+遇到问题时,请先查阅 [常见问题](https://jin-yufeng.gitee.io/mp-html/#/question/faq) 和 [issue](https://github.com/jin-yufeng/mp-html/issues) 中是否已有相同的问题
+可通过 [issue](https://github.com/jin-yufeng/mp-html/issues/new/choose) 、插件问答或发送邮件到 [mp_html@126.com](mailto:mp_html@126.com) 提问,不建议在评论区提问(不方便回复)
+提问请严格按照 [issue 模板](https://github.com/jin-yufeng/mp-html/issues/new/choose) ,描述清楚使用环境、`html` 内容或可复现的 `demo` 项目以及复现方式,对于 **描述不清**、**无法复现** 或重复的问题将不予回复
+
+欢迎加入 `QQ` 交流群:
+群1(已满):`699734691`
+群2:`778239129`
+
+查看 [问题反馈](https://jin-yufeng.gitee.io/mp-html/#/question/feedback) 了解更多
diff --git a/uni_modules/mp-html/changelog.md b/uni_modules/mp-html/changelog.md
new file mode 100644
index 0000000..e313d38
--- /dev/null
+++ b/uni_modules/mp-html/changelog.md
@@ -0,0 +1,129 @@
+## v2.4.2(2023-05-14)
+1. `A` `editable` 插件支持修改文字颜色 [详细](https://github.com/jin-yufeng/mp-html/issues/254)
+2. `F` 修复了 `svg` 中有 `style` 不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/505)
+3. `F` 修复了使用旧版编译器可能报错 `Bad attr nodes` 的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/472)
+4. `F` 修复了 `app` 端可能出现无法读取 `lazyLoad` 的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/513)
+5. `F` 修复了 `editable` 插件在点击换图时未拼接 `domain` 的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/497) by [@TwoKe945](https://github.com/TwoKe945)
+6. `F` 修复了 `latex` 插件部分情况下不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/515)
+7. `F` 修复了 `editable` 插件点击音视频时其他标签框不消失的问题
+## v2.4.1(2022-12-25)
+1. `F` 修复了没有图片时 `ready` 事件可能不触发的问题
+2. `F` 修复了加载过程中可能出现 `Root label not found` 错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/470)
+3. `F` 修复了 `audio` 插件退出页面可能会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/457)
+4. `F` 修复了 `vue3` 运行到 `app` 在 `HBuilder X 3.6.10` 以上报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/480)
+5. `F` 修复了 `nvue` 端链接中包含 `%22` 时可能无法显示的问题
+6. `F` 修复了 `vue3` 使用 `highlight` 插件可能报错的问题
+## v2.4.0(2022-08-27)
+1. `A` 增加了 [setPlaybackRate](https://jin-yufeng.gitee.io/mp-html/#/advanced/api#setPlaybackRate) 的 `api`,可以设置音视频的播放速率 [详细](https://github.com/jin-yufeng/mp-html/issues/452)
+2. `A` 示例小程序代码开源 [详细](https://github.com/jin-yufeng/mp-html-demo)
+3. `U` 优化 `ready` 事件触发时机,未设置懒加载的情况下基本可以准确触发 [详细](https://github.com/jin-yufeng/mp-html/issues/195)
+4. `U` `highlight` 插件在编辑状态下不进行高亮处理,便于编辑
+5. `F` 修复了 `flex` 布局下图片大小可能不正确的问题
+6. `F` 修复了 `selectable` 属性没有设置 `force` 也可能出现渲染异常的问题
+7. `F` 修复了表格中的图片大小可能不正确的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/448)
+8. `F` 修复了含有合并单元格的表格可能无法设置竖直对齐的问题
+9. `F` 修复了 `editable` 插件在 `scroll-view` 中使用时工具条位置可能不正确的问题
+10. `F` 修复了 `vue3` 使用 [search](advanced/plugin#search) 插件可能导致错误换行的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/449)
+## v2.3.2(2022-08-13)
+1. `A` 增加 [latex](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#latex) 插件,可以渲染数学公式 [详细](https://github.com/jin-yufeng/mp-html/pull/447) by [@Zeng-J](https://github.com/Zeng-J)
+2. `U` 优化根节点下有很多标签的长内容渲染速度
+3. `U` `highlight` 插件适配 `lang-xxx` 格式
+4. `F` 修复了 `table` 标签设置 `border` 属性后可能无法修改边框样式的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/439) by [@zouxingjie](https://github.com/zouxingjie)
+5. `F` 修复了 `editable` 插件输入连续空格无效的问题
+6. `F` 修复了 `vue3` 图片设置 `inline` 会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/438)
+7. `F` 修复了 `vue3` 使用 `table` 可能报错的问题
+## v2.3.1(2022-05-20)
+1. `U` `app` 端支持使用本地图片
+2. `U` 优化了微信小程序 `selectable` 属性在 `ios` 端的处理 [详细](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#selectable)
+3. `F` 修复了 `editable` 插件不在顶部时 `tooltip` 位置可能错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/430)
+4. `F` 修复了 `vue3` 运行到微信小程序可能报错丢失内容的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/414)
+5. `F` 修复了 `vue3` 部分标签可能被错误换行的问题
+6. `F` 修复了 `editable` 插件 `app` 端插入视频无法预览的问题
+## v2.3.0(2022-04-01)
+1. `A` 增加了 `play` 事件,音视频播放时触发,可用于与页面其他音视频进行互斥播放 [详细](basic/event#play)
+2. `U` `show-img-menu` 属性支持控制预览时是否长按弹出菜单
+3. `U` 优化 `wxs` 处理,提高渲染性能 [详细](https://developers.weixin.qq.com/community/develop/article/doc/0006cc2b204740f601bd43fa25a413)
+4. `U` `video` 标签支持 `object-fit` 属性
+5. `U` 增加支持一些常用实体编码 [详细](https://github.com/jin-yufeng/mp-html/issues/418)
+6. `F` 修复了图片仅设置高度可能不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/410)
+7. `F` 修复了 `video` 标签高度设置为 `auto` 不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/411)
+8. `F` 修复了使用 `grid` 布局时可能样式错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/413)
+9. `F` 修复了含有合并单元格的表格部分情况下显示异常的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/417)
+10. `F` 修复了 `editable` 插件连续插入内容时顺序不正确的问题
+11. `F` 修复了 `uni-app` 包 `vue3` 使用 `audio` 插件报错的问题
+12. `F` 修复了 `uni-app` 包 `highlight` 插件使用自定义的 `prism.min.js` 报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/416)
+## v2.2.2(2022-02-26)
+1. `A` 增加了 [pauseMedia](https://jin-yufeng.gitee.io/mp-html/#/advanced/api#pauseMedia) 的 `api`,可用于暂停播放音视频 [详细](https://github.com/jin-yufeng/mp-html/issues/317)
+2. `U` 优化了长内容的加载速度
+3. `U` 适配 `vue3` [#389](https://github.com/jin-yufeng/mp-html/issues/389)、[#398](https://github.com/jin-yufeng/mp-html/pull/398) by [@zhouhuafei](https://github.com/zhouhuafei)、[#400](https://github.com/jin-yufeng/mp-html/issues/400)
+4. `F` 修复了小程序端图片高度设置为百分比时可能不显示的问题
+5. `F` 修复了 `highlight` 插件部分情况下可能显示不完整的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/403)
+## v2.2.1(2021-12-24)
+1. `A` `editable` 插件增加上下移动标签功能
+2. `U` `editable` 插件支持在文本中间光标处插入内容
+3. `F` 修复了 `nvue` 端设置 `margin` 后可能导致高度不正确的问题
+4. `F` 修复了 `highlight` 插件使用压缩版的 `prism.css` 可能导致背景失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/367)
+5. `F` 修复了编辑状态下使用 `emoji` 插件内容为空时可能报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/371)
+6. `F` 修复了使用 `editable` 插件后将 `selectable` 属性设置为 `force` 不生效的问题
+## v2.2.0(2021-10-12)
+1. `A` 增加 `customElements` 配置项,便于添加自定义功能性标签 [详细](https://github.com/jin-yufeng/mp-html/issues/350)
+2. `A` `editable` 插件增加切换音视频自动播放状态的功能 [详细](https://github.com/jin-yufeng/mp-html/pull/341) by [@leeseett](https://github.com/leeseett)
+3. `A` `editable` 插件删除媒体标签时触发 `remove` 事件,便于删除已上传的文件
+4. `U` `editable` 插件 `insertImg` 方法支持同时插入多张图片 [详细](https://github.com/jin-yufeng/mp-html/issues/342)
+5. `U` `editable` 插入图片和音视频时支持拼接 `domian` 主域名
+6. `F` 修复了内部链接参数中包含 `://` 时被认为是外部链接的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/356)
+7. `F` 修复了部分 `svg` 标签名或属性名大小写不正确时不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/351)
+8. `F` 修复了 `nvue` 页面运行到非 `app` 平台时可能样式错误的问题
+## v2.1.5(2021-08-13)
+1. `A` 增加支持标签的 `dir` 属性
+2. `F` 修复了 `ruby` 标签文字与拼音没有居中对齐的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/325)
+3. `F` 修复了音视频标签内有 `a` 标签时可能无法播放的问题
+4. `F` 修复了 `externStyle` 中的 `class` 名包含下划线或数字时可能失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/326)
+5. `F` 修复了 `h5` 端引入 `externStyle` 可能不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/326)
+## v2.1.4(2021-07-14)
+1. `F` 修复了 `rt` 标签无法设置样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/318)
+2. `F` 修复了表格中有单元格同时合并行和列时可能显示不正确的问题
+3. `F` 修复了 `app` 端无法关闭图片长按菜单的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/322)
+4. `F` 修复了 `editable` 插件只能添加图片链接不能修改的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/312) by [@leeseett](https://github.com/leeseett)
+## v2.1.3(2021-06-12)
+1. `A` `editable` 插件增加 `insertTable` 方法
+2. `U` `editable` 插件支持编辑表格中的空白单元格 [详细](https://github.com/jin-yufeng/mp-html/issues/310)
+3. `F` 修复了 `externStyle` 中使用伪类可能失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/298)
+4. `F` 修复了多个组件同时使用时 `tag-style` 属性时可能互相影响的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/305) by [@woodguoyu](https://github.com/woodguoyu)
+5. `F` 修复了包含 `linearGradient` 的 `svg` 可能无法显示的问题
+6. `F` 修复了编译到头条小程序时可能报错的问题
+7. `F` 修复了 `nvue` 端不触发 `click` 事件的问题
+8. `F` 修复了 `editable` 插件尾部插入时无法撤销的问题
+9. `F` 修复了 `editable` 插件的 `insertHtml` 方法只能在末尾插入的问题
+10. `F` 修复了 `editable` 插件插入音频不显示的问题
+## v2.1.2(2021-04-24)
+1. `A` 增加了 [img-cache](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#img-cache) 插件,可以在 `app` 端缓存图片 [详细](https://github.com/jin-yufeng/mp-html/issues/292) by [@PentaTea](https://github.com/PentaTea)
+2. `U` 支持通过 `container-style` 属性设置 `white-space` 来保留连续空格和换行符 [详细](https://jin-yufeng.gitee.io/mp-html/#/question/faq#space)
+3. `U` 代码风格符合 [standard](https://standardjs.com) 标准
+4. `U` `editable` 插件编辑状态下支持预览视频 [详细](https://github.com/jin-yufeng/mp-html/issues/286)
+5. `F` 修复了 `svg` 标签内嵌 `svg` 时无法显示的问题
+6. `F` 修复了编译到支付宝和头条小程序时部分区域不可复制的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/291)
+## v2.1.1(2021-04-09)
+1. 修复了对 `p` 标签设置 `tag-style` 可能不生效的问题
+2. 修复了 `svg` 标签中的文本无法显示的问题
+3. 修复了使用 `editable` 插件编辑表格时可能报错的问题
+4. 修复了使用 `highlight` 插件运行到头条小程序时可能没有样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/280)
+5. 修复了使用 `editable` 插件 `editable` 属性为 `false` 时会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/284)
+6. 修复了 `style` 插件连续子选择器失效的问题
+7. 修复了 `editable` 插件无法修改图片和字体大小的问题
+## v2.1.0.2(2021-03-21)
+修复了 `nvue` 端使用可能报错的问题
+## v2.1.0(2021-03-20)
+1. `A` 增加了 [container-style](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#container-style) 属性 [详细](https://gitee.com/jin-yufeng/mp-html/pulls/1)
+2. `A` 增加支持 `strike` 标签
+3. `A` `editable` 插件增加 `placeholder` 属性 [详细](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#editable)
+4. `A` `editable` 插件增加 `insertHtml` 方法 [详细](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#editable)
+5. `U` 外部样式支持标签名选择器 [详细](https://jin-yufeng.gitee.io/mp-html/#/overview/quickstart#setting)
+6. `F` 修复了 `nvue` 端部分情况下可能不显示的问题
+## v2.0.5(2021-03-12)
+1. `U` [linktap](https://jin-yufeng.gitee.io/mp-html/#/basic/event#linktap) 事件增加返回内部文本内容 `innerText` [详细](https://github.com/jin-yufeng/mp-html/issues/271)
+2. `U` [selectable](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#selectable) 属性设置为 `force` 时能够在微信 `iOS` 端生效(文本块会变成 `inline-block`) [详细](https://github.com/jin-yufeng/mp-html/issues/267)
+3. `F` 修复了部分情况下竖向无法滚动的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/182)
+4. `F` 修复了多次修改富文本数据时部分内容可能不显示的问题
+5. `F` 修复了 [腾讯视频](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#txv-video) 插件可能无法播放的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/265)
+6. `F` 修复了 [highlight](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#highlight) 插件没有设置高亮语言时没有应用默认样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/276) by [@fuzui](https://github.com/fuzui)
diff --git a/uni_modules/mp-html/components/mp-html/mp-html.vue b/uni_modules/mp-html/components/mp-html/mp-html.vue
new file mode 100644
index 0000000..d4cad07
--- /dev/null
+++ b/uni_modules/mp-html/components/mp-html/mp-html.vue
@@ -0,0 +1,498 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/mp-html/components/mp-html/node/node.vue b/uni_modules/mp-html/components/mp-html/node/node.vue
new file mode 100644
index 0000000..c8fa062
--- /dev/null
+++ b/uni_modules/mp-html/components/mp-html/node/node.vue
@@ -0,0 +1,576 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{n.text}}
+
+
+ {{n.text}}
+
+ \n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/uni_modules/mp-html/components/mp-html/parser.js b/uni_modules/mp-html/components/mp-html/parser.js
new file mode 100644
index 0000000..e2e7a87
--- /dev/null
+++ b/uni_modules/mp-html/components/mp-html/parser.js
@@ -0,0 +1,1335 @@
+/**
+ * @fileoverview html 解析器
+ */
+
+// 配置
+const config = {
+ // 信任的标签(保持标签名不变)
+ trustTags: makeMap('a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,ruby,rt,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'),
+
+ // 块级标签(转为 div,其他的非信任标签转为 span)
+ blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,pre,section'),
+
+ // #ifdef (MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE3
+ // 行内标签
+ inlineTags: makeMap('abbr,b,big,code,del,em,i,ins,label,q,small,span,strong,sub,sup'),
+ // #endif
+
+ // 要移除的标签
+ ignoreTags: makeMap('area,base,canvas,embed,frame,head,iframe,input,link,map,meta,param,rp,script,source,style,textarea,title,track,wbr'),
+
+ // 自闭合的标签
+ voidTags: makeMap('area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr'),
+
+ // html 实体
+ entities: {
+ lt: '<',
+ gt: '>',
+ quot: '"',
+ apos: "'",
+ ensp: '\u2002',
+ emsp: '\u2003',
+ nbsp: '\xA0',
+ semi: ';',
+ ndash: '–',
+ mdash: '—',
+ middot: '·',
+ lsquo: '‘',
+ rsquo: '’',
+ ldquo: '“',
+ rdquo: '”',
+ bull: '•',
+ hellip: '…',
+ larr: '←',
+ uarr: '↑',
+ rarr: '→',
+ darr: '↓'
+ },
+
+ // 默认的标签样式
+ tagStyle: {
+ // #ifndef APP-PLUS-NVUE
+ address: 'font-style:italic',
+ big: 'display:inline;font-size:1.2em',
+ caption: 'display:table-caption;text-align:center',
+ center: 'text-align:center',
+ cite: 'font-style:italic',
+ dd: 'margin-left:40px',
+ mark: 'background-color:yellow',
+ pre: 'font-family:monospace;white-space:pre',
+ s: 'text-decoration:line-through',
+ small: 'display:inline;font-size:0.8em',
+ strike: 'text-decoration:line-through',
+ u: 'text-decoration:underline'
+ // #endif
+ },
+
+ // svg 大小写对照表
+ svgDict: {
+ animatetransform: 'animateTransform',
+ lineargradient: 'linearGradient',
+ viewbox: 'viewBox',
+ attributename: 'attributeName',
+ repeatcount: 'repeatCount',
+ repeatdur: 'repeatDur'
+ }
+}
+const tagSelector={}
+const {
+ windowWidth,
+ // #ifdef MP-WEIXIN
+ system
+ // #endif
+} = uni.getSystemInfoSync()
+const blankChar = makeMap(' ,\r,\n,\t,\f')
+let idIndex = 0
+
+// #ifdef H5 || APP-PLUS
+config.ignoreTags.iframe = undefined
+config.trustTags.iframe = true
+config.ignoreTags.embed = undefined
+config.trustTags.embed = true
+// #endif
+// #ifdef APP-PLUS-NVUE
+config.ignoreTags.source = undefined
+config.ignoreTags.style = undefined
+// #endif
+
+/**
+ * @description 创建 map
+ * @param {String} str 逗号分隔
+ */
+function makeMap (str) {
+ const map = Object.create(null)
+ const list = str.split(',')
+ for (let i = list.length; i--;) {
+ map[list[i]] = true
+ }
+ return map
+}
+
+/**
+ * @description 解码 html 实体
+ * @param {String} str 要解码的字符串
+ * @param {Boolean} amp 要不要解码 &
+ * @returns {String} 解码后的字符串
+ */
+function decodeEntity (str, amp) {
+ let i = str.indexOf('&')
+ while (i !== -1) {
+ const j = str.indexOf(';', i + 3)
+ let code
+ if (j === -1) break
+ if (str[i + 1] === '#') {
+ // { 形式的实体
+ code = parseInt((str[i + 2] === 'x' ? '0' : '') + str.substring(i + 2, j))
+ if (!isNaN(code)) {
+ str = str.substr(0, i) + String.fromCharCode(code) + str.substr(j + 1)
+ }
+ } else {
+ // 形式的实体
+ code = str.substring(i + 1, j)
+ if (config.entities[code] || (code === 'amp' && amp)) {
+ str = str.substr(0, i) + (config.entities[code] || '&') + str.substr(j + 1)
+ }
+ }
+ i = str.indexOf('&', i + 1)
+ }
+ return str
+}
+
+/**
+ * @description 合并多个块级标签,加快长内容渲染
+ * @param {Array} nodes 要合并的标签数组
+ */
+function mergeNodes (nodes) {
+ let i = nodes.length - 1
+ for (let j = i; j >= -1; j--) {
+ if (j === -1 || nodes[j].c || !nodes[j].name || (nodes[j].name !== 'div' && nodes[j].name !== 'p' && nodes[j].name[0] !== 'h') || (nodes[j].attrs.style || '').includes('inline')) {
+ if (i - j >= 5) {
+ nodes.splice(j + 1, i - j, {
+ name: 'div',
+ attrs: {},
+ children: nodes.slice(j + 1, i + 1)
+ })
+ }
+ i = j - 1
+ }
+ }
+}
+
+/**
+ * @description html 解析器
+ * @param {Object} vm 组件实例
+ */
+function Parser (vm) {
+ this.options = vm || {}
+ this.tagStyle = Object.assign({}, config.tagStyle, this.options.tagStyle)
+ this.imgList = vm.imgList || []
+ this.imgList._unloadimgs = 0
+ this.plugins = vm.plugins || []
+ this.attrs = Object.create(null)
+ this.stack = []
+ this.nodes = []
+ this.pre = (this.options.containerStyle || '').includes('white-space') && this.options.containerStyle.includes('pre') ? 2 : 0
+}
+
+/**
+ * @description 执行解析
+ * @param {String} content 要解析的文本
+ */
+Parser.prototype.parse = function (content) {
+ // 插件处理
+ for (let i = this.plugins.length; i--;) {
+ if (this.plugins[i].onUpdate) {
+ content = this.plugins[i].onUpdate(content, config) || content
+ }
+ }
+
+ new Lexer(this).parse(content)
+ // 出栈未闭合的标签
+ while (this.stack.length) {
+ this.popNode()
+ }
+ if (this.nodes.length > 50) {
+ mergeNodes(this.nodes)
+ }
+ return this.nodes
+}
+
+/**
+ * @description 将标签暴露出来(不被 rich-text 包含)
+ */
+Parser.prototype.expose = function () {
+ // #ifndef APP-PLUS-NVUE
+ for (let i = this.stack.length; i--;) {
+ const item = this.stack[i]
+ if (item.c || item.name === 'a' || item.name === 'video' || item.name === 'audio') return
+ item.c = 1
+ }
+ // #endif
+}
+
+/**
+ * @description 处理插件
+ * @param {Object} node 要处理的标签
+ * @returns {Boolean} 是否要移除此标签
+ */
+Parser.prototype.hook = function (node) {
+ for (let i = this.plugins.length; i--;) {
+ if (this.plugins[i].onParse && this.plugins[i].onParse(node, this) === false) {
+ return false
+ }
+ }
+ return true
+}
+
+/**
+ * @description 将链接拼接上主域名
+ * @param {String} url 需要拼接的链接
+ * @returns {String} 拼接后的链接
+ */
+Parser.prototype.getUrl = function (url) {
+ const domain = this.options.domain
+ if (url[0] === '/') {
+ if (url[1] === '/') {
+ // // 开头的补充协议名
+ url = (domain ? domain.split('://')[0] : 'http') + ':' + url
+ } else if (domain) {
+ // 否则补充整个域名
+ url = domain + url
+ } /* #ifdef APP-PLUS */ else {
+ url = plus.io.convertLocalFileSystemURL(url)
+ } /* #endif */
+ } else if (!url.includes('data:') && !url.includes('://')) {
+ if (domain) {
+ url = domain + '/' + url
+ } /* #ifdef APP-PLUS */ else {
+ url = plus.io.convertLocalFileSystemURL(url)
+ } /* #endif */
+ }
+ return url
+}
+
+/**
+ * @description 解析样式表
+ * @param {Object} node 标签
+ * @returns {Object}
+ */
+Parser.prototype.parseStyle = function (node) {
+ const attrs = node.attrs
+ const list = (this.tagStyle[node.name] || '').split(';').concat((attrs.style || '').split(';'))
+ const styleObj = {}
+ let tmp = ''
+
+ if (attrs.id && !this.xml) {
+ // 暴露锚点
+ if (this.options.useAnchor) {
+ this.expose()
+ } else if (node.name !== 'img' && node.name !== 'a' && node.name !== 'video' && node.name !== 'audio') {
+ attrs.id = undefined
+ }
+ }
+
+ // 转换 width 和 height 属性
+ if (attrs.width) {
+ styleObj.width = parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px')
+ attrs.width = undefined
+ }
+ if (attrs.height) {
+ styleObj.height = parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px')
+ attrs.height = undefined
+ }
+
+ for (let i = 0, len = list.length; i < len; i++) {
+ const info = list[i].split(':')
+ if (info.length < 2) continue
+ const key = info.shift().trim().toLowerCase()
+ let value = info.join(':').trim()
+ if ((value[0] === '-' && value.lastIndexOf('-') > 0) || value.includes('safe')) {
+ // 兼容性的 css 不压缩
+ tmp += `;${key}:${value}`
+ } else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import')) {
+ // 重复的样式进行覆盖
+ if (value.includes('url')) {
+ // 填充链接
+ let j = value.indexOf('(') + 1
+ if (j) {
+ while (value[j] === '"' || value[j] === "'" || blankChar[value[j]]) {
+ j++
+ }
+ value = value.substr(0, j) + this.getUrl(value.substr(j))
+ }
+ } else if (value.includes('rpx')) {
+ // 转换 rpx(rich-text 内部不支持 rpx)
+ value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * windowWidth / 750 + 'px')
+ }
+ styleObj[key] = value
+ }
+ }
+
+ node.attrs.style = tmp
+ return styleObj
+}
+
+/**
+ * @description 解析到标签名
+ * @param {String} name 标签名
+ * @private
+ */
+Parser.prototype.onTagName = function (name) {
+ this.tagName = this.xml ? name : name.toLowerCase()
+ if (this.tagName === 'svg') {
+ this.xml = (this.xml || 0) + 1 // svg 标签内大小写敏感
+ config.ignoreTags.style = undefined // svg 标签内 style 可用
+ }
+}
+
+/**
+ * @description 解析到属性名
+ * @param {String} name 属性名
+ * @private
+ */
+Parser.prototype.onAttrName = function (name) {
+ name = this.xml ? name : name.toLowerCase()
+ if (name.substr(0, 5) === 'data-') {
+ if (name === 'data-src' && !this.attrs.src) {
+ // data-src 自动转为 src
+ this.attrName = 'src'
+ } else if (this.tagName === 'img' || this.tagName === 'a') {
+ // a 和 img 标签保留 data- 的属性,可以在 imgtap 和 linktap 事件中使用
+ this.attrName = name
+ } else {
+ // 剩余的移除以减小大小
+ this.attrName = undefined
+ }
+ } else {
+ this.attrName = name
+ this.attrs[name] = 'T' // boolean 型属性缺省设置
+ }
+}
+
+/**
+ * @description 解析到属性值
+ * @param {String} val 属性值
+ * @private
+ */
+Parser.prototype.onAttrVal = function (val) {
+ const name = this.attrName || ''
+ if (name === 'style' || name === 'href') {
+ // 部分属性进行实体解码
+ this.attrs[name] = decodeEntity(val, true)
+ } else if (name.includes('src')) {
+ // 拼接主域名
+ this.attrs[name] = this.getUrl(decodeEntity(val, true))
+ } else if (name) {
+ this.attrs[name] = val
+ }
+}
+
+/**
+ * @description 解析到标签开始
+ * @param {Boolean} selfClose 是否有自闭合标识 />
+ * @private
+ */
+Parser.prototype.onOpenTag = function (selfClose) {
+ // 拼装 node
+ const node = Object.create(null)
+ node.name = this.tagName
+ node.attrs = this.attrs
+ // 避免因为自动 diff 使得 type 被设置为 null 导致部分内容不显示
+ if (this.options.nodes.length) {
+ node.type = 'node'
+ }
+ this.attrs = Object.create(null)
+
+ const attrs = node.attrs
+ const parent = this.stack[this.stack.length - 1]
+ const siblings = parent ? parent.children : this.nodes
+ const close = this.xml ? selfClose : config.voidTags[node.name]
+
+ // 替换标签名选择器
+ if (tagSelector[node.name]) {
+ attrs.class = tagSelector[node.name] + (attrs.class ? ' ' + attrs.class : '')
+ }
+
+ // 转换 embed 标签
+ if (node.name === 'embed') {
+ // #ifndef H5 || APP-PLUS
+ const src = attrs.src || ''
+ // 按照后缀名和 type 将 embed 转为 video 或 audio
+ if (src.includes('.mp4') || src.includes('.3gp') || src.includes('.m3u8') || (attrs.type || '').includes('video')) {
+ node.name = 'video'
+ } else if (src.includes('.mp3') || src.includes('.wav') || src.includes('.aac') || src.includes('.m4a') || (attrs.type || '').includes('audio')) {
+ node.name = 'audio'
+ }
+ if (attrs.autostart) {
+ attrs.autoplay = 'T'
+ }
+ attrs.controls = 'T'
+ // #endif
+ // #ifdef H5 || APP-PLUS
+ this.expose()
+ // #endif
+ }
+
+ // #ifndef APP-PLUS-NVUE
+ // 处理音视频
+ if (node.name === 'video' || node.name === 'audio') {
+ // 设置 id 以便获取 context
+ if (node.name === 'video' && !attrs.id) {
+ attrs.id = 'v' + idIndex++
+ }
+ // 没有设置 controls 也没有设置 autoplay 的自动设置 controls
+ if (!attrs.controls && !attrs.autoplay) {
+ attrs.controls = 'T'
+ }
+ // 用数组存储所有可用的 source
+ node.src = []
+ if (attrs.src) {
+ node.src.push(attrs.src)
+ attrs.src = undefined
+ }
+ this.expose()
+ }
+ // #endif
+
+ // 处理自闭合标签
+ if (close) {
+ if (!this.hook(node) || config.ignoreTags[node.name]) {
+ // 通过 base 标签设置主域名
+ if (node.name === 'base' && !this.options.domain) {
+ this.options.domain = attrs.href
+ } /* #ifndef APP-PLUS-NVUE */ else if (node.name === 'source' && parent && (parent.name === 'video' || parent.name === 'audio') && attrs.src) {
+ // 设置 source 标签(仅父节点为 video 或 audio 时有效)
+ parent.src.push(attrs.src)
+ } /* #endif */
+ return
+ }
+
+ // 解析 style
+ const styleObj = this.parseStyle(node)
+
+ // 处理图片
+ if (node.name === 'img') {
+ if (attrs.src) {
+ // 标记 webp
+ if (attrs.src.includes('webp')) {
+ node.webp = 'T'
+ }
+ // data url 图片如果没有设置 original-src 默认为不可预览的小图片
+ if (attrs.src.includes('data:') && !attrs['original-src']) {
+ attrs.ignore = 'T'
+ }
+ if (!attrs.ignore || node.webp || attrs.src.includes('cloud://')) {
+ for (let i = this.stack.length; i--;) {
+ const item = this.stack[i]
+ if (item.name === 'a') {
+ node.a = item.attrs
+ }
+ if (item.name === 'table' && !node.webp && !attrs.src.includes('cloud://')) {
+ if (!styleObj.display || styleObj.display.includes('inline')) {
+ node.t = 'inline-block'
+ } else {
+ node.t = styleObj.display
+ }
+ styleObj.display = undefined
+ }
+ // #ifndef H5 || APP-PLUS
+ const style = item.attrs.style || ''
+ if (style.includes('flex:') && !style.includes('flex:0') && !style.includes('flex: 0') && (!styleObj.width || parseInt(styleObj.width) > 100)) {
+ styleObj.width = '100% !important'
+ styleObj.height = ''
+ for (let j = i + 1; j < this.stack.length; j++) {
+ this.stack[j].attrs.style = (this.stack[j].attrs.style || '').replace('inline-', '')
+ }
+ } else if (style.includes('flex') && styleObj.width === '100%') {
+ for (let j = i + 1; j < this.stack.length; j++) {
+ const style = this.stack[j].attrs.style || ''
+ if (!style.includes(';width') && !style.includes(' width') && style.indexOf('width') !== 0) {
+ styleObj.width = ''
+ break
+ }
+ }
+ } else if (style.includes('inline-block')) {
+ if (styleObj.width && styleObj.width[styleObj.width.length - 1] === '%') {
+ item.attrs.style += ';max-width:' + styleObj.width
+ styleObj.width = ''
+ } else {
+ item.attrs.style += ';max-width:100%'
+ }
+ }
+ // #endif
+ item.c = 1
+ }
+ attrs.i = this.imgList.length.toString()
+ let src = attrs['original-src'] || attrs.src
+ // #ifndef H5 || MP-ALIPAY || APP-PLUS || MP-360
+ if (this.imgList.includes(src)) {
+ // 如果有重复的链接则对域名进行随机大小写变换避免预览时错位
+ let i = src.indexOf('://')
+ if (i !== -1) {
+ i += 3
+ let newSrc = src.substr(0, i)
+ for (; i < src.length; i++) {
+ if (src[i] === '/') break
+ newSrc += Math.random() > 0.5 ? src[i].toUpperCase() : src[i]
+ }
+ newSrc += src.substr(i)
+ src = newSrc
+ }
+ }
+ // #endif
+ this.imgList.push(src)
+ if (!node.t) {
+ this.imgList._unloadimgs += 1
+ }
+ // #ifdef H5 || APP-PLUS
+ if (this.options.lazyLoad) {
+ attrs['data-src'] = attrs.src
+ attrs.src = undefined
+ }
+ // #endif
+ }
+ }
+ if (styleObj.display === 'inline') {
+ styleObj.display = ''
+ }
+ // #ifndef APP-PLUS-NVUE
+ if (attrs.ignore) {
+ styleObj['max-width'] = styleObj['max-width'] || '100%'
+ attrs.style += ';-webkit-touch-callout:none'
+ }
+ // #endif
+ // 设置的宽度超出屏幕,为避免变形,高度转为自动
+ if (parseInt(styleObj.width) > windowWidth) {
+ styleObj.height = undefined
+ }
+ // 记录是否设置了宽高
+ if (!isNaN(parseInt(styleObj.width))) {
+ node.w = 'T'
+ }
+ if (!isNaN(parseInt(styleObj.height)) && (!styleObj.height.includes('%') || (parent && (parent.attrs.style || '').includes('height')))) {
+ node.h = 'T'
+ }
+ } else if (node.name === 'svg') {
+ siblings.push(node)
+ this.stack.push(node)
+ this.popNode()
+ return
+ }
+ for (const key in styleObj) {
+ if (styleObj[key]) {
+ attrs.style += `;${key}:${styleObj[key].replace(' !important', '')}`
+ }
+ }
+ attrs.style = attrs.style.substr(1) || undefined
+ // #ifdef (MP-WEIXIN || MP-QQ) && VUE3
+ if (!attrs.style) {
+ delete attrs.style
+ }
+ // #endif
+ } else {
+ if ((node.name === 'pre' || ((attrs.style || '').includes('white-space') && attrs.style.includes('pre'))) && this.pre !== 2) {
+ this.pre = node.pre = 1
+ }
+ node.children = []
+ this.stack.push(node)
+ }
+
+ // 加入节点树
+ siblings.push(node)
+}
+
+/**
+ * @description 解析到标签结束
+ * @param {String} name 标签名
+ * @private
+ */
+Parser.prototype.onCloseTag = function (name) {
+ // 依次出栈到匹配为止
+ name = this.xml ? name : name.toLowerCase()
+ let i
+ for (i = this.stack.length; i--;) {
+ if (this.stack[i].name === name) break
+ }
+ if (i !== -1) {
+ while (this.stack.length > i) {
+ this.popNode()
+ }
+ } else if (name === 'p' || name === 'br') {
+ const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
+ siblings.push({
+ name,
+ attrs: {
+ class: tagSelector[name] || '',
+ style: this.tagStyle[name] || ''
+ }
+ })
+ }
+}
+
+/**
+ * @description 处理标签出栈
+ * @private
+ */
+Parser.prototype.popNode = function () {
+ const node = this.stack.pop()
+ let attrs = node.attrs
+ const children = node.children
+ const parent = this.stack[this.stack.length - 1]
+ const siblings = parent ? parent.children : this.nodes
+
+ if (!this.hook(node) || config.ignoreTags[node.name]) {
+ // 获取标题
+ if (node.name === 'title' && children.length && children[0].type === 'text' && this.options.setTitle) {
+ uni.setNavigationBarTitle({
+ title: children[0].text
+ })
+ }
+ siblings.pop()
+ return
+ }
+
+ if (node.pre && this.pre !== 2) {
+ // 是否合并空白符标识
+ this.pre = node.pre = undefined
+ for (let i = this.stack.length; i--;) {
+ if (this.stack[i].pre) {
+ this.pre = 1
+ }
+ }
+ }
+
+ const styleObj = {}
+
+ // 转换 svg
+ if (node.name === 'svg') {
+ if (this.xml > 1) {
+ // 多层 svg 嵌套
+ this.xml--
+ return
+ }
+ // #ifdef APP-PLUS-NVUE
+ (function traversal (node) {
+ if (node.name) {
+ // 调整 svg 的大小写
+ node.name = config.svgDict[node.name] || node.name
+ for (const item in node.attrs) {
+ if (config.svgDict[item]) {
+ node.attrs[config.svgDict[item]] = node.attrs[item]
+ node.attrs[item] = undefined
+ }
+ }
+ for (let i = 0; i < (node.children || []).length; i++) {
+ traversal(node.children[i])
+ }
+ }
+ })(node)
+ // #endif
+ // #ifndef APP-PLUS-NVUE
+ let src = ''
+ const style = attrs.style
+ attrs.style = ''
+ attrs.xmlns = 'http://www.w3.org/2000/svg';
+ (function traversal (node) {
+ if (node.type === 'text') {
+ src += node.text
+ return
+ }
+ const name = config.svgDict[node.name] || node.name
+ src += '<' + name
+ for (const item in node.attrs) {
+ const val = node.attrs[item]
+ if (val) {
+ src += ` ${config.svgDict[item] || item}="${val}"`
+ }
+ }
+ if (!node.children) {
+ src += '/>'
+ } else {
+ src += '>'
+ for (let i = 0; i < node.children.length; i++) {
+ traversal(node.children[i])
+ }
+ src += '' + name + '>'
+ }
+ })(node)
+ node.name = 'img'
+ node.attrs = {
+ src: 'data:image/svg+xml;utf8,' + src.replace(/#/g, '%23'),
+ style,
+ ignore: 'T'
+ }
+ node.children = undefined
+ // #endif
+ this.xml = false
+ config.ignoreTags.style = true
+ return
+ }
+
+ // #ifndef APP-PLUS-NVUE
+ // 转换 align 属性
+ if (attrs.align) {
+ if (node.name === 'table') {
+ if (attrs.align === 'center') {
+ styleObj['margin-inline-start'] = styleObj['margin-inline-end'] = 'auto'
+ } else {
+ styleObj.float = attrs.align
+ }
+ } else {
+ styleObj['text-align'] = attrs.align
+ }
+ attrs.align = undefined
+ }
+
+ // 转换 dir 属性
+ if (attrs.dir) {
+ styleObj.direction = attrs.dir
+ attrs.dir = undefined
+ }
+
+ // 转换 font 标签的属性
+ if (node.name === 'font') {
+ if (attrs.color) {
+ styleObj.color = attrs.color
+ attrs.color = undefined
+ }
+ if (attrs.face) {
+ styleObj['font-family'] = attrs.face
+ attrs.face = undefined
+ }
+ if (attrs.size) {
+ let size = parseInt(attrs.size)
+ if (!isNaN(size)) {
+ if (size < 1) {
+ size = 1
+ } else if (size > 7) {
+ size = 7
+ }
+ styleObj['font-size'] = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', 'xxx-large'][size - 1]
+ }
+ attrs.size = undefined
+ }
+ }
+ // #endif
+
+ // 一些编辑器的自带 class
+ if ((attrs.class || '').includes('align-center')) {
+ styleObj['text-align'] = 'center'
+ }
+
+ Object.assign(styleObj, this.parseStyle(node))
+
+ if (node.name !== 'table' && parseInt(styleObj.width) > windowWidth) {
+ styleObj['max-width'] = '100%'
+ styleObj['box-sizing'] = 'border-box'
+ }
+
+ // #ifndef APP-PLUS-NVUE
+ if (config.blockTags[node.name]) {
+ node.name = 'div'
+ } else if (!config.trustTags[node.name] && !this.xml) {
+ // 未知标签转为 span,避免无法显示
+ node.name = 'span'
+ }
+
+ if (node.name === 'a' || node.name === 'ad'
+ // #ifdef H5 || APP-PLUS
+ || node.name === 'iframe' // eslint-disable-line
+ // #endif
+ ) {
+ this.expose()
+ } else if (node.name === 'video') {
+ if ((styleObj.height || '').includes('auto')) {
+ styleObj.height = undefined
+ }
+ /* #ifdef APP-PLUS */
+ let str = ''
+ node.html = str
+ /* #endif */
+ } else if ((node.name === 'ul' || node.name === 'ol') && node.c) {
+ // 列表处理
+ const types = {
+ a: 'lower-alpha',
+ A: 'upper-alpha',
+ i: 'lower-roman',
+ I: 'upper-roman'
+ }
+ if (types[attrs.type]) {
+ attrs.style += ';list-style-type:' + types[attrs.type]
+ attrs.type = undefined
+ }
+ for (let i = children.length; i--;) {
+ if (children[i].name === 'li') {
+ children[i].c = 1
+ }
+ }
+ } else if (node.name === 'table') {
+ // 表格处理
+ // cellpadding、cellspacing、border 这几个常用表格属性需要通过转换实现
+ let padding = parseFloat(attrs.cellpadding)
+ let spacing = parseFloat(attrs.cellspacing)
+ const border = parseFloat(attrs.border)
+ const bordercolor = styleObj['border-color']
+ const borderstyle = styleObj['border-style']
+ if (node.c) {
+ // padding 和 spacing 默认 2
+ if (isNaN(padding)) {
+ padding = 2
+ }
+ if (isNaN(spacing)) {
+ spacing = 2
+ }
+ }
+ if (border) {
+ attrs.style += `;border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'}`
+ }
+ if (node.flag && node.c) {
+ // 有 colspan 或 rowspan 且含有链接的表格通过 grid 布局实现
+ styleObj.display = 'grid'
+ if (spacing) {
+ styleObj['grid-gap'] = spacing + 'px'
+ styleObj.padding = spacing + 'px'
+ } else if (border) {
+ // 无间隔的情况下避免边框重叠
+ attrs.style += ';border-left:0;border-top:0'
+ }
+
+ const width = [] // 表格的列宽
+ const trList = [] // tr 列表
+ const cells = [] // 保存新的单元格
+ const map = {}; // 被合并单元格占用的格子
+
+ (function traversal (nodes) {
+ for (let i = 0; i < nodes.length; i++) {
+ if (nodes[i].name === 'tr') {
+ trList.push(nodes[i])
+ } else {
+ traversal(nodes[i].children || [])
+ }
+ }
+ })(children)
+
+ for (let row = 1; row <= trList.length; row++) {
+ let col = 1
+ for (let j = 0; j < trList[row - 1].children.length; j++) {
+ const td = trList[row - 1].children[j]
+ if (td.name === 'td' || td.name === 'th') {
+ // 这个格子被上面的单元格占用,则列号++
+ while (map[row + '.' + col]) {
+ col++
+ }
+ let style = td.attrs.style || ''
+ let start = style.indexOf('width') ? style.indexOf(';width') : 0
+ // 提取出 td 的宽度
+ if (start !== -1) {
+ let end = style.indexOf(';', start + 6)
+ if (end === -1) {
+ end = style.length
+ }
+ if (!td.attrs.colspan) {
+ width[col] = style.substring(start ? start + 7 : 6, end)
+ }
+ style = style.substr(0, start) + style.substr(end)
+ }
+ // 设置竖直对齐
+ style += ';display:flex'
+ start = style.indexOf('vertical-align')
+ if (start !== -1) {
+ const val = style.substr(start + 15, 10)
+ if (val.includes('middle')) {
+ style += ';align-items:center'
+ } else if (val.includes('bottom')) {
+ style += ';align-items:flex-end'
+ }
+ } else {
+ style += ';align-items:center'
+ }
+ // 设置水平对齐
+ start = style.indexOf('text-align')
+ if (start !== -1) {
+ const val = style.substr(start + 11, 10)
+ if (val.includes('center')) {
+ style += ';justify-content: center'
+ } else if (val.includes('right')) {
+ style += ';justify-content: right'
+ }
+ }
+ style = (border ? `;border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'}` + (spacing ? '' : ';border-right:0;border-bottom:0') : '') + (padding ? `;padding:${padding}px` : '') + ';' + style
+ // 处理列合并
+ if (td.attrs.colspan) {
+ style += `;grid-column-start:${col};grid-column-end:${col + parseInt(td.attrs.colspan)}`
+ if (!td.attrs.rowspan) {
+ style += `;grid-row-start:${row};grid-row-end:${row + 1}`
+ }
+ col += parseInt(td.attrs.colspan) - 1
+ }
+ // 处理行合并
+ if (td.attrs.rowspan) {
+ style += `;grid-row-start:${row};grid-row-end:${row + parseInt(td.attrs.rowspan)}`
+ if (!td.attrs.colspan) {
+ style += `;grid-column-start:${col};grid-column-end:${col + 1}`
+ }
+ // 记录下方单元格被占用
+ for (let rowspan = 1; rowspan < td.attrs.rowspan; rowspan++) {
+ for (let colspan = 0; colspan < (td.attrs.colspan || 1); colspan++) {
+ map[(row + rowspan) + '.' + (col - colspan)] = 1
+ }
+ }
+ }
+ if (style) {
+ td.attrs.style = style
+ }
+ cells.push(td)
+ col++
+ }
+ }
+ if (row === 1) {
+ let temp = ''
+ for (let i = 1; i < col; i++) {
+ temp += (width[i] ? width[i] : 'auto') + ' '
+ }
+ styleObj['grid-template-columns'] = temp
+ }
+ }
+ node.children = cells
+ } else {
+ // 没有使用合并单元格的表格通过 table 布局实现
+ if (node.c) {
+ styleObj.display = 'table'
+ }
+ if (!isNaN(spacing)) {
+ styleObj['border-spacing'] = spacing + 'px'
+ }
+ if (border || padding) {
+ // 遍历
+ (function traversal (nodes) {
+ for (let i = 0; i < nodes.length; i++) {
+ const td = nodes[i]
+ if (td.name === 'th' || td.name === 'td') {
+ if (border) {
+ td.attrs.style = `border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'};${td.attrs.style || ''}`
+ }
+ if (padding) {
+ td.attrs.style = `padding:${padding}px;${td.attrs.style || ''}`
+ }
+ } else if (td.children) {
+ traversal(td.children)
+ }
+ }
+ })(children)
+ }
+ }
+ // 给表格添加一个单独的横向滚动层
+ if (this.options.scrollTable && !(attrs.style || '').includes('inline')) {
+ const table = Object.assign({}, node)
+ node.name = 'div'
+ node.attrs = {
+ style: 'overflow:auto'
+ }
+ node.children = [table]
+ attrs = table.attrs
+ }
+ } else if ((node.name === 'td' || node.name === 'th') && (attrs.colspan || attrs.rowspan)) {
+ for (let i = this.stack.length; i--;) {
+ if (this.stack[i].name === 'table') {
+ this.stack[i].flag = 1 // 指示含有合并单元格
+ break
+ }
+ }
+ } else if (node.name === 'ruby') {
+ // 转换 ruby
+ node.name = 'span'
+ for (let i = 0; i < children.length - 1; i++) {
+ if (children[i].type === 'text' && children[i + 1].name === 'rt') {
+ children[i] = {
+ name: 'div',
+ attrs: {
+ style: 'display:inline-block;text-align:center'
+ },
+ children: [{
+ name: 'div',
+ attrs: {
+ style: 'font-size:50%;' + (children[i + 1].attrs.style || '')
+ },
+ children: children[i + 1].children
+ }, children[i]]
+ }
+ children.splice(i + 1, 1)
+ }
+ }
+ } else if (node.c) {
+ (function traversal (node) {
+ node.c = 2
+ for (let i = node.children.length; i--;) {
+ const child = node.children[i]
+ // #ifdef (MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE3
+ if (child.name && (config.inlineTags[child.name] || ((child.attrs.style || '').includes('inline') && child.children)) && !child.c) {
+ traversal(child)
+ }
+ // #endif
+ if (!child.c || child.name === 'table') {
+ node.c = 1
+ }
+ }
+ })(node)
+ }
+
+ if ((styleObj.display || '').includes('flex') && !node.c) {
+ for (let i = children.length; i--;) {
+ const item = children[i]
+ if (item.f) {
+ item.attrs.style = (item.attrs.style || '') + item.f
+ item.f = undefined
+ }
+ }
+ }
+ // flex 布局时部分样式需要提取到 rich-text 外层
+ const flex = parent && ((parent.attrs.style || '').includes('flex') || (parent.attrs.style || '').includes('grid'))
+ // #ifdef MP-WEIXIN
+ // 检查基础库版本 virtualHost 是否可用
+ && !(node.c && wx.getNFCAdapter) // eslint-disable-line
+ // #endif
+ // #ifndef MP-WEIXIN || MP-QQ || MP-BAIDU || MP-TOUTIAO
+ && !node.c // eslint-disable-line
+ // #endif
+ if (flex) {
+ node.f = ';max-width:100%'
+ }
+
+ if (children.length >= 50 && node.c && !(styleObj.display || '').includes('flex')) {
+ mergeNodes(children)
+ }
+ // #endif
+
+ for (const key in styleObj) {
+ if (styleObj[key]) {
+ const val = `;${key}:${styleObj[key].replace(' !important', '')}`
+ /* #ifndef APP-PLUS-NVUE */
+ if (flex && ((key.includes('flex') && key !== 'flex-direction') || key === 'align-self' || key.includes('grid') || styleObj[key][0] === '-' || (key.includes('width') && val.includes('%')))) {
+ node.f += val
+ if (key === 'width') {
+ attrs.style += ';width:100%'
+ }
+ } else /* #endif */ {
+ attrs.style += val
+ }
+ }
+ }
+ attrs.style = attrs.style.substr(1) || undefined
+ // #ifdef (MP-WEIXIN || MP-QQ) && VUE3
+ for (const key in attrs) {
+ if (!attrs[key]) {
+ delete attrs[key]
+ }
+ }
+ // #endif
+}
+
+/**
+ * @description 解析到文本
+ * @param {String} text 文本内容
+ */
+Parser.prototype.onText = function (text) {
+ if (!this.pre) {
+ // 合并空白符
+ let trim = ''
+ let flag
+ for (let i = 0, len = text.length; i < len; i++) {
+ if (!blankChar[text[i]]) {
+ trim += text[i]
+ } else {
+ if (trim[trim.length - 1] !== ' ') {
+ trim += ' '
+ }
+ if (text[i] === '\n' && !flag) {
+ flag = true
+ }
+ }
+ }
+ // 去除含有换行符的空串
+ if (trim === ' ') {
+ if (flag) return
+ // #ifdef VUE3
+ else {
+ const parent = this.stack[this.stack.length - 1]
+ if (parent && parent.name[0] === 't') return
+ }
+ // #endif
+ }
+ text = trim
+ }
+ const node = Object.create(null)
+ node.type = 'text'
+ // #ifdef (MP-BAIDU || MP-ALIPAY || MP-TOUTIAO) && VUE3
+ node.attrs = {}
+ // #endif
+ node.text = decodeEntity(text)
+ if (this.hook(node)) {
+ // #ifdef MP-WEIXIN
+ if (this.options.selectable === 'force' && system.includes('iOS') && !uni.canIUse('rich-text.user-select')) {
+ this.expose()
+ }
+ // #endif
+ const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
+ siblings.push(node)
+ }
+}
+
+/**
+ * @description html 词法分析器
+ * @param {Object} handler 高层处理器
+ */
+function Lexer (handler) {
+ this.handler = handler
+}
+
+/**
+ * @description 执行解析
+ * @param {String} content 要解析的文本
+ */
+Lexer.prototype.parse = function (content) {
+ this.content = content || ''
+ this.i = 0 // 标记解析位置
+ this.start = 0 // 标记一个单词的开始位置
+ this.state = this.text // 当前状态
+ for (let len = this.content.length; this.i !== -1 && this.i < len;) {
+ this.state()
+ }
+}
+
+/**
+ * @description 检查标签是否闭合
+ * @param {String} method 如果闭合要进行的操作
+ * @returns {Boolean} 是否闭合
+ * @private
+ */
+Lexer.prototype.checkClose = function (method) {
+ const selfClose = this.content[this.i] === '/'
+ if (this.content[this.i] === '>' || (selfClose && this.content[this.i + 1] === '>')) {
+ if (method) {
+ this.handler[method](this.content.substring(this.start, this.i))
+ }
+ this.i += selfClose ? 2 : 1
+ this.start = this.i
+ this.handler.onOpenTag(selfClose)
+ if (this.handler.tagName === 'script') {
+ this.i = this.content.indexOf('', this.i)
+ if (this.i !== -1) {
+ this.i += 2
+ this.start = this.i
+ }
+ this.state = this.endTag
+ } else {
+ this.state = this.text
+ }
+ return true
+ }
+ return false
+}
+
+/**
+ * @description 文本状态
+ * @private
+ */
+Lexer.prototype.text = function () {
+ this.i = this.content.indexOf('<', this.i) // 查找最近的标签
+ if (this.i === -1) {
+ // 没有标签了
+ if (this.start < this.content.length) {
+ this.handler.onText(this.content.substring(this.start, this.content.length))
+ }
+ return
+ }
+ const c = this.content[this.i + 1]
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ // 标签开头
+ if (this.start !== this.i) {
+ this.handler.onText(this.content.substring(this.start, this.i))
+ }
+ this.start = ++this.i
+ this.state = this.tagName
+ } else if (c === '/' || c === '!' || c === '?') {
+ if (this.start !== this.i) {
+ this.handler.onText(this.content.substring(this.start, this.i))
+ }
+ const next = this.content[this.i + 2]
+ if (c === '/' && ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
+ // 标签结尾
+ this.i += 2
+ this.start = this.i
+ this.state = this.endTag
+ return
+ }
+ // 处理注释
+ let end = '-->'
+ if (c !== '!' || this.content[this.i + 2] !== '-' || this.content[this.i + 3] !== '-') {
+ end = '>'
+ }
+ this.i = this.content.indexOf(end, this.i)
+ if (this.i !== -1) {
+ this.i += end.length
+ this.start = this.i
+ }
+ } else {
+ this.i++
+ }
+}
+
+/**
+ * @description 标签名状态
+ * @private
+ */
+Lexer.prototype.tagName = function () {
+ if (blankChar[this.content[this.i]]) {
+ // 解析到标签名
+ this.handler.onTagName(this.content.substring(this.start, this.i))
+ while (blankChar[this.content[++this.i]]);
+ if (this.i < this.content.length && !this.checkClose()) {
+ this.start = this.i
+ this.state = this.attrName
+ }
+ } else if (!this.checkClose('onTagName')) {
+ this.i++
+ }
+}
+
+/**
+ * @description 属性名状态
+ * @private
+ */
+Lexer.prototype.attrName = function () {
+ let c = this.content[this.i]
+ if (blankChar[c] || c === '=') {
+ // 解析到属性名
+ this.handler.onAttrName(this.content.substring(this.start, this.i))
+ let needVal = c === '='
+ const len = this.content.length
+ while (++this.i < len) {
+ c = this.content[this.i]
+ if (!blankChar[c]) {
+ if (this.checkClose()) return
+ if (needVal) {
+ // 等号后遇到第一个非空字符
+ this.start = this.i
+ this.state = this.attrVal
+ return
+ }
+ if (this.content[this.i] === '=') {
+ needVal = true
+ } else {
+ this.start = this.i
+ this.state = this.attrName
+ return
+ }
+ }
+ }
+ } else if (!this.checkClose('onAttrName')) {
+ this.i++
+ }
+}
+
+/**
+ * @description 属性值状态
+ * @private
+ */
+Lexer.prototype.attrVal = function () {
+ const c = this.content[this.i]
+ const len = this.content.length
+ if (c === '"' || c === "'") {
+ // 有冒号的属性
+ this.start = ++this.i
+ this.i = this.content.indexOf(c, this.i)
+ if (this.i === -1) return
+ this.handler.onAttrVal(this.content.substring(this.start, this.i))
+ } else {
+ // 没有冒号的属性
+ for (; this.i < len; this.i++) {
+ if (blankChar[this.content[this.i]]) {
+ this.handler.onAttrVal(this.content.substring(this.start, this.i))
+ break
+ } else if (this.checkClose('onAttrVal')) return
+ }
+ }
+ while (blankChar[this.content[++this.i]]);
+ if (this.i < len && !this.checkClose()) {
+ this.start = this.i
+ this.state = this.attrName
+ }
+}
+
+/**
+ * @description 结束标签状态
+ * @returns {String} 结束的标签名
+ * @private
+ */
+Lexer.prototype.endTag = function () {
+ const c = this.content[this.i]
+ if (blankChar[c] || c === '>' || c === '/') {
+ this.handler.onCloseTag(this.content.substring(this.start, this.i))
+ if (c !== '>') {
+ this.i = this.content.indexOf('>', this.i)
+ if (this.i === -1) return
+ }
+ this.start = ++this.i
+ this.state = this.text
+ } else {
+ this.i++
+ }
+}
+
+export default Parser
diff --git a/uni_modules/mp-html/package.json b/uni_modules/mp-html/package.json
new file mode 100644
index 0000000..5959db8
--- /dev/null
+++ b/uni_modules/mp-html/package.json
@@ -0,0 +1,76 @@
+{
+ "id": "mp-html",
+ "displayName": "mp-html 富文本组件【全端支持,支持编辑、latex等扩展】",
+ "version": "v2.4.2",
+ "description": "一个强大的富文本组件,高效轻量,功能丰富",
+ "keywords": [
+ "富文本",
+ "编辑器",
+ "html",
+ "rich-text",
+ "editor"
+ ],
+ "repository": "https://github.com/jin-yufeng/mp-html",
+ "dcloudext": {
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/mp-html",
+ "type": "component-vue"
+ },
+ "uni_modules": {
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "u",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "y",
+ "联盟": "y"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/mp-html/static/app-plus/mp-html/js/handler.js b/uni_modules/mp-html/static/app-plus/mp-html/js/handler.js
new file mode 100644
index 0000000..1d986bd
--- /dev/null
+++ b/uni_modules/mp-html/static/app-plus/mp-html/js/handler.js
@@ -0,0 +1 @@
+"use strict";function t(t){for(var e=Object.create(null),n=t.attributes.length;n--;)e[t.attributes[n].name]=t.attributes[n].value;return e}function e(){a[1]&&(this.src=a[1],this.onerror=null),this.onclick=null,this.ontouchstart=null,uni.postMessage({data:{action:"onError",source:"img",attrs:t(this)}})}function n(){window.unloadimgs-=1,0===window.unloadimgs&&uni.postMessage({data:{action:"onReady"}})}function o(r,s,c){for(var d=0;d0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("navigateTo",{url:encodeURI(n)})},navigateBack:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.delta;a("navigateBack",{delta:parseInt(n)||1})},switchTab:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("switchTab",{url:encodeURI(n)})},reLaunch:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("reLaunch",{url:encodeURI(n)})},redirectTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("redirectTo",{url:encodeURI(n)})},getEnv:function(e){window.plus?e({plus:!0}):e({h5:!0})},postMessage:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};a("postMessage",e.data||{})}},r=/uni-app/i.test(navigator.userAgent),d=/Html5Plus/i.test(navigator.userAgent),s=/complete|loaded|interactive/;var w=window.my&&navigator.userAgent.indexOf("AlipayClient")>-1;var u=window.swan&&window.swan.webView&&/swan/i.test(navigator.userAgent);var c=window.qq&&window.qq.miniProgram&&/QQ/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var g=window.tt&&window.tt.miniProgram&&/toutiaomicroapp/i.test(navigator.userAgent);var v=window.wx&&window.wx.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var p=window.qa&&/quickapp/i.test(navigator.userAgent);for(var l,_=function(){window.UniAppJSBridge=!0,document.dispatchEvent(new CustomEvent("UniAppJSBridgeReady",{bubbles:!0,cancelable:!0}))},f=[function(e){if(r||d)return window.__dcloud_weex_postMessage||window.__dcloud_weex_?document.addEventListener("DOMContentLoaded",e):window.plus&&s.test(document.readyState)?setTimeout(e,0):document.addEventListener("plusready",e),o},function(e){if(v)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.wx.miniProgram},function(e){if(c)return window.QQJSBridge&&window.QQJSBridge.invoke?setTimeout(e,0):document.addEventListener("QQJSBridgeReady",e),window.qq.miniProgram},function(e){if(w){document.addEventListener("DOMContentLoaded",e);var n=window.my;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(u)return document.addEventListener("DOMContentLoaded",e),window.swan.webView},function(e){if(g)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(p){window.QaJSBridge&&window.QaJSBridge.invoke?setTimeout(e,0):document.addEventListener("QaJSBridgeReady",e);var n=window.qa;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){return document.addEventListener("DOMContentLoaded",e),o}],m=0;m
\ No newline at end of file
diff --git a/uni_modules/p-f-unicom/1.jpg b/uni_modules/p-f-unicom/1.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a27b39253e1f96d45cb6105f3a5059c473f1fb55
GIT binary patch
literal 80482
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 |