1.修改 vscode 快捷键
(1)vscode将向下复制行,改为 ctrl+D
(2)设置 volar 快捷键,并打开拆分图标
快捷键:
拆分图标:

设置左右折叠的标签种类:

// 左侧不折叠的标签,其余标签会折叠
"volar.splitEditors.layout.left": ["script", "scriptSetup", "styles"],
// 右侧不折叠的标签,其余标签会折叠
"volar.splitEditors.layout.right": ["template", "customBlocks"],
2.vant时间选择器组件的策略模版
模版中定义:

vant 选择日期的组件:需要两个处理回调函数,一个用来改变 html 显示 内容,一个用来调用接口发起请求
同时还有一个 formatter 函数,用来处理选中的组件数据绑定到data 的数据里面
这个组件的处理较为复杂!

注意:经项目上线测试
不要用 formatter,有重大 bug:
在我们选择日期,还处于滚动状态的时候,就点击了确定触发请求的时候,formatter是不会生效的
这就导致了最新的请求用的是上一次的参数year 和 month,而页面上显示的确是最新的时间
经测试,我们发现 changDate 是新的,而 year 和 month 是旧的:

所以改用在发送请求的时候使用 changDate 切分作为参数:

所以,change 回调是选择了就触发,即使滚动没有结束
而formatter是滚动结束时才会生效的
所以更建议依赖 change 回调,而不是 formatter 回调!
3.无限滚动组件的分页接口策略
无限滚动组件通常用于 app 和小程序,这时我们分页接口传参lastSortKey而不是 pageIndex
原理:后端返回的列表数据每一个对象都有一个索引,我们取每次返回的数据列表的最后一项的索引,作为下一次的参数传入后端,后端下一次就会从这个索引的下一个位置给我们返回数据!


sortKey 就是一个数据的索引(相当于是主键唯一标识)
4.用指令的方式使用 element-ui的 Loading 组件
Element提供了两种调用Loading的方法:指令和服务。
指令
对于自定义指令 v-loading,只需要绑定 Boolean即可,默认情况下,loading遮罩会插入到绑定元素的子节点通过添加 body修饰符,可以使遮罩插入至DOM中的body上。
<div
v-loading="true"
element-loading-text="拼命加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
>
</div>
注意:当使用指令方式时,全屏遮罩需要添加fullscreen修饰符(遮罩会插入至body上),此时若需要锁定屏幕的滚动,可以使用lock修饰符。(当使用服务方式时,遮罩默认即为全屏,无需额外设置)
服务
Loading 还可以以服务的方式调用。引入 Loading 服务:
import { Loading } from 'element-ui';
在需要调用时:
Loading.service(options);
其中,options参数为loading的配置项,具体见下表。LoadingService会返回一个 Loading 实例,可通过调用该实例的close方法来关闭它:
const loadingInstance = Loading.service(options);
this.$nextTick(() => { // 以服务的方式调用的 Loading 需要异步关闭,当数据返回了,重新渲染页面之后(即$nextTick),关闭 Loading
loadingInstance.close();
});
需要注意的是,以服务的方式调用的全屏 Loading 是单例的:若在前一个全屏 Loading 关闭前再次调用全屏 Loading,并不会创建一个新的 Loading 实例,而是返回现有全屏 Loading 的实例:
const loadingInstance1 = Loading.service({ fullscreen: true });
const loadingInstance2 = Loading.service({ fullscreen: true });
console.log(loadingInstance1 === loadingInstance2); // true
此时调用它们中任意一个的close方法都能关闭这个全屏 Loading。
如果完整引入了 Element,那么 Vue.prototype 上会有一个全局方法loading,它的调用方式为:this.$loading(options),同样会返回一个 Loading 实例。
5.dingtalk-jsapi在 vue 中的使用
介绍
"DingTalk JSAPI" 是指钉钉开放平台提供的 JavaScript API,用于在钉钉客户端中集成和使用钉钉的功能和服务。
钉钉是一款企业级的即时通讯和协作工具,针对企业内部沟通和协作提供了一系列功能,例如消息通知、日程安排、文件共享、考勤管理等。为了扩展钉钉的功能和让开发者能够在自己的应用中嵌入钉钉特性,钉钉开放平台提供了一套 API,其中就包括了 "DingTalk JSAPI"。
使用 DingTalk JSAPI,开发者可以通过 JavaScript 调用钉钉客户端提供的接口,实现与钉钉的交互。这些接口包括发送消息、获取用户信息、打开钉钉的特定页面、调起钉钉的功能模块等。通过集成 DingTalk JSAPI,开发者可以在自己的应用中实现与钉钉的无缝对接,从而更好地满足企业的协作和通讯需求。
需要注意的是,DingTalk JSAPI 主要用于在钉钉客户端中运行的应用,而不是网页上的应用。开发者需要按照钉钉开放平台的规范和文档进行开发和集成。具体的接口和功能详情可以参考钉钉开放平台的官方文档。
6.node 版本适配 node-sass插件
node14版本的 node 是适配 node-sass的
可以下载node14.15或者node14.19版本
对应的 node-sass版本为:
"node-sass": "^4.12.0",
"sass-loader": "^8.0.2",
注意:如果是 node16 版本,就要使用 sass 插件而不是 node-sass了
7.使用公共的模版组件时,要善于使用插槽
把公共的部分写在组件中,不公共的部分用插槽由外界传入进来!
或者使用默认插槽,在特殊的时候,把不一样的内容传入插槽,可以覆盖默认插槽
常用于:列表组件
8.当外层有 click 事件时,要阻止事件冒泡
使用@click.stop绑定事件,这样此 click 事件就只会由自己触发了,不会触发外层组件的事件!
9.前端向后端的安全传参方式
传参示例:
{
"param": {
"rankKind": 1,
"scopType": "1",
"year": "2023",
"month": "2"
},
"sign": "3463dc5da317637951cc5ec871bb5e68",
"time": 1677204422678
}
这是前端向后端传递参数的方式,其中包含了三个参数:
rand
: 这是一个随机数,用于在每次请求时生成一个不同的值。随机数可以用于防止缓存或重放攻击,以确保每次请求都是唯一的。sign
: 这是一个签名参数,用于验证请求的合法性和完整性。签名通常是通过对其他参数进行加密或散列计算而得到的值。后端可以使用相同的算法和密钥来验证签名,并确保参数未被篡改。time
: 这是一个时间戳,表示请求发起的时间。时间戳用于确保请求在一定时间范围内有效,以防止请求的重放。
这种在前端向后端传递参数时加入随机数、签名和时间戳的方式,可以增加请求的安全性和防御性,防止恶意攻击和参数篡改。通过这些参数,后端可以验证请求的合法性,并确保参数的完整性和时效性。
具体的加密算法、签名方法和参数处理方式可能因具体的应用场景和后端实现而有所不同。在具体使用时,您需要参考后端接口文档或与后端开发人员进行沟通,以了解参数的具体含义和处理方式。
10.用 vue 构建小程序(钉钉小程序)的目录策略及写法

写在 pages 文件夹里面,这里不用 main.js,而是写 app.js
app.js:
import Vue from 'vue';
import App from '@/views/expand/App';
import store from './store';
import router from './router';
import 'lib-flexible/flexible.js';
import '@/pages/expand/permission';
import * as dd from 'dingtalk-jsapi';
import {
Loading, Message, Select, Option, Input,
} from 'element-ui';
import Vconsole from 'vconsole';
import { message } from '../../utils/message';
Vue.use(Select);
Vue.use(Option);
Vue.use(Input);
Vue.use(Loading);
// 引用你的文件到 main.js
Vue.prototype.$message = message; // 在 main.js 内挂载element的地方下面写上这一句
// Vue.prototype.$message = Message;
// Vue.prototype.$loading = Loading;
// Vue.prototype.$loading = Loading.service;
// 此方式为整体加载,也可按需进行加载
Vue.prototype.$dd = dd; //这里绑定了钉钉 jsAPI
// 只有测试环境和开发环境才显示 vConsole
if (process.env.VUE_APP_ENV === 'test' || process.env.VUE_APP_ENV === 'development' || process.env.VUE_APP_ENV === 'pre') {
let vConsole = new Vconsole();
Vue.use(vConsole);
}
new Vue({
router,
store,
render: (h) => h(App),
}).$mount('#app');
permission.js是对于 router 的处理:
import router from '@/pages/expand/router';
router.beforeEach(async (to, from, next) => {
next();
});
router.onError((error) => {
const pattern = /Loading chunk (\d)+ failed/g;
const isChunkLoadFailed = error.message.match(pattern); //使用正则表达式模式匹配错误信息 (error.message),判断是否出现了 "Loading chunk" 加载失败的错误。
const targetPath = router.history.pending.fullPath;//获取当前未完成的路由跳转的完整路径。
if (isChunkLoadFailed) {
Toast.text(error.msg || '网络延迟,请检查你的网络设置后,刷新重试');//在出现 chunk 加载失败时显示一个提示信息,告诉用户网络延迟,并建议检查网络设置后刷新重试。
}
});
11.对于element 的 Message 组件二次封装
对于element 的 Message 组件二次封装
其实这里相当于使用了单例模式,因为全局只能有一个 Message 组件被创建
../../utils/message是封装了 element 的 Message 组件,为了防止element点击多次弹出message弹框
// 防止element点击多次弹出message弹框
// 创建一个js文件将此内容放入即可
import { Message } from 'element-ui';
let messageval = null; //有一个唯一的弹窗对象
const Messages = (opt) => {
opt.customClass = 'messageCustomClass';
// opt.duration = 60000;
if (messageval) { // 如果已经有一个message
messageval.close(); // 将上一个关闭
}
messageval = Message(opt); //然后开启本次的新的,把参数传入 element 的Message组件形成弹窗
};
['error', 'success', 'info', 'warning'].forEach(type => { // 判断弹窗类型
Messages[type] = (opt) => { //给Messages方法设置几个属性,每个属性是一个状态下的函数,type 为类型,opt 为展示的字符串
if (typeof opt === 'string') {
opt = { //作为参数传入 Messages 函数
message: opt,
};
}
opt.type = type;
return Messages(opt);
};
});
export const message = Messages;
使用:
this.$message.error(res.msg || "请求失败");
this.$message.success(res.msg || "请求失败");
为什么可以给方法设置属性呢?
在 JavaScript 中,函数也是对象的一种。函数可以拥有属性和方法,就像普通的对象一样。这是因为在 JavaScript 中,函数被视为一种特殊的对象类型,可以拥有可执行的代码块(函数体)和其他属性。
在给定的代码示例中,Messages
被定义为一个函数,但它也被用作一个对象。通过给函数对象设置属性,可以为函数添加额外的功能或元数据,使其具有更多的灵活性和复用性。
在代码中,Messages[type]
这种语法是给 Messages
函数对象动态添加属性。每个属性的键名是通过循环遍历消息框类型数组得到的值,例如 'error'
、'success'
、'info'
、'warning'
。每个属性的值是一个函数,用于处理特定类型的消息框逻辑。
通过这种方式,可以根据属性名来调用对应类型的消息框函数,实现动态创建和显示不同类型的消息框。
总结来说,虽然 Messages
被定义为一个函数,但它仍然可以当作对象使用,通过为其设置属性来扩展其功能。这种特性让 JavaScript 中的函数更加灵活,既可以执行代码,又可以拥有属性和方法。
所以同理,数组也可以被设置属性!
12.对于单例模式和代理模式的理解
单例模式就是定义一个全局变量,然后保证这个对象在全局只能被创建一次,只能出现一个实例
代理模式在 js 中的体现就是 Proxy 这个 api,应用在了 vue 中,它相当于接管了一个对象,当外界对于这个对象要产生更改的时候,它会替外界做这个事情,相当于把对象又包了一层,好处就是可以在特定的情况下进行特定的回应
而修改对象的方式除了直接obj[a]=b以外,还有一个 Reflect 这个方法可以用来修改对象,具体的好处暂时不清楚