fix(ui): 支持首页点击搜索按钮或者搜索框进入登录页面及优化构建输出微信小程序

This commit is contained in:
2025-10-31 11:14:59 +08:00
parent aa0b776e6b
commit 6673a494cf
6 changed files with 210 additions and 15 deletions

View File

@@ -49,9 +49,7 @@ var config = {
* 1.开发调试模式 * 1.开发调试模式
* 去掉注释 ...devCfg; * 去掉注释 ...devCfg;
* 注释掉 ...releaseCfg, * 注释掉 ...releaseCfg,
* 2.发行/发布模式,例如通过`HBuilder>发行>小程序微信`的时候, * 2.发行/发布模式,例如通过`HBuilder>发行>小程序微信`的时候,原理是:
* 注释掉 ...devCfg;
* 去掉注释 ...releaseCfg,
* 然后将 `import site from "../site.js";`追加到 `unpackage\dist\build\mp-weixin\common\vendor.js` 文件内容开头部分 * 然后将 `import site from "../site.js";`追加到 `unpackage\dist\build\mp-weixin\common\vendor.js` 文件内容开头部分
* 然后将 site.js 文件放到 `unpackage\dist\build\mp-weixin\` 目录下面 * 然后将 site.js 文件放到 `unpackage\dist\build\mp-weixin\` 目录下面
*/ */

View File

@@ -1,7 +1,7 @@
<template> <template>
<view data-component-name="diy-search" class="diy-search"> <view data-component-name="diy-search" class="diy-search">
<view class="diy-search-wrap" :class="value.positionWay" :style="fixedCss"> <view class="diy-search-wrap" :class="value.positionWay" :style="fixedCss">
<view :class="['search-box','search-box-'+value.searchStyle]" :style="searchWrapCss" @click="search()"> <view :class="['search-box','search-box-'+value.searchStyle]" :style="searchWrapCss" @click="handlerSearchClick" @tap="handlerSearchClick">
<block v-if="[1,2].includes(value.searchStyle)"> <block v-if="[1,2].includes(value.searchStyle)">
<view class="img" v-if="value.searchStyle == 2 && value.iconType == 'img'"> <view class="img" v-if="value.searchStyle == 2 && value.iconType == 'img'">
<image :src="$util.img(value.imageUrl)" mode="heightFix"/> <image :src="$util.img(value.imageUrl)" mode="heightFix"/>
@@ -10,22 +10,22 @@
:value="value.style ? value.style : 'null'" :value="value.style ? value.style : 'null'"
:style="{ maxWidth: 30 * 2 + 'rpx', maxHeight: 30 * 2 + 'rpx' }"></diy-icon> :style="{ maxWidth: 30 * 2 + 'rpx', maxHeight: 30 * 2 + 'rpx' }"></diy-icon>
<view class="search-content" :style="inputStyle"> <view class="search-content" :style="inputStyle">
<input type="text" class="uni-input ns-font-size-base" maxlength="50" :placeholder="value.title" v-model="searchText" @confirm="search()" disabled="true" :placeholderStyle="placeholderStyle" /> <input type="text" class="uni-input ns-font-size-base" maxlength="50" :placeholder="value.title" v-model="searchText" @confirm="handlerSearchClick" disabled="true" :placeholderStyle="placeholderStyle" />
<text class="iconfont icon-sousuo3" @click.stop="search()" :style="{ color: value.textColor ? value.textColor : 'rgba(0,0,0,0)' }"></text> <text class="iconfont icon-sousuo3" @click.stop="handlerSearchClick" @tap="handlerSearchClick" :style="{ color: value.textColor ? value.textColor : 'rgba(0,0,0,0)' }"></text>
</view> </view>
</block> </block>
<block v-if="value.searchStyle == 3"> <block v-if="value.searchStyle == 3">
<view class="search-content" :style="inputStyle" @click.stop="search()"> <view class="search-content" :style="inputStyle" @click.stop="handlerSearchClick" @tap="handlerSearchClick">
<text class="iconfont icon-sousuo3" :style="{ color: value.textColor ? value.textColor : 'rgba(0,0,0,0)' }"></text> <text class="iconfont icon-sousuo3" :style="{ color: value.textColor ? value.textColor : 'rgba(0,0,0,0)' }"></text>
<input type="text" class="uni-input ns-font-size-base" maxlength="50" :placeholder="value.title" v-model="searchText" @confirm="search()" disabled="true" @click.stop="search()" :placeholderStyle="placeholderStyle" /> <input type="text" class="uni-input ns-font-size-base" maxlength="50" :placeholder="value.title" v-model="searchText" @confirm="handlerSearchClick" disabled="true" @click.stop="handlerSearchClick" @tap="handlerSearchClick" :placeholderStyle="placeholderStyle" />
<text class="search-content-btn" @click.stop="search()" :style="{ 'backgroundColor': value.pageBgColor ? value.pageBgColor : 'rgba(0,0,0,0)' }">搜索</text> <text class="search-content-btn" @click.stop="handlerSearchClick" @tap="handlerSearchClick" :style="{ 'backgroundColor': value.pageBgColor ? value.pageBgColor : 'rgba(0,0,0,0)' }">搜索</text>
</view> </view>
<view class="img" v-if="value.iconType == 'img'" @click.stop="redirectTo(value.searchLink)"><image :src="$util.img(value.imageUrl)" mode="heightFix"/> <view class="img" v-if="value.iconType == 'img'" @click.stop="handlerRedirectToClick(value.searchLink)" @tap="handlerRedirectToClick(value.searchLink)"><image :src="$util.img(value.imageUrl)" mode="heightFix"/>
</view> </view>
<diy-icon class="icon" v-if="value.iconType == 'icon'" :icon="value.icon" <diy-icon class="icon" v-if="value.iconType == 'icon'" :icon="value.icon"
:value="value.style ? value.style : 'null'" :value="value.style ? value.style : 'null'"
:style="{ maxWidth: 30 * 2 + 'rpx', maxHeight: 30 * 2 + 'rpx' }" :style="{ maxWidth: 30 * 2 + 'rpx', maxHeight: 30 * 2 + 'rpx' }"
@click.stop="redirectTo(value.searchLink)"></diy-icon> @click.stop="handlerRedirectToClick(value.searchLink)" @tap="handlerRedirectToClick(value.searchLink)"></diy-icon>
</block> </block>
</view> </view>
</view> </view>
@@ -44,6 +44,8 @@
menuButtonInfo = uni.getMenuButtonBoundingClientRect(); menuButtonInfo = uni.getMenuButtonBoundingClientRect();
// #endif // #endif
import DiyMinx from './minx.js'
// 搜索 // 搜索
export default { export default {
name: 'diy-search', name: 'diy-search',
@@ -77,6 +79,7 @@
moduleHeight: 0 moduleHeight: 0
}; };
}, },
mixins: [DiyMinx],
computed: { computed: {
fixedCss() { fixedCss() {
var obj = ''; var obj = '';
@@ -217,6 +220,18 @@
}); });
}).exec(); }).exec();
}) })
},
async handlerRedirectToClick(link) {
await this.__$emitEvent({eventName: 'search-tap', data: link, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.redirectTo(link);
}})
},
async handlerSearchClick(item) {
await this.__$emitEvent({eventName: 'search-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.search();
}})
} }
} }
}; };

View File

@@ -1,4 +1,7 @@
{ {
"scripts": {
"release-mp-weixin": "node scripts/mp-weixin.patch.js"
},
"devDependencies": { "devDependencies": {
"terser-webpack-plugin": "^5.3.10" "terser-webpack-plugin": "^5.3.10"
} }

View File

@@ -32,7 +32,8 @@ export default {
'merch-list-tap', 'merch-list-tap',
'map-tap', 'map-tap',
'img-ads-tap', 'img-ads-tap',
'many-goods-list-tap' 'many-goods-list-tap',
'search-tap',
], this._handleDiyGroupInteractionEvent); ], this._handleDiyGroupInteractionEvent);
}, },
beforeDestroy() { beforeDestroy() {

View File

@@ -86,9 +86,7 @@ var config = {
* 1.开发调试模式 * 1.开发调试模式
* 去掉注释 ...devCfg; * 去掉注释 ...devCfg;
* 注释掉 ...releaseCfg, * 注释掉 ...releaseCfg,
* 2.发行/发布模式,例如通过`HBuilder>发行>小程序微信`的时候, * 2.发行/发布模式,例如通过`HBuilder>发行>小程序微信`的时候,原理
* 注释掉 ...devCfg;
* 去掉注释 ...releaseCfg,
* 然后将 `import site from "../site.js";`追加到 `unpackage\dist\build\mp-weixin\common\vendor.js` 文件内容开头部分 * 然后将 `import site from "../site.js";`追加到 `unpackage\dist\build\mp-weixin\common\vendor.js` 文件内容开头部分
* 然后将 site.js 文件放到 `unpackage\dist\build\mp-weixin\` 目录下面 * 然后将 site.js 文件放到 `unpackage\dist\build\mp-weixin\` 目录下面
*/ */

180
scripts/mp-weixin.patch.js Normal file
View File

@@ -0,0 +1,180 @@
#!/usr/bin/env node
/**
* fix-wechat-miniapp.js
*
* 该脚本用于修复微信小程序的一些问题:
* 1. 将项目根目录下的 site.js 文件拷贝到 unpackage/dist/build/mp-weixin 目录下,如果文件存在则覆盖
* 2. 将 `import site from "../site.js";` 这段代码追加到
* unpackage/dist/build/mp-weixin/common/vendor.js 文件内容开头部分,
* 如果这个文件开头已经有了这行代码,则不追加
*
* 使用:
* node fix-wechat-miniapp.js
*
* 注意:
* - 在 Windows 上路径使用反斜杠也是可以的;脚本使用 path.join 来兼容不同平台。
* - 运行前请确认在项目根目录运行site.js 在当前工作目录下)。
*/
const fs = require('fs');
const fsp = fs.promises;
const path = require('path');
const { exec } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);
async function commonPatch(mode = 'production') {
try {
// 根据当前脚本所在目录scripts定位到项目根目录
const cwd = path.join(__dirname, '..');
const srcSitePath = path.join(cwd, 'site.js');
const destDir = path.join(cwd, 'unpackage', 'dist', mode === 'production' ? 'build' : 'dev', 'mp-weixin');
const destSitePath = path.join(destDir, 'site.js');
const vendorPath = path.join(destDir, 'common', 'vendor.js');
// 1) 检查源文件是否存在
const srcExists = await exists(srcSitePath);
if (!srcExists) {
console.error(`源文件不存在: ${srcSitePath}`);
process.exitCode = 2;
return;
}
// 确保目标目录存在
await ensureDir(destDir);
// 复制 site.js 到目标目录(覆盖)
await fsp.copyFile(srcSitePath, destSitePath);
console.log(`已拷贝: ${srcSitePath} -> ${destSitePath}`);
// 2) 处理 vendor.js在开头追加 import 语句(如果还没有的话)
const vendorExists = await exists(vendorPath);
if (!vendorExists) {
console.warn(`目标 vendor.js 不存在,跳过追加 import。路径: ${vendorPath}`);
return;
}
let vendorContent = await fsp.readFile(vendorPath, 'utf8');
const importLine = 'import site from "../site.js";';
// 检查文件开头(例如前 5 行或前 400 字符)是否已经包含该 import 语句
const inspectPrefix = vendorContent.slice(0, 400);
const importRegex = new RegExp(
// 匹配可能存在的引号或分号差异,但我们只需要确切匹配这行文字
'^\\s*import\\s+site\\s+from\\s+[\'"]\\.\\./site\\.js[\'"];?',
'm'
);
if (importRegex.test(inspectPrefix)) {
console.log('vendor.js 开头已包含 import site 语句,跳过追加。');
return;
}
// 如果文件以 shebang 或者注释开头,决定放在哪:通常我们把 import 放在文件最顶部index 0
// 但如果文件以 "use strict"; 等指令开头import 必须在所有非-import/非-comment 语句之前。
// 简单实现:如果文件开头有 UTF BOM保留它然后把 importLine + newline 插入文件最前面。
// 保留原始换行风格(若可能)
const eol = vendorContent.includes('\r\n') ? '\r\n' : '\n';
let prefix = '';
// 保留可能的 BOM
if (vendorContent.charCodeAt(0) === 0xfeff) {
prefix = '\uFEFF';
vendorContent = vendorContent.slice(1);
}
const newContent = prefix + importLine + eol + vendorContent;
await fsp.writeFile(vendorPath, newContent, 'utf8');
console.log(`已在 vendor.js 开头追加: ${importLine}`);
} catch (err) {
console.error('发生错误:', err);
process.exitCode = 1;
}
}
/**
* 使用系统命令创建ZIP跨平台
* @param {string} sourceDir - 要压缩的目录路径
* @param {string} outputDir - 压缩文件输出目录
* @returns {Promise<string>} - 压缩文件的路径
*/
async function createZipWithSystemCommand(sourceDir, outputDir) {
// 检查源目录
if (!fs.existsSync(sourceDir)) {
throw new Error(`源目录不存在: ${sourceDir}`);
}
// 生成文件名
const dateString = new Date().toISOString().split('T')[0];
const zipFileName = `mp-weixin-${dateString}-${new Date().getTime()}.zip`;
const zipFilePath = path.join(outputDir, zipFileName);
let command;
// 根据操作系统选择命令
if (process.platform === 'win32') {
// Windows: 使用PowerShell的Compress-Archive
const sourcePath = sourceDir.replace(/'/g, "''");
const destPath = zipFilePath.replace(/'/g, "''");
command = `powershell -Command "Compress-Archive -Path '${sourcePath}\\*' -DestinationPath '${destPath}' -Force"`;
} else {
// Linux/Mac: 使用zip命令
const sourceBase = path.dirname(sourceDir);
const sourceName = path.basename(sourceDir);
command = `cd '${sourceBase}' && zip -r '${zipFilePath}' '${sourceName}' -x '*/node_modules/*' '*.git/*' '*.DS_Store' '*.log'`;
}
try {
console.log(`执行命令: ${command}`);
const { stdout, stderr } = await execAsync(command);
if (stderr) {
console.warn('警告:', stderr);
}
console.log(`✅ ZIP文件创建完成: ${zipFileName}`);
return zipFilePath;
} catch (error) {
throw new Error(`系统命令执行失败: ${error.message}`);
}
}
async function main() {
// 1) 打补丁
await commonPatch('production');
// await commonPatch('development');
// 2) 创建 ZIP 文件
const cwd = path.join(__dirname, '..');
const sourceDir = path.join(cwd, 'unpackage', 'dist', 'build', 'mp-weixin');
const destDir = path.join(cwd, 'unpackage', 'dist', 'build');
const zipFilePath = await createZipWithSystemCommand(sourceDir, destDir);
console.log(`ZIP 文件路径: ${zipFilePath}`);
}
async function exists(p) {
try {
await fsp.access(p, fs.constants.F_OK);
return true;
} catch (e) {
return false;
}
}
async function ensureDir(dirPath) {
try {
await fsp.mkdir(dirPath, { recursive: true });
} catch (e) {
// ignore if exists
if (e.code !== 'EEXIST') throw e;
}
}
main();