【前端开发】前端小白必会开发小技巧

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.剪切板使用记录

  • 1、剪切板可以从剪切板粘贴图片到外界;
  • 2、可以写入图片到剪切板
  • 代码:

<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>

后续

同时,贴上咱的个人博客,欢迎客官大老爷们来访~
青枫阁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值