目录
1.实现一个可切换状态的按钮
需求:
- 根据后台传的状态字段(0-1)切换展示颜色。
要求效果:
- 如图,要求解决状态字段0:未解决;1:已解决。分别展示不同的颜色效果。
代码(Javascript)
<template
slot="status"
slot-scope="{ row }"
>
<span :class="{
green: row.status === 0 ,
grey: row.status === 1
}">{{row.status === 0 ? '未解决' : '已解决' }}</span>
</template>
<style>
.green {
display: inline-block;
background: rgba(0, 204, 135, 0.1);
border-radius: 3px;
border: 1px solid rgba(0, 204, 135, 0.2);
color: #00cc87;
padding: 2px 6px;
font-size: 12px;
}
.grey {
display: inline-block;
background: #f5f9ff;
border-radius: 3px;
border: 1px solid rgba(122, 133, 155, 0.2);
color: #3e5071;
padding: 2px 6px;
font-size: 12px;
}
</style>
效果二:
代码(Javascript)
<template slot-scope="{ row }" slot="status">
<span :class="statusMap[row.status].theme">
{{statusMap[row.status].name}}
</span>
</template>
//-----------------------------------------------------------------
export const statusMap: any = {
waitAudit: { name: '待审核', theme: 'waitAudit' },
repulse: { name: '审核驳回', theme: 'repulse' },
auditPass: { name: '授权成功', theme: 'auditPass' },
auditFail: { name: '授权失败', theme: 'auditFail' },
auditing: { name: '授权中', theme: 'auditing' }
};
<style>
.waitAudit {
display: inline-block;
background: rgba(253, 215, 0, 0.103);
border-radius: 10px;
border: 1px solid rgba(253, 215, 0, 0.932);
color: rgba(253, 215, 0, 0.932);
padding: 2px 6px;
font-size: 12px;
}
.repulse {
display: inline-block;
background: rgba(253, 0, 0, 0.132);
border-radius: 10px;
border: 1px solid rgba(253, 0, 0, 0.932);
color: rgba(253, 0, 0, 0.932);
padding: 2px 6px;
font-size: 12px;
}
.auditFail {
display: inline-block;
background: rgba(253, 0, 0, 0.132);
border-radius: 10px;
border: 1px solid rgba(253, 0, 0, 0.932);
color: rgba(253, 0, 0, 0.932);
padding: 2px 6px;
font-size: 12px;
}
.auditPass {
display: inline-block;
background: rgba(135, 253, 0, 0.132);
border-radius: 10px;
border: 1px solid rgba(135, 253, 0, 0.932);
color: rgba(135, 253, 0, 0.932);
padding: 2px 6px;
font-size: 12px;
}
.auditing {
display: inline-block;
background: rgba(0, 160, 253, 0.132);
border-radius: 10px;
border: 1px solid rgba(0, 160, 253, 0.932);
color: rgba(0, 160, 253, 0.932);
padding: 2px 6px;
font-size: 12px;
}
</style>
代码(利用render渲染)
export const statusMap: any = {
waitAudit: { name: '待审核', theme: 'waitAudit', background: 'rgba(253, 215, 0, 0.103)', color:'rgba(253, 215, 0, 0.932)'},
repulse: { name: '审核驳回', theme: 'repulse', background: 'rgba(253, 0, 0, 0.132)', color:'rgba(253, 0, 0, 0.932)' },
auditPass: { name: '授权成功', theme: 'auditPass', background: 'rgba(253, 0, 0, 0.132)', color:'rgba(253, 0, 0, 0.932)' },
auditFail: { name: '授权失败', theme: 'auditFail', background: 'rgba(135, 253, 0, 0.132)', color:'rgba(135, 253, 0, 0.932)' },
auditing: { name: '授权中', theme: 'auditing', background: 'rgba(0, 160, 253, 0.132)', color:'rgba(0, 160, 253, 0.932)' }
};
//-----------------------------------------------------------------
{
title: '状态',
slot: 'status',
fixed: 'right',
width: 120,
align: 'center',
render: (h, params) => {
const row: any = params.row;
if (row.status) {
return h('span', {
style: {
display: 'inline-block',
background: this.statusMap[row.status].background,
color: this.statusMap[row.status].color,
'border-radius': '10px',
border: `1px solid ${this.statusMap[row.status].color}`,
padding: '2px 6px',
'font-size': '12px'
}
}, this.statusMap[row.status].name)
}
}
},
2.代码中更改文字
代码(Javascript)
<Input type="text" v-model="name" :placeholder="`请输入${typeMap[label]}名称`" search />
<script>
@Prop({ default: 'st' })
private label: string;
// 标签名称映射
typeMap: Record<string, any> = {
st: '试题',
sj: '试卷',
klb: '课例包'
}
</script>
3.css常用样式
代码(Javascript)
- css变光标小手
<style>
cursor: pointer;
</style>
- 文本过长省略,并悬浮显示完整内容
<Tooltip class="notice-topic" placement="bottom">
<span>{{ item.topic }}</span>
<div slot="content">
<span class="topic-content">{{ item.topic }}</span>
</div>
</Tooltip>
<style>
.notice-item {
.notice-topic {
overflow: hidden;
width: 182px;
text-overflow: ellipsis; // 省略部分显示为省略号
white-space: nowrap; //不换行
}
.topic-content {
white-space: normal;
}
}
</style>
4.如何监听多组件中的参数
代码(Javascript)
@Prop({ default: () => ({}) })
resource: any;
@Watch('resource', {
deep: true,
immediate: true
})
public getSelect(val){
console.log(val);
debugger;
}
5.如何固定页面的按钮
需求:
- 页面上的按钮正常情况下随页面滚动,当会被遮挡时,将其固定在页面右上角。
要求效果:
代码(Javascript)
<div class="header-tool">
<div :class="{ 'right-btns': isActive, 'right-Fixed': isFixed }" v-if="activeTab === 'waitAudit'">
<Button style="margin-right: 8px;" @click="batchAudit('repulse')"
:disabled="currentSelection.length < 1">批量审核打回</Button>
</div>
</div>
<script>
//按钮是否固定
//不固定按钮时的样式
isActive:boolean = true;
//固定按钮时的样式
isFixed:boolean = false;
//控制右上角按钮始终显示
public handleScroll() {
//1.先获取到dom元素(3种方法)ts中要加类型断言不然会报错:<HTMLElement>
let childDom = <HTMLElement>document.querySelector('.header-tool');
//2. let childDom1 = document.getElementsByClassName('right-btns');
//3. let childDom = <HTMLElement>this.$refs.rightBtns;
//2.getBoundingClientRect获取到元素位置
let topVal = childDom.getBoundingClientRect().top;
console.log(topVal)
//3.监听到距离顶端距离<100时,切换class样式
if (topVal < 100) {
this.isActive = false;
this.isFixed = true;
// childDom.style.position = 'fixed';
// childDom.style.top = '50px';
// childDom.style.right = '34px';
}
else {
this.isActive = true;
this.isFixed = false;
}
}
</script>
<style>
.right-btns {
float: right;
.info-container {
margin-right: 8px;
span {
padding: 0 5px;
font-size: 13px;
color: #66728e;
&.number {
color: #23d7ae;
}
}
}
}
.right-Fixed {
//-----------------
//固定直接用position: fixed;固定;z-index: 10;控制层级显示
float: right;
position: fixed;
top: 12px;
right: 15px;
z-index: 10;
//-------------------
.info-container {
margin-right: 8px;
span {
padding: 0 5px;
font-size: 13px;
color: #66728e;
&.number {
color: #23d7ae;
}
}
}
}
</style>
6.【教考平台】表单验证配置记录
需求:
- 教考平台的CommonForm组件表单进行输入校验的配置写法。
代码(Javascript)
rules: {
taskName: [
{
required: true,
message: '任务名称不能为空',
trigger: 'blur',
type: 'string'
},
{
pattern: /^[^%&]*$/,
message: '任务名称不支持%和&字符',
trigger: 'blur'
},
{
validator: (rule: any, value: string, callback: Function) => {
if (
value &&
value .length > 100
) {
callback(new Error('任务名称不得超过100个字符'));
} else {
callback();
}
}
}
],
7.传参处理
代码(Javascript)
//把name :"name1,name2" 改成 name : p.within("name1","name2")
if (this.name) {
if (/ /.test(this.name) || /%/.test(this.name) || /&/.test(this.name)) {
let nameArr = '';
nameArr = this.name.replace(/%/g, '","').replace(/&/g, '","').replace(/ /g, '","').split(',').join();
nameArr = '"' + nameArr + '"';
orConditionMap.name = 'P.within(' + nameArr + ')';
orConditionMap.identifier = 'P.within(' + nameArr + ')';
}
else {
orConditionMap.name = `P.within("${this.name}")`;
orConditionMap.identifier = this.name;
}
}
8.子组件值变化触发父-父组件
需求:
- 有时候我们需要利用深层的子组件影响到上一层,甚至上上层的组件
- 利用watch、emit实现
代码(Javascript)
//子组件内
@Prop({
type: Array,
default: () => {
return []
}
})
value: Array<Array<string>>;// 父组件传下来的值
//1.监听父组件传下来的值触发emit(父组件利用子组件)
@Watch('value', {
deep: true,
immediate: true
})
public watchValue (newValue: Array<any>) {
//值触发TagCom组件的updateModel方法
this.$emit('changeFun');
}
//2.直接子组件函数触发emit(子组件影响父组件)
public getChangeFun(newValue: Array<any>) {
this.$emit('changeFun');
}
//-------------------------------
//父组件内
<!-- 多层级级联 -->
<CascaderMult v-if="item.type==='multCascader'" :value="item.value" @changeFun="multCascaderChangeFun(item)"></CascaderMult>
public multCascaderChangeFun (item: any) {
if (item.changeFun) {
item.changeFun();
}
}
//祖组件内
//通过检查type字符串内包含multCascader,调用父组件的changeFun 函数
if (['select', 'cascader', 'multCascader', 'numberRange', 'yearRange'].includes(type)) {
(item as any).changeFun = () => {
//向再上一级组件发送emit
this.$emit('updateModel', true);
}
}
//老祖组件
//子组件这样跨越三层组件通过值变化触发updateModel函数
<TagCom ref="moreTagFilter" :tagData="moreTagData" :tagArr="moreTagArr" :needAll="true" @updateModel="updateModel"></TagCom>
public async updateModel () {}
9.对象、数组的深拷贝
需求:
- 对象、数组有时候需要对里面的某个值进行拷贝,这时候直接赋值、浅拷贝,都会变成引用,改一处,原始的值也会变(浅拷贝)
代码(Javascript)
//方法一:浅拷贝的实现 注意:当拷贝对象只有一层的时候,是深拷贝
// 1.展开运算符... 实现浅拷贝
let obj1 = {
name: 'Chen',
hobby: ['see a film', 'write the code', 'play basketball', 'tourism']
}
let obj2 = {...obj1};
//2.Object.assign() 实现浅拷贝
let obj1 = {
name: 'Chen',
hobby: ['see a film', 'write the code', 'play basketball', 'tourism']
}
let obj2 = Object.assign({}, obj1);
// 3.Array.prototype.concat() 实现浅拷贝
let arr1 = [
{
name: 'Chen'
},
'see a film',
'write the code',
'play basketball',
'tourism'
];
let arr2 = arr1.concat([]);
//4. Array.prototype.concat() 实现浅拷贝
let arr1 = [
{
name: 'Chen'
},
'see a film',
'write the code',
'play basketball',
'tourism'
];
let arr2 = arr1.slice();
//深拷贝的实现
//1. JSON.parse(JSON.stringify())实现深拷贝Object
let obj1 = {
name: 'Chen',
hobby: ['see a film', 'write the code', 'play basketball', 'tourism']
}
let obj2 = JSON.parse(JSON.stringify(obj1));
// JSON.parse(JSON.stringify())实现深拷贝Array
let arr1 = [
{
name: 'Chen'
},
'see a film',
'write the code',
'play basketball',
'tourism'
];
let arr2 = JSON.parse(JSON.stringify(arr1));
10.遍历筛选对象对应属性的技巧
代码(Javascript)
"properties": [
{
"name": "year",
"cnName": null,
"value": "2022-01-01 00:00:00.000",
"cnNames": ""
},
{
"name": "numberOfOptions",
"cnName": null,
"value": 0,
"cnNames": ""
},
{
"name": "discipline",
"cnName": null,
"value": [
"english"
],
"cnNames": [
"英文"
]
},
]
let TempSourceData = [];
const tempObj = {};
properties.forEach(properties=> {
const { name, value } = proItem;
if (['year', 'discipline''].includes(name)) {
TempSourceData.push(proItem);
tempObj[name] = value;
}
});
this.stTagData = tempObj;
this.sourceData = TempSourceData;
}
//--------------------------
sourceData = [
{
"name": "year",
"cnName": null,
"value": "2022-01-01 00:00:00.000",
"cnNames": ""
},
{
"name": "discipline",
"cnName": null,
"value": [
"english"
],
"cnNames": [
"英文"
]
}]
stTagData = {
"year": "2022-01-01 00:00:00.000",
"discipline": ["english"],
}
11.watch监听深层数组出现视图不更新的情况
需求:
- 某些情况下,对一个数组很深的值进行更改后,视图并不会刷新,这时候可以先把原视图的值全干掉,再用nextTick在dom更新后赋值
代码(Javascript)
@Watch('sourceData', {
immediate: true,
deep: true
})
public setStSourceData(newValue: any) {
const tempObj = {};
if (newValue) {
newValue.forEach(item =>{
const { name, value,cnNames } = item;
if(name == 'sourceOfTestQuestions'){
debugger;
//stly1001:教学,stly1002:模考
if(value == 'stly1002'){
//1.tempArr 临时存一下不刷新的值(tempArr 引用类型)
let tempArr = this.categoryArr;
//2.需要改数组categoryArr里面的required (比较深)
this.categoryArr[0].categoryFormObj.rules.category[0].required = false;
//----------------------------------------
//3.先把categoryArr(原视图数组)全干掉
this.$set(this, 'categoryArr', []);
//4.再延迟回调把更改的categoryArr赋回去
this.$nextTick(()=>{
this.$set(this, 'categoryArr', tempArr);
}
//---------------------------------------------
// this.categoryFormObj.rules.category[0].required = false;
}
tempObj[name] = value;
}
if(name == 'point'){
tempObj[name] = value.name;
}
if(name == 'testPaperClassification'){
tempObj[name] = cnNames.toString();
}
});
this.stSelectData = tempObj;
}
}
12.对象object那些事
1.Object.keys()以及Object.getOwnPropertyNames()
- Object.keys方法和Object.getOwnPropertyNames方法都用来遍历对象的属性。
- 区别:Object.keys方法只返回可枚举的属性,Object.getOwnPropertyNames方法还返回不可枚举的属性名。
//1.
var obj = {
p1: 123,
p2: 456
};
Object.keys(obj) // ["p1", "p2"]
Object.getOwnPropertyNames(obj) // ["p1", "p2"]
//2.数组的length属性是不可枚举的属性
var a = ['Hello', 'World'];
Object.keys(a) // ["0", "1"]
Object.getOwnPropertyNames(a) // ["0", "1", "length"]
13.对象数组去重(拿来主义)
- 注意:只能筛选第一层,深层的需要再次调函数去重;
1.使用filter和Map
//arr:需去重对象数组;uniId:筛选属性(字符串)
function uniqueFunc(arr, uniId){
const res = new Map();
return arr.filter((item) => !res.has(item[uniId]) && res.set(item[uniId], 1));
}
2.使用reduce
//arr:需去重对象数组;uniId:筛选属性(字符串)
function uniqueFunc2(arr, uniId){
let hash = {}
return arr.reduce((accum,item) => {
hash[item[uniId]] ? '' : hash[item[uniId]] = true && accum.push(item)
return accum
},[])
}
3.使用filter和Map
//arr:需去重对象数组;uniId:筛选属性(字符串)
unction uniqueFunc3(arr, uniId){
let obj = {}
let tempArr = []
for(var i = 0; i<arr.length; i++){
if(!obj[arr[i][uniId]]){
tempArr.push(arr[i])
obj[arr[i][uniId]] = true
}
}
return tempArr
}
14.iview表格之render函数
- 利用render函数渲染表格内容
1.渲染提示图标ToolTip
要求效果:
代码:
{
title: '授权状态',
key: 'authStatus',
fixed: 'right',
width: 111,
align: 'center',
ellipsis: true,
tooltip: true,
render: (h, params) => {
const row: any = params.row;
if (row.authStatus === 'failed') {
return h('div', [
h(
'span',
{
class: `${row.authStatus} template-status`
},
this.statusMap[row.authStatus].name
),
h('Tooltip', {
props: {
content: row.extend.errorDesc,
transfer: true
},
style: 'white-space: normal;'
}, [
h('i', {
class: 'ivu-icon ivu-icon-ios-help-circle-outline'
})
])
]);
} else {
return h(
'span',
{
class: `${row.authStatus} template-status`
},
this.statusMap[row.authStatus].name
);
}
}
},
2.表头渲染提示图标ToolTip(renderHeader)
要求效果:
代码:
{
// title: '授权进度',
key: 'progress',
minWidth: 120,
align: 'center',
// ellipsis: true,
// tooltip: true,
renderHeader: (h, params) => {
return h('div', [
h('Tooltip', {
props: {
content: '授权进度:授权成功/申请授权',
trigger: 'hover',
size: 'small',
placement: 'top-start',
theme: 'light',
transfer: true
}
}, [
h('span', {
domProps: {
innerHTML: '授权进度'
}
}),
h('Icon', {
props: {
type: 'ios-help-circle-outline'
}
})
]),
])
}
},
15.非表格多选
- 多选
要求效果:
代码:
<template>
//全部全选
<Checkbox v-model="allPageSel" >当前页全选</Checkbox>
//遍历listData中的每个多选框
<div class="list-item" v-for="(item, index) in listData" :key="index">
<Checkbox v-if="type === 'st'" class="status-checkbox" v-model="item.checkSel" @on-change="getAllCheckSel(item,index)"></Checkbox>
</div>
</template>
<script lang="ts">
allCheckSel: Array<any> = [];
allPageSel: boolean= false;
//this.listData在列表刷新时初始化checkSel ,设为false
if (res) {
const data: any = res.data;
const records: Array<any> = data.records;
records.forEach(item => {
//初始未勾选
item.checkSel = false;
});
this.listData = records;
this.checkSelToList();
}
}
//全部勾选时
@Watch('allPageSel', {
})
public allCheckBoxSel(val){
//全部勾选时给this.listData所有item的checkSel 设状态
this.listData = this.listData.map(sel =>{
sel.checkSel = val ? true : false;
return sel;
})
this.listData.forEach((sel) =>{
this.getAllCheckSel(sel);
})
}
//对象数组去重
private uniqueFunc(arr, uniId) {
const res = new Map();
return arr.filter((item) => !res.has(item[uniId]) && res.set(item[uniId], 1));
}
//根据checkSel状态,将数据存入allCheckSel
public getAllCheckSel(item,index){
if(item.checkSel){
this.allCheckSel.push(item);
//根据id去重
this.allCheckSel = this.uniqueFunc(this.allCheckSel, 'id');
}
else {
this.allCheckSel = this.allCheckSel.filter(sel =>{
return sel.id !== item.id;
})
}
this.listData[index].checkSel = item.checkSel;
this.syncCheckSel();
}
//根据id对比将allCheckSel数组里的勾选状态checkSel 赋给listData(用来回显勾选不勾选)
public checkSelToList() {
if(this.allCheckSel.length) {
this.allCheckSel.forEach(sel => {
this.listData.forEach(item => {
if(sel.id === item.id) {
item.checkSel = sel.checkSel;
}
})
})
}
this.syncCheckSel();
}
//同步全勾选/勾选
public syncCheckSel() {
let isAllSel = true;
this.listData.forEach(sel =>{
if(!sel.checkSel) {
isAllSel = false;
}
});
this.allPageSel = isAllSel;
}
</script>
16.自由调整iview对话框尺寸
- 可以调整组件对话框大小
要求效果:
代码:
//CSS3 resize 属性
//指定一个div元素,允许用户调整大小
div {
resize:both;
overflow:auto;
}
17.剪切板使用记录
<template>
<div class="drawing-container">
<div id="tui-image-editor"></div>
<Tooltip class="icon-copy" content="导入图片" placement="right" transfer>
<Icon type="ios-cut-outline" size="26" @click="getClipboardContents()" />
</Tooltip>
<Tooltip class="icon-out" content="导出图片" placement="right" transfer>
<Icon type="ios-log-out" size="26" @click="writeDataToClipboard()" />
</Tooltip>
</div>
</template>
<script>
export default {
data() {
return {
instance: null,
isCopy: null,
url: '',
path: img
}
},
mounted() {
const that = this
// document.addEventListener('paste', function (event) {
// console.log(event)
// let items = event.clipboardData && event.clipboardData.items;
// let file = null;
// if (items && items.length) {
// // 检索剪切板 items
// for (var i = 0; i < items.length; i++) {
// if (items[i].type.indexOf('image') !== -1) {
// // 此时file就是剪切板中的图片文件
// file = items[i].getAsFile();
// break;
// }
// }
// }
// const url = window.URL.createObjectURL(file);
// console.log(url)
//拿到url可以做下一步处理
// });
document.onkeydown = async function (event) {
let key = window.event.keyCode;
if (key === 86 && event.ctrlKey) {
// 监听ctrl+V组合键
// window.event.preventDefault(); //关闭浏览器默认快捷键
// console.log('crtl+ V 组合键',navigator.clipboard)
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
for (const type of clipboardItem.types) {
const blob = await clipboardItem.getType(type);
console.log("已读取剪贴板中的内容:", blob, await blob.text());
if (/image/.test(blob.type) && blob.size !== 267) {
that.url = window.URL.createObjectURL(blob);
//拿到url可以做下一步处理
that.isCopy = blob.size;
}
}
}
}
}
},
watch: {
isCopy: function (newVal, oldVal) {
if (this.url) {
//拿到url可以做下一步处理
}
}
},
methods: {
async writeDataToClipboard() {
try {
const base64String = this.instance.toDataURL() // base64 文件
const data = window.atob(base64String.split(',')[1])
const ia = new Uint8Array(data.length)
for (let i = 0; i < data.length; i++) {
ia[i] = data.charCodeAt(i)
}
const imageBlob = new Blob([ia], { type: 'image/png' }) // blob 文件
const item = new ClipboardItem({
[imageBlob.type]: imageBlob,
});
await navigator.clipboard.write([item]);
this.$Message.success('图片已导出至粘贴板,Ctrl+V可粘贴');
} catch (error) {
this.$Message.error('图片导出失败', error);
}
},
async getClipboardContents() {
try {
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
for (const type of clipboardItem.types) {
const blob = await clipboardItem.getType(type);
if (/image/.test(blob.type)) {
const url = window.URL.createObjectURL(blob);
//拿到url可以做下一步处理
}
}
}
} catch (err) {
console.error("图片导入失败", err);
this.$Message.error("图片导入失败", err);
}
},
}
}
</script>
<style lang="scss" scoped>
.drawing-container {
// height: 900px;
width: 1076px;
height: 658px;
position: relative;
border: 1px solid #000;
.save {
position: absolute;
right: 50px;
top: 15px;
}
.icon-copy {
cursor: pointer;
position: absolute;
right: 1035px;
top: 38px;
}
:hover {
color: rgb(197, 197, 197);
}
.icon-out {
cursor: pointer;
position: absolute;
right: 1035px;
top: 568px;
}
:hover {
color: rgb(197, 197, 197);
}
}</style>
16.利用ChatGpt输出的符合vue3+ts规范的防抖函数
- 这里我们使用了 defineComponent 函数来定义组件,使用了 ref 函数来创建响应式数据 keyword,使用了 computed 函数来计算 debounceSearch 的值。
另外,我们对 debounce 函数的泛型类型参数做了一些调整,可以更好地支持类型推断,还调整了一些类型错误,使得代码符合 Vue 3 + TypeScript 规范。
需要注意的是,由于 this 的类型是 unknown,而不是 any,因此需要进行类型断言。在这里,我们使用了 as 关键字将返回值的类型声明为和函数参数类型相同的泛型类型 F。
最后,我们在 setup 函数中返回了响应式数据 keyword、计算属性 debounceSearch,以及搜索函数 search。
要求效果:
代码:
<template>
<el-input v-model="keyword" placeholder="请输入关键字" @input="debounceSearch"></el-input>
</template>
<script lang="ts">
import { defineComponent, ref, computed } from 'vue';
// 防抖函数
function debounce<F extends (...args: any[]) => any>(fn: F, delay: number) {
let timer: ReturnType<typeof setTimeout> | null;
return function(this: unknown, ...args: Parameters<F>) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn.apply(this as unknown, args);
}, delay);
} as F;
}
export default defineComponent({
setup() {
const keyword = ref('');
const search = () => {
console.log('search:', keyword.value);
};
const debounceSearch = computed(() => debounce(search, 500));
return {
keyword,
debounceSearch,
};
},
});
</script>
后续
同时,贴上咱的个人博客,欢迎客官大老爷们来访~
青枫阁