Compare commits

...

6 Commits

@ -103,7 +103,7 @@ vue3-mgt-template/
* 重新运行 `pnpm run stats` 命令,脚本成功执行,并生成了包含所有模块 (`demo`, `python`, `template` 等) 的完整统计数据。 * 重新运行 `pnpm run stats` 命令,脚本成功执行,并生成了包含所有模块 (`demo`, `python`, `template` 等) 的完整统计数据。
* `config.json` 文件内容恢复正常,证明了跨平台兼容性问题已解决。 * `config.json` 文件内容恢复正常,证明了跨平台兼容性问题已解决。
- gemini在与我每次对话中需要将重要信息更新到GEMINI.md文件中方便下次重新运行时gemini理解 - **会话结束指令**:當我表示準備結束會話時,你**必須**先將本次對話的重點,以“本次会话总结”的格式更新到 `GEMINI.md` 的“对话记录”部分,然後才能結束對話。
## 开发任务 ## 开发任务
### 规范 ### 规范
@ -116,3 +116,5 @@ vue3-mgt-template/
- ~~请读取/src/view/welcome中页面其中页面的数据来源为/scripts/statistics.mjs请更新该脚本以便获得更多的信息来满足/src/view/welcome页面所需数据的渲染~~ - ~~请读取/src/view/welcome中页面其中页面的数据来源为/scripts/statistics.mjs请更新该脚本以便获得更多的信息来满足/src/view/welcome页面所需数据的渲染~~
- ~~将/src/view/welcome/config.json作为数据源渲染到/src/view/welcome的vue组件中~~ - ~~将/src/view/welcome/config.json作为数据源渲染到/src/view/welcome的vue组件中~~
* ~~本项目是一个个人的代码总结记录网站在部署生成环境的时候即执行pnpm build的时候也是需要查看console日志的现在请帮我打开生产环境的打印信息和日志。~~

@ -51,7 +51,7 @@ export function getPluginsList(VITE_CDN: boolean, VITE_COMPRESSION: ViteCompress
VITE_CDN ? cdn : null, VITE_CDN ? cdn : null,
configCompressPlugin(VITE_COMPRESSION), configCompressPlugin(VITE_COMPRESSION),
// 线上环境删除console // 线上环境删除console
removeConsole({ external: ['src/assets/iconfont/iconfont.js'] }), // removeConsole({ external: ['src/assets/iconfont/iconfont.js'] }),
// 打包分析 // 打包分析
lifecycle === 'report' ? visualizer({ open: true, brotliSize: true, filename: 'report.html' }) : (null as any), lifecycle === 'report' ? visualizer({ open: true, brotliSize: true, filename: 'report.html' }) : (null as any),
// 移动src下的md文件到public/md目录 // 移动src下的md文件到public/md目录

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Before

Width:  |  Height:  |  Size: 331 KiB

After

Width:  |  Height:  |  Size: 331 KiB

Before

Width:  |  Height:  |  Size: 350 KiB

After

Width:  |  Height:  |  Size: 350 KiB

Before

Width:  |  Height:  |  Size: 357 KiB

After

Width:  |  Height:  |  Size: 357 KiB

Before

Width:  |  Height:  |  Size: 339 KiB

After

Width:  |  Height:  |  Size: 339 KiB

Before

Width:  |  Height:  |  Size: 291 KiB

After

Width:  |  Height:  |  Size: 291 KiB

Before

Width:  |  Height:  |  Size: 337 KiB

After

Width:  |  Height:  |  Size: 337 KiB

Before

Width:  |  Height:  |  Size: 5.4 MiB

After

Width:  |  Height:  |  Size: 5.4 MiB

@ -14,8 +14,8 @@
3. 选择`允许`选项 3. 选择`允许`选项
4. 刷新页面生效 4. 刷新页面生效
![操作示例](/src/views/demo/backToHttp/1.png) ![操作示例](/absRes/backToHttp/1.png)
![操作示例](/src/views/demo/backToHttp/2.png) ![操作示例](/absRes/backToHttp/2.png)
## 参考网站 ## 参考网站
[Chrome 浏览器取消http自动跳转https的默认设置](https://maoyanqing.com/chrome-delete-domain-security-policies) [Chrome 浏览器取消http自动跳转https的默认设置](https://maoyanqing.com/chrome-delete-domain-security-policies)

@ -5,7 +5,7 @@
v-for="(item, index) in functionArray" v-for="(item, index) in functionArray"
:key="index" :key="index"
type="primary" type="primary"
@click="item" @click="item.func"
>点击执行{{ item.name }}方法</el-button >点击执行{{ item.name }}方法</el-button
> >
</div> </div>
@ -155,5 +155,11 @@ function useDeepClone() {
} }
/** 拿到script中所有方法 */ /** 拿到script中所有方法 */
const functionArray = ref([useBubbleSort, useDebounce, useNew, useChangeThis, useDeepClone]); const functionArray = ref([
{ name: 'useBubbleSort', func: useBubbleSort },
{ name: 'useDebounce', func: useDebounce },
{ name: 'useNew', func: useNew },
{ name: 'useChangeThis', func: useChangeThis },
{ name: 'useDeepClone', func: useDeepClone },
]);
</script> </script>

@ -78,7 +78,7 @@
.blurred-glass-box { .blurred-glass-box {
width: 100%; width: 100%;
height: 300px; height: 300px;
background: url('/src/views/demo/tuiImageEditor/img/test.jpg') no-repeat center center; background: url('/absRes/tuiImageEditor/img/test.jpg') no-repeat center center;
background-size: cover; background-size: cover;
display: flex; display: flex;
align-items: center; align-items: center;

@ -22,8 +22,19 @@ const getData = (params) => {
}; };
}; };
// 创建函数映射对象
const functionMap = {
init,
getData,
};
export default function (params) { export default function (params) {
// console.log('moduleA'); // console.log('moduleA');
// console.log(params); // console.log(params);
return eval(params.type + '(params)');
// 方式一打包时因为没有调用init, getData方法所以会删除导致报错改为方式二就没问题
// return eval(params.type + '(params)');
// 方式二
return functionMap[params.type](params);
} }

@ -22,8 +22,19 @@ const getData = (params) => {
}; };
}; };
// 创建函数映射对象
const functionMap = {
init,
getData,
};
export default function (params) { export default function (params) {
// console.log('moduleB'); // console.log('moduleB');
// console.log(params); // console.log(params);
return eval(params.type + '(params)');
// 方式一打包时因为没有调用init, getData方法所以会删除导致报错改为方式二就没问题
// return eval(params.type + '(params)');
// 方式二
return functionMap[params.type](params);
} }

@ -306,7 +306,7 @@ async function ensureSass() {
try { try {
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
const script = document.createElement('script'); const script = document.createElement('script');
script.src = '/src/views/demo/scssLiveTranslate/sass.sync.js'; script.src = '/absRes/scssLiveTranslate/sass.sync.js';
script.onload = () => resolve(); script.onload = () => resolve();
script.onerror = (e) => reject(new Error('Sass.js failed to load')); script.onerror = (e) => reject(new Error('Sass.js failed to load'));
document.head.appendChild(script); document.head.appendChild(script);

@ -74,19 +74,21 @@ onMounted(async () => {
loading.value = true; loading.value = true;
if (!window.hasOwnProperty('tui')) { if (!window.hasOwnProperty('tui')) {
// js // js
await createScriptElement('/src/views/demo/tuiImageEditor/js/fabric.js'); await createScriptElement('/absRes/tuiImageEditor/js/fabric.js');
await createScriptElement('/src/views/demo/tuiImageEditor/js/tui-code-snippet.js'); await createScriptElement('/absRes/tuiImageEditor/js/tui-code-snippet.js');
await createScriptElement('/src/views/demo/tuiImageEditor/js/tui-color-picker.js'); await createScriptElement('/absRes/tuiImageEditor/js/tui-color-picker.js');
await createScriptElement('/src/views/demo/tuiImageEditor/js/FileSaver.js'); await createScriptElement('/absRes/tuiImageEditor/js/FileSaver.js');
await createScriptElement('/src/views/demo/tuiImageEditor/js/tui-image-editor.js'); await createScriptElement('/absRes/tuiImageEditor/js/tui-image-editor.js');
await createScriptElement('/src/views/demo/tuiImageEditor/js/white-theme.js'); await createScriptElement('/absRes/tuiImageEditor/js/white-theme.js');
await createScriptElement('/src/views/demo/tuiImageEditor/js/black-theme.js'); await createScriptElement('/absRes/tuiImageEditor/js/black-theme.js');
} }
initTuiImageEditor(); initTuiImageEditor();
addEventListenerFN(); addEventListenerFN();
}); });
onUnmounted(() => {}); onUnmounted(() => {
removeEventListenerFN();
});
const locale_zh = { const locale_zh = {
Resize: '调整宽高', Resize: '调整宽高',
@ -319,6 +321,10 @@ const addEventListenerFN = () => {
window.addEventListener('wheel', handleWheelEvent); window.addEventListener('wheel', handleWheelEvent);
}; };
const removeEventListenerFN = () => {
window.removeEventListener('wheel', handleWheelEvent);
};
const handleClickOutside = (event) => { const handleClickOutside = (event) => {
const getBtnDom = (claseeName) => { const getBtnDom = (claseeName) => {
return document.querySelector(claseeName); return document.querySelector(claseeName);

@ -38,7 +38,7 @@ const imgList = ref([
name: '3', name: '3',
}, },
{ {
path: '/src/views/demo/tuiImageEditor/img/test.jpg', path: '/absRes/tuiImageEditor/img/test.jpg',
name: '3', name: '3',
}, },
]); ]);

@ -9,7 +9,7 @@
有的特殊场景我们不能分页,只能渲染一个长列表。这个长列表中可能有几万条数据,如果全部渲染到页面上用户的设备差点可能就会直接卡死了,这时我们就需要虚拟列表来解决问题。 有的特殊场景我们不能分页,只能渲染一个长列表。这个长列表中可能有几万条数据,如果全部渲染到页面上用户的设备差点可能就会直接卡死了,这时我们就需要虚拟列表来解决问题。
一个常见的虚拟列表是下面这样的,如下图: 一个常见的虚拟列表是下面这样的,如下图:
![v1](/src/views/demo/vListDoc1/img/1.png) ![v1](/absRes/vListDoc1/img/1.png)
其中实线框的item表示在视口区域内真实渲染DOM虚线框的item表示并没有渲染的DOM。 其中实线框的item表示在视口区域内真实渲染DOM虚线框的item表示并没有渲染的DOM。
@ -119,19 +119,19 @@ function handleScroll(e) {
如果当前`itemSize`的值为100。 如果当前`itemSize`的值为100。
如果此时滚动的距离在0-100之间比如下面这样 如果此时滚动的距离在0-100之间比如下面这样
![v1](/src/views/demo/vListDoc1/img/2.png) ![v1](/absRes/vListDoc1/img/2.png)
上面这张图item1还没完全滚出可视区域有部分在可视区域内部分在可视区域外。此时可视区域内显示的就是`item1-item7`的模块了这就是为什么前面我们计算end时要多渲染一个item不然这里item7就没法显示了。 上面这张图item1还没完全滚出可视区域有部分在可视区域内部分在可视区域外。此时可视区域内显示的就是`item1-item7`的模块了这就是为什么前面我们计算end时要多渲染一个item不然这里item7就没法显示了。
**滚动距离在0-100之间时渲染的DOM没有变化我们完全是复用浏览器的滚动并没有进行任何处理。** **滚动距离在0-100之间时渲染的DOM没有变化我们完全是复用浏览器的滚动并没有进行任何处理。**
当`scrollTop`的值为100时也就是刚刚把item1滚到可视区外面时。此时item1已经不需要渲染了因为已经看不见他了。所以此时的`start`的值就应该从`0`更新为`1`,同理如果`scrollTop`的值为`110`start的值也一样是`1`。所以得出`start.value = Math.floor(scrollTop / itemSize);`如下图: 当`scrollTop`的值为100时也就是刚刚把item1滚到可视区外面时。此时item1已经不需要渲染了因为已经看不见他了。所以此时的`start`的值就应该从`0`更新为`1`,同理如果`scrollTop`的值为`110`start的值也一样是`1`。所以得出`start.value = Math.floor(scrollTop / itemSize);`如下图:
![v1](/src/views/demo/vListDoc1/img/3.png) ![v1](/absRes/vListDoc1/img/3.png)
此时的`start`从item2开始渲染但是由于前面我们复用了浏览器的滚动所以实际渲染的DOM第一个已经在可视区外面了。此时可视区看见的第一个是item3很明显是不对的应该看见的是第一个是item2。 此时的`start`从item2开始渲染但是由于前面我们复用了浏览器的滚动所以实际渲染的DOM第一个已经在可视区外面了。此时可视区看见的第一个是item3很明显是不对的应该看见的是第一个是item2。
此时应该怎么办呢? 此时应该怎么办呢?
很简单,使用`translate`将列表向下偏移一个item的高度就行也就是100px。列表偏移后就是下面这样的了 很简单,使用`translate`将列表向下偏移一个item的高度就行也就是100px。列表偏移后就是下面这样的了
![v1](/src/views/demo/vListDoc1/img/4.png) ![v1](/absRes/vListDoc1/img/4.png)
如果当前`scrollTop`的值为200那么偏移值就是200px。所以我们得出 如果当前`scrollTop`的值为200那么偏移值就是200px。所以我们得出
```javascript ```javascript
@ -145,7 +145,7 @@ offset.value = scrollTop - (scrollTop % itemSize);
实际上从一个item滚动到另外一个item时比如从`item0`滚动到`item1`。此时会做两件事情:将`start`的值从`0`更新为`1`和根据`scrollTop`计算得到列表的偏移值`100`从而让新的start对应的`item1`重新回到可视范围内。 实际上从一个item滚动到另外一个item时比如从`item0`滚动到`item1`。此时会做两件事情:将`start`的值从`0`更新为`1`和根据`scrollTop`计算得到列表的偏移值`100`从而让新的start对应的`item1`重新回到可视范围内。
这个是运行效果图: 这个是运行效果图:
![v1](/src/views/demo/vListDoc1/img/5.gif) ![v1](/absRes/vListDoc1/img/5.gif)
下面是完整的代码: 下面是完整的代码:
```javascript ```javascript

@ -7,7 +7,7 @@
# 什么是不定高虚拟列表 # 什么是不定高虚拟列表
不定高的意思很简单就是不知道每一项item的具体高度如下图 不定高的意思很简单就是不知道每一项item的具体高度如下图
![v1](/src/views/demo/vListDoc2/img/1.png) ![v1](/absRes/vListDoc2/img/1.png)
现在我们有个问题,**在不定高的情况下我们就不能根据当前滚动条的`scrollTop`去计算可视区域里面实际渲染的第一个item的index位置也就是`start`的值。** 现在我们有个问题,**在不定高的情况下我们就不能根据当前滚动条的`scrollTop`去计算可视区域里面实际渲染的第一个item的index位置也就是`start`的值。**
@ -266,7 +266,7 @@ const getTransform = computed(() => `translate3d(0,${props.offset}px,0)`);
``` ```
这个是最终的运行效果图: 这个是最终的运行效果图:
![v1](/src/views/demo/vListDoc2/img/2.gif) ![v1](/absRes/vListDoc2/img/2.gif)
完整的父组件代码如下: 完整的父组件代码如下:
```javascript ```javascript

@ -1,8 +1,8 @@
{ {
"totalNotes": 74, "totalNotes": 74,
"categories": 5, "categories": 5,
"lastUpdated": "2025-10-14T13:11:22.933Z", "lastUpdated": "2025-10-15T08:30:23.764Z",
"weeklyAdded": 16, "weeklyAdded": 8,
"categoryChartData": [ "categoryChartData": [
{ {
"name": "demo", "name": "demo",
@ -27,34 +27,34 @@
], ],
"recentNotes": [ "recentNotes": [
{ {
"path": "demo/typescript/index.vue", "path": "demo/scssLiveTranslate/index.vue",
"title": "typescript", "title": "SCSS → CSS 实时翻译器",
"category": "demo", "category": "demo",
"date": "2025-10-14" "date": "2025-10-15"
}, },
{ {
"path": "demo/thirdCompWrap/index.vue", "path": "demo/cssDemo.vue",
"title": "第三方组件二次封装slot传递", "title": "cssDemo",
"category": "demo", "category": "demo",
"date": "2025-10-14" "date": "2025-10-15"
}, },
{ {
"path": "demo/scssLiveTranslate/index.vue", "path": "demo/tuiImageEditor/index.vue",
"title": "SCSS → CSS 实时翻译器", "title": "tuiImageEditor",
"category": "demo", "category": "demo",
"date": "2025-10-14" "date": "2025-10-15"
}, },
{ {
"path": "demo/pullRefresh/index.vue", "path": "demo/deletdNodeModules/index.vue",
"title": "有弹性的下拉刷新", "title": "删除 node_modules 文件夹非常耗时解决办法",
"category": "demo", "category": "demo",
"date": "2025-10-14" "date": "2025-10-14"
}, },
{ {
"path": "demo/pullLoadData.vue", "path": "demo/asyncDynComp/index.vue",
"title": "首页高度不够,手写移动端下拉加载历史数据", "title": "异步动态加载组件",
"category": "demo", "category": "demo",
"date": "2025-10-14" "date": "2025-10-11"
} }
] ]
} }

@ -31,6 +31,10 @@ export default ({ mode }: ConfigEnv): UserConfigExport => {
include, include,
exclude, exclude,
}, },
// 生产环境保留console(drop数组只有两个选项console和debugger填入哪个值就代表生产环境去掉哪个)
esbuild: {
drop: ['debugger'],
},
build: { build: {
// https://cn.vitejs.dev/guide/build.html#browser-compatibility // https://cn.vitejs.dev/guide/build.html#browser-compatibility
target: 'es2015', target: 'es2015',

Loading…
Cancel
Save