前端开发疑难杂症:盘点工作中令人头疼不已的难题集!

259 阅读3分钟

一、element-ui组件

1、el-table多选时设置fixed固定,全选按钮失效

image.png

<el-table-column type="selection" width="55" fixed="left"> </el-table-column>

解决方案造成这个问题的原因是element-ui表格实现原理固定列是叠加需要固定的列,多出一层class为el-table__fixed的元素,而这个元素设置了pointer-events: none将事件都取消了,所以我们只需要修改这个属性即可。

::v-deep .el-table__fixed {
  pointer-events: auto;
}

2、el-dialog的destroy-on-close属性更新数据失效

在使用elementUI的弹窗组件el-dialog时,因为每次打开必须要重新渲染里面的内容,所以使用了destroy-on-close属性,发现并没有用:

<el-dialog title="编辑" :key="key" :visible.sync="show" :destroy-on-close="true">
    <el-form :model="form">
        <el-form-item prop="">
            <el-button type="primary" @click="onSubmit">查询</el-button>
        </el-form-item>
    </el-form>
</el-dialog>

原因

element是基于vue的UI库,vue中通过key作为组件的唯一标识,一旦key更新,就会触发组件的更新。但是dialog的数据是维护dialog的父组件中,而destroy-on-close属性是销毁dialog组件及其子元素。

解决方案

  1. 使用v-if代替destroy-on-close
  2. 如果一定要用destroy-on-close,注意在el-dialog传入子组件,并且注意dialog的关闭事件,会触发组件的生命周期。
<el-dialog title="编辑" v-if="show" :visible.sync="show" :destroy-on-close="true">
    ...
</el-dialog>
// 或者
<el-dialog title="编辑" :visible.sync="show" :destroy-on-close="true">
    <child></child>
</el-dialog>

3、表单验证绑定数组报错**is not string

这是一个非常基础的知识,但是在开发中由于这个报错研究了很久,后来才发现是表单验证不知道绑定类型时会默认为string,当绑定字段为数组是,需指定rulestype:'array',特此记录一下。

<el-form-item label="数组" prop="list">{{model.list}}</el-form-item>
data() {
    return {
        rules: {
            list: [{ required:true, type:'array', trigger:'blur', validator:validListLength }]
        },
    }
}

4、解决全屏模式下弹窗被覆盖不显示问题

场景 做看板全屏显示的时候,点击弹窗不显示,关闭全屏时发现已展现,表明弹窗是被覆盖。 原因 F12查看元素,发现全屏元素和弹窗是分别属于body元素下,不是包含关系,局部全屏元素全屏时就会覆盖这种弹窗,包括下拉框,分页弹窗等等不插入body的弹窗。 解决方案

  1. 将弹窗的dom节点和局部全屏元素的dom节点,这两个节点的共同父节点全屏,即将body元素全屏,再改变全屏局部元素的样式使它占满整个屏幕;
  2. 将弹窗的dom节点插入到局部全屏元素下,成包含关系,有些UI组件会有:append-to-body属性,像el-diaologel-selectel-cascader等元素,有些弹窗则没有,如分页el-pagination。对于前者,可以用:append-to-body=!$store.state.isFullScreen绑定是否全屏的变量isFullScreen;将isFullScreen存储到store供全局动态调用,点击全屏按钮时触发store事件改变全屏状态;对于后者,通过操作dom将节点插入全屏局部元素下,实现代码如下:
<el-dialog title="看板弹窗" :visible.sync="dialogVisible":append-to-body="!$store.state.isFullScreen" :modal-append-to-body="!$store.state.isFullScreen">
    //...
</el-dialog>
<el-select v-model="value" placeholder="请选择">
    <el-option v-for="item in options" :key="item.value" :label="item.label"  :value="item.value">
    </el-option>
</el-select>
<el-pagination layout="prev, pager, next" :total="50" class="pagination-container"
    :popper-class="$store.state.isFullScreen ? 'pagePopper' : ''">
</el-pagination>
// script
mounted () {
    // 创建一个observer示例与回调函数相关联
    this.observer = new MutationObserver(() => {
        let dom = document.querySelector('.pagination-container')
        if(document.querySelector('.pagePopper') && this.$store.state.app.isFullScreen){
            dom.childNodes[0].childNodes[1].appendChild(document.querySelector('.pagePopper'))
        }
    });
    // 监听body元素子节点的变化(即监听body新增弹窗节点时执行插入节点的方法)
    // childList:子节点的变动(指新增,删除或者更改)
    this.observer.observe(document.body, { childList: true });
  },
// css
::v-deep .pagePopper {
  position: absolute !important;
  left: 70px !important; // 根据实际位置设定
  top: 33px !important; // 根据实际位置设定
}

二、vue2进阶用法

1、this.$options的用法

vue实例属性$options是一个对象,可以调用vue的各个组件下的方法和数据。

(1)在methods使用filters过滤器;

export default {
    data() {
        return {}  
    },
    filters: {
        name: function (value) {...}
    },
    methods: {
        getDetail() {
            this.$api.getDetail({
                id: this.id
            }).then(res => {
                this.title = this.$options.filters.name(res.data.title)
            })
        }
    }
}

(2)重置data中的数据,初始化数据;

// 一个el-dialog中有一个el-form,我们要求每次打开el-dialog时都要重置el-form里的数据
export default {
   data() {
        return {
            form: {
                input: ''
            }
        }
    },
    methods: {
        // 重置表单方法
        retset() {
            this.form = this.$options.data().form;
            // 也可以通过给组件$data对象赋值来重置来重置整个$data。 
            //~~ this.$data = this.$options.data();~~
            // Object.assgin(this.$data,this.$options.data())
        }
    },
}

(3)定义非响应式的数据,get和set方法,节约性能;

export default {
  name: "邓紫棋",
  data() {
    return {
         
    };
  },
  methods:{
    changeName(){
        this.$options.name="林俊杰";
      },
  }
}

三、工作中必备

1、鼠标滚轮控制横向滚动

使用鼠标滚轮控制横向滚动的应用场景在日常工作中常见,比如顶部标签栏横向滚动。

<el-scrollbar ref="scrollContainer" id="scrollPane" @wheel.native.prevent="handleScroll">
</el-scrollbar>
...
// 第一种
mounted() {
    const container = document.getElementById('scrollPane');
      container.addEventListener("wheel", (e) => {
        e.preventDefault();
        container.scrollLeft += e.deltaY; //e.deltaY为100
    });
},
// 第二种
methods: {
    handleScroll(e) {
      const $scrollWrapper = this.$refs.scrollContainer.$refs.wrap
      $scrollWrapper.scrollLeft += e.wheelDelta / 4 // 每次移动30
    },
}