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

75 阅读6分钟

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)

<style>
cursor: pointer;
</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>

后续

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