92.更新一些收藏的经验贴总结学习

一、JS相关

1.进制转换

(1)十进制转二进制

十进制数除2取余法:十进制数除2,余数为权位上的数,得到的商继续除2,直到商为0。最后余数从下往上取值。

(2)二进制转十进制

把二进制按权展开:从右到左 权值乘以2的0次方到N次方

(3)二进制转八进制

3位二进制数为一组:从右到左3位二进制数按权展开相加得到一位八进制数,不足补零

(4)八进制转二进制

八进制数除2取余法:除2取余,余数从下往上取值

(5)二进制转十六进制

4位二进制数为一组:从右到左4位二进制数按权展开相加得到一位十六进制数,不足补零

(6)十六进制转二进制

十六进制除2取余法:除2取余,余数从下往上取值

(7)十进制转八进制或十六进制

有2种方法:

一是:把十进制转为二进制后再转八进制或十六进制

二是:十进制除8或除16取余法,余数也是从下往上取值

(8)八进制或十六进制转十进制 

把八进制数或十六进制数按权展开相加得到十进制数:比如八进制226为 2*8^2+2*8^1+6*8^0

(9)八进制与十六进制转换

有2种方法:

一是:先转换为二进制再相互转换

二是:想转换为十进制再互相转换

(10)负数转换

先将负数写为补码形式,再根据二进制转换其他进制的方法进行:

比如将十进制数 -9 转为八进制:

-9的补码为1111 1111 1111 0111(先原码--再反码--再补码)

然后从右往左3位一划,不足补零,最后得到177767,即为-9的八进制形式

总结:

十进制(八进制、十六进制)转二进制:除2取余法

二进制转十进制:从右到左按权展开(2的n次方)

二进制转八进制:3位一划,从右到左按权展开,不足补零(2的n次方)

二进制转十六进制:4位一划,从右到左按权展开,不足补零(2的n次方)

十进制转八进制(十六进制):除8(16)取余法

八进制(十六进制)转十进制:从右到左按权展开(8的n次方或16的n次方)

八进制与十六进制相互转换:可先转为二进制(十进制)再相互转换

十进制负数转八进制(十六进制):先将负数写为补码再用二进制转换

2.js超出显示省略号

str = "开始时间,结束时间,span名称,应用名称,页面访问趋势"

需求:只显示字符串前3项,其余以省略号展示,并且鼠标悬浮时展示全部

newStr = str.split(',').slice(0,3).join(',') + ',...'

<div :title="str">

        newStr:{{newStr}}

</div>

3.call()、apply()、bind()用法

(1)都用来重定义this指向

var name = "小小" , age = 20

var obj = {

        name:"阿拙",

        objjAge:this.age,

        myFun:function(){

                // 此时取不到this.age值 因为this指向obj这个对象

                console.log(this.name + "年龄:" + this.age) 

        }

var data = {

        name:'苏苏",

        age:19

}

obj.myFun.call(data)          //   苏苏年龄:19

obj.myFun.apply(data)       //   苏苏年龄:19

obj.myFun.bind(data)()      //   苏苏年龄:19

由以上代码可知:call、apply和bind都可以通过传参调用obj对象内的方法将值传递进去,bind返回的是一个新的函数,必须调用它才能被执行。

(2)对比三者传参

var name = "小小" , age = 20

var obj = {

        name:"阿拙",

        objjAge:this.age,

        myFun:function(fm,to){

                // 此时取不到this.age值 因为this指向obj这个对象

                console.log(this.name + "年龄:" + this.age,"来自" + fm + "去往" + to) 

        }

var data = {

        name:'苏苏",

        age:19

}

obj.myFun.call(data,'北京','上海')          //   苏苏年龄:19,来自北京去往上海

obj.myFun.apply(data,['北京','上海'])     //   苏苏年龄:19,来自北京去往上海

obj.myFun.bind(data,'北京','上海')()      //    苏苏年龄:19,来自北京去往上海

由以上代码可知:call、apply和bind三个函数的第一个参数都是this的指向对象 ,第二个参数传参有区别:call和bind都是直接放在第一个参数后,以逗号隔开;apply的第二个参数需要放在数组里。三者的参数不限定是 string 类型,允许是各种类型,包括函数 、 object 等。

4.js点击按钮复制文本

因为select()输入框只对input和textarea有效,对<p>无效,所以可以在p标签后添加textarea标签并将其隐藏,点击按钮时先把<textarea>的value改为<p>的innerText,然后复制<textarea>的内容。

<style type="text/css">

 .wrapper {position: relative;}

 #input {position: absolute;top: 0;left: 0;opacity: 0;z-index: -10;}

</style>

<div class="wrapper">

 <p id="text">被复制的内容</p>

 <textarea id="input">已隐藏</textarea>

 <button onclick="copyText()">复制</button>

</div>

<script type="text/javascript">

 function copyText() {

  var text = document.getElementById("text").innerText;

  var input = document.getElementById("input");

  input.value = text; // 修改文本框的内容

  input.select(); // 选中文本

  document.execCommand("copy"); // 执行浏览器复制命令

  alert("复制成功");

 }

</script>

5.js获取数组对象最大(小)值

list = [{ id: 1, name: 'jack' },
        { id: 2, name: 'may' },
        { id: 3, name: 'shawn' },
        { id: 4, name: 'tony' }]

需要获取list数组对象中id属性的最大值和最小值:

(1)Math方法

// 最大值 4
Math.max.apply(Math,this.list.map(item => { return item.id }))
// 最小值 1
Math.min.apply(Math,this.list.map(item => { return item.id }))

(2)sort排序(会使原数组元素位置发生变化)

// 最大值 4
this.list.sort((a, b) => { return b-a })[0].id  
// 最小值 1
this.list.sort((a, b) => { return a-b })[0].id 

6.for循环内异步操作

(1)每隔1秒打印0~4的值

function box(index){

        if(index <5){

                console.log("index is : ",index)

                setTimeout(function(){

                        box(index+1)

                },1000) 

        }

}

box(0)

(2)使用递归实现倒计时

function showTime(count){

        console.log("count is : ", count)

        if(count==0){

                console.log("All is Done !")

        }else{

                count -= 1

                setTimeout(function(){

                        showTime(count)

                },1000)

        }

}

showTime(10)

(3)async和await打印0~4

var asyncFunc = function(arr,i){

        return new Promise(resolve,reject){

                setTimeout(function(){

                        arr.push(i)

                        console.log("index is: " ,i)

                        resolve()

                },1000)

        }

}

var box1 = async function(){

        var arr = []

        for(var i=0;i<5;i++){

                await asyncFunc(arr,i)

        }

        console.log(arr)

}

box1()

(4)即时执行函数打印数值

function buildList(list){

        var result = []

        for(var i=0;i<list.length;i++){

                var item = 'item' + list[i]       // item6   item7  item8

                result.push(function(index,it){

                        return function(){

                                console.log(it + ' ' + list[index])

                        }

                }(i,item))

        }

        return result

}

function testList(){

        var fnList = buildList([6,7,8])

        for(j=0;j<fnList.length;j++){

                fnList[j]()

        }

}

testList()

7.js求n个数中的最大值

// 求n个数中的最大值
function getMax(arr) {
    var max = arr[0];
    for (var i = 1; i < arr.length; i++) {
        if (max < arr[i]) {
            max = arr[i];
        }
    }
    console.log(max);
}
var array = [12, 17, 9, 0, 90]

getMax(array)   // 90

8.js获取本周、本月时间区间

先写一个方法:

function getDateStr(now){

        var year = now.getFullYear()        //  年

        var month = now.getMonth()+1    //  月

        var day = now.getDate()               //  天

        if(month < 10){

                month = '0' + month

        }

        if(day < 10){

                day = '0' + day

        }

        return year + '-' + month + '-' + day

}

(1)从周一0点到当天的时间

now.getDay()获取当天是周几,周日是0,周六是6,所以需要判断,即如果今天是周三,值为2.

var now = new Date()

var nowDayOfWeek = now.getDay() == 0 ? 6 : (now.getDay()-1)

var startTime = getDateStr(new Date(now.getTime() - nowDayOfWeek * 24 * 60 * 60 * 1000)) + ' 00:00:00'

var endTime = getDateStr(now) +'23:59:59'

(2)从1日0点到当天的时间

now.getDate() 获取的是今日日期,传参时需要减1,因为是现在时刻时间戳减去过去n-1天时间戳进行传参。

var now = new Date()

var nowDay = now.getData()-1

var startTime = getDateStr(new Date(now.getTime() - nowDay * 24 * 60 * 60 * 1000)) + ' 00:00:00'

var endTime = getDateStr(now) +'23:59:59'

9.js判断字符串是否包含指定值

(1)使用indexOf()

indexOf()返回某个字符传值在字符串中首次出现的位置,若没有则返回-1

var str = "欢迎来到这里!"

console.log(str.indexOf('欢迎') != -1)         // true

console.log(str.indexOf('欢迎'))                  //  0

console.log(str.indexOf('欢迎到') != -1)     // false

(2)使用search()

search()检索字符串中指定的子字符串,若没有则返回-1

var str = "欢迎来到这里!"

console.log(str.search('欢迎') != -1)         // true

console.log(str.search('欢迎'))                  //  0

console.log(str.search('欢迎到') != -1)     // false

(3)使用test()

test()检索字符串中指定的值,返回true或false

var str = "123"

var reg =RegExp(/3/)

console.log(reg.test(str))   //  true

(4)使用exec()

exec()检索字符串中正则匹配,返回数组,存放匹配结果,若未找到匹配,返回null

var str = "123"

var reg =RegExp(/3/)

var reg1 =RegExp(/5/)

console.log(reg.exec(str))   //  [0:'3',index:2,input:'123']

console.log(reg1 .exec(str))   //  null

10.js获取任意一天0点和24点

(1)获取当天零点

var date1 = new Date(new Date(new Date().toLocaleDateString()).getTime())

(2)获取当天24点

var date2 = new Date(new Date(new Date().toLocaleDateString()).getTime() +24 * 60 * 60 * 1000 -1)

(3)获取3天前的零点

var date3 =  new Date(new Date(new Date().setDate(new Date().getDate() - 3)).setHours(0,0,0,0))

(4)获取一周前的零点

var date4 =  new Date(new Date(new Date().setDate(new Date().getDate() - 7)).setHours(0,0,0,0))

(5)获取任意一天的零点

const getStartTime = (num) => {
    return  new Date(new Date(new Date().setDate(new Date().getDate() - num)).setHours(0,0,0,0))
}
getStartTime(5)      //  五天前

(6)格式化时间

// 格式化时间
dataFormat(date) {
    let d = new Date(date);

    let month =d.getMonth() + 1 < 10 ? "0" + (d.getMonth() + 1) : d.getMonth() + 1;
    let day = d.getDate() < 10 ? "0" + d.getDate() : d.getDate();
    let hours = d.getHours() < 10 ? "0" + d.getHours() : d.getHours();
    let min = d.getMinutes() < 10 ? "0" + d.getMinutes() : d.getMinutes();
    let sec = d.getSeconds() < 10 ? "0" + d.getSeconds() : d.getSeconds();

    let times = d.getFullYear() + "-" + month + "-" + day + " " + hours + ":" + min + ":" + sec;

    return times;
},

//调用方法
 this.startTime = this.dataFormat(this.startTime);
 this.endTime = this.dataFormat(this.endTime);

11.js替换字符串中的字符

(1)使用replace()

单独使用replace方法只能替换字符串中重复字符的最前方的一个

var str = '银河猫加油油';
alert(str.replace('油','饭'));    // 输出结果:银河猫加饭油

(2)使用for循环+replace()

利用for循环和replace方法实现字符串中某个字符全部替换

var str = '加油银河猫加油油';
for(var i = 0; i < str.length; i++){
    if (str[i] == '油') {
        str = str.replace('油','饭'); // 注意替换之后就变成新数组了
    }
}
alert(str); // 输出结果 加饭银河猫加饭饭

12.使用pre标签不生效解决方法

<pre>
   我寻你千百度 日出到迟暮
   一瓢江湖我沉浮
   我寻你千百度 又一岁荣枯
   可你从不在 灯火阑珊处
</pre>

直接这样写,有可能不生效,就可以使用模板字符串`` 或者换行符\n 来解决

<pre id='preId'>{`我寻你千百度 日出到迟暮
一瓢江湖我沉浮
我寻你千百度 又一岁荣枯
可你从不在 灯火阑珊处
`}
</pre>
<pre id='preId1'>
   我寻你千百度 日出到迟暮{'\n'}    //加入\n需要使用{}
   一瓢江湖我沉浮{'\n'}
   我寻你千百度 又一岁荣枯{'\n'}
   可你从不在 灯火阑珊处
</pre>

13.isNaN()函数学习

isNaN(value)

console.log(isNaN(10));        // false,10是有效数字
console.log(isNaN("hello"));  // true,"hello"无法转换为数字,返回NaN
console.log(isNaN(NaN));     // true,NaN本身就是特殊值NaN
console.log(isNaN("123"));    // false,"123"可以转换为有效数字123

为了避免在字符串上误用isNaN(),可以使用Number.isNaN()函数来确保准确性,它不会尝试将参数转换为数字,只会对参数进行严格的NaN检查。

console.log(Number.isNaN("hello"));  // false,不会尝试转换为数字,直接检查是NaN
console.log(Number.isNaN(NaN));     // true,直接检查是NaN

14.js更改其中一个数组值 另一个数组也会改变

在vue项目中,在data中定义了两个数组对象,一个用于展示,一个用于修改操作。当修改其中一个数组的值时发现另一个也会跟着改变。

由于数组是引用变量,进行引用赋值,其实还是原来的数组,也就是说,两个数组对象,其实一直引用的是同一个内存地址中的数组 , 所以修改其中一个引用数组,其他引用也会随之改变。

解决方法:

this.newList = JSON.parse(JSON.stringify(response.data))
this.data = response.data

先把数组转换成字符串,再转换成对象,会分配一块新的内存空间,创建一个新的对象。这样两个引用指向的就是不同的对象了。

15.js splice()在循环删除中漏删问题

错误:

data.forEach((v,index,arr) => {
    if(****){
       arr.splice(index,1)
     }
}) 

正确:

for(var i=data.length-1;i>=0;i--){
        if(*******){
            data.splice(i,1)
        }

}

直接使用forEach循环删除,会生成新的数组,破坏原数组下标,导致漏删除,可以使用倒序循环删除。

二、Vue相关

1.vue中proxy配置

proxy: {

      "axis": {
        target: "http://www.baidu.com",

        changeOrigin: true,

        pathRewrite: {
          ["^" + axis]: ""

        }

      },

      "/another": {
        target: "http://aaa.aaa.com",

        changeOrigin: true,

        secure: false

      }

    }

  }

理解vue中proxy配置的含义:当我们从自己本地请求别人本地的数据时,因为浏览器的同源策略,会出现跨域无法成功请求的情况,但是通过运行vue项目而本地开启的node服务器是可以进行请求的,所以我们将自己本地的数据请求代理到node本地运行环境中从而进行请求别人本地的数据。

注:vue项目中配置的proxy只是对于开发环境中将本地的localhost请求代理到www.xxx.com,当项目发布到生产环境则是走nginx代理服务器,项目中的proxy配置无效。

2.判断页面首次进入或再次刷新

(1)第一种方法

mounted () {
    if(window.name == ""){
       console.log("首次被加载");
       window.name = "isReload";  // 在首次进入页面时给window.name设置一个固定值 
    }else if(window.name == "isReload"){
       console.log("页面被刷新");
    }
}

(2)第二种方法

mounted () {
      if (window.performance.navigation.type == 1) {
        console.log("页面被刷新")
      }else{
        console.log("首次被加载")
      }
}

3.单页长时间不操作清除cookie退出登录

(1)首先创建一个astrict.js

// 单页长时间不操作就会自动退出
 
var lastTime = new Date().getTime()
var currentTime = new Date().getTime()
var timeOut = 1 * 60 *1000    // 设置超时时间: 30分
 
window.onload = function() {
    window.document.onmousedown = function() {
        localStorage.setItem("lastTime",new Date().getTime())
    }
};
 
function checkTimeout() {
    currentTime = new Date().getTime()         // 更新当前时间
    lastTime = localStorage.getItem("lastTime");
    // console.log(currentTime - lastTime);
    // console.log(timeOut);
    if (currentTime - lastTime > timeOut) {   // 判断是否超时
        // console.log("超时");
        var url = window.location.href;
        var newUrl=url.match(/(\S*)#/);
        sessionStorage.clear()
        
        window.open('/login','_self');
    }
}
 
 
/* 定时器 间隔30秒检测是否长时间未操作页面 */
window.setInterval(checkTimeout, 30000);

(2)在mian.js引入、注册

import Astrict from './assets/js/astrict.js'


Vue.use(Astrict)

4.window.open()原页面下载

var url = ‘XXX’
const link = document.createElement('a')
link.href = url;
document.body.appendChild(link)
link.click()
document.body.removeChild(link)

5.由接口返回(“↵”)进行换行

(1)使用textarea赋值

当我们拿到后端返回的数据时,直接通过v-model绑定给textarea,就会有默认的换行,但是它不能随内容高度增加textarea高度实现自适应,如果用JS来实现的话,相对麻烦一点

(2)使用v-html输出文本

“↵”符号在html中会识别别为\r,\n等转义字符,所以我们可以使用\r\n去替换.replace(/(\r\n|\n|\r)/gm, ' < br /> ')

<span v-html="detail.replace(/(\r\n|\n|\r)/gm, '<br />')"></span>

(3)使用vue计算属性实现

将文本字符串转化为数组(split() 方法用于把一个字符串分割成字符串数组),然后将数组中“\n”换成浏览器正常解析的换行标签< br >即可。
然后使用正则表达式将字符串的换行符转换为< br >,最后使用join() 方法把数组中的所有元素放入一个字符串用以展示。

<div v-html="content"></div>
computed: {
    content () {
      let arr =data.split("")   // data是后端传回来的文本数据
      return arr.map((item) => {
        return item === "\n" ? "<br>" : item
      }).join("")
    }
  }

(4)使用css改变展示样式

white-space:该CSS属性是用来设置如何处理元素中的空白

① pre-wrap: 保留空白符序列,但是正常地进行换行

② pre-line: 合并空白符序列,但是保留换行符

<html>
        <head>
                 <style type="text/css">
                          p{
                                    // white-space:pre-line;
                                    white-space:pre-wrap;
                            }
                 </style>
        </head>
        <body>
                  <p>
                            这是一些文本。
                            这是一些文本。
                            这是一些文本。
                            这是一些文本。
                  </p>
         </body>
</html>

6.Vue项目使用Vuex

(1)安装

npm install vuex --save

(2)新建仓库

在src目录下新建一个文件夹,命名为store,然后在该文件夹下面创建一个store.js文件

(3)在main.js中引入

import Vuex from 'vuex'

import store from './store/store'

Vue.use(Vuex)

......

new Vuw({

        .....

        store   // 使用store

})

(4)在store.js文件写

import Vue from 'vue'

import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.store({

        state:{

                name:'张三',     // 存储了一个公共状态

                age:22     // 存储了一个公共状态

        },

        mutations:{

                showPeople(state,msg){

                        state.name = msg

                }

        }

})

export default store

(5)在其他页面打印this

created(){

        console.log(this)    // 里边有$store

        console.log(this.$store.state.name)   // 张三

}

(6)使用mutation改变值

在其他页面data内定义msg并写一个方法去改变store中的值,最后再调用方法

data(){

        return{

                msg:'李四'

        }

}

methods:{

        changeName(){

                this.$store.commit('showPeople',this.msg)

        }

}

created(){

        this.changeName()

        console.log(this.$store.state.name)   // 李四

}

7.解决Vue报错

Duplicate keys detected:'1'.This may cause an update error

(1)错误信息展示为关键字‘keys’

 此时应该检查for循环中的key:循环中的key值不为唯一性

(2)两个相同的for循环key一样

需要将其中一个for循环的key值加一个数字或字符串

<p v-for="(item,index) in arr1" :key="index+'1'">{{item}}</p>

<p v-for="(item1,index) in arr2" :key="index">{{item1}}</p>

8.vue中css引用新字体

(1)字体网站下载所需字体

我是在这个网址下载的: https://www.fonts.net.cn/fonts-zh-15.html

(2)将.ttf文件放入assets/font

(3)新建对应css文件(如上图)

@font-face{

        font-family:"DingTalkJinBuTi";    //  和.ttf文件名同名(也可按自己喜好设置)

        src:url('../font/DingTalk JinBuTi.ttf') format('truetype');

}

(4)main.js中引入css文件

import './assets/font/DingTalk JinBuTi.css'

(5)在需要的界面使用字体

font-family: DingTalkJinBuTi;

9.Vue监听浏览器刷新

(1)在App.vue的mounted中添加:

 window.addEventListener("beforeunload", e => {
        this.unloadFn(e);
 })

(2)在App.vue的destroyed中添加:

window.removeEventListener("beforeunload", e => {
        this.unloadFn(e);
})

(3)在App.vue的methods中添加:

unloadFn(){
        //  逻辑代码
}

10.Vue重复点击菜单刷新当前页面

(1)方案一:改变路由

// 通过时间戳实现菜单刷新
this.$router.push({
  path: url,
  query: {
    t: +new Date()  // 保证每次点击路由的query项都是不一样的,确保会重新刷新view
  }
})

缺点:每次点击后,地址栏地址后面会存在一长串时间戳

(2)方案二:借助重定向

  1. 创建一个空的页面:src/layout/components/redirect.vue

<script>
export default {
  beforeCreate() {
    const { query } = this.$route
    const path = query.path
    this.$router.replace({ path: path })
  },
  mounted() {},
  render: function(h) {
    return h()      // avoid warning message
  }
}
</script>

  1. 挂载路由:src/router/index.js

{
  path: '/redirect',
  component: () => import('@/layout/components/redirect.vue')
},

  1. 菜单跳转的地方添加事件,进行相关处理

<el-menu ... @select="selectMenuItem">
    // ...
</el-menu>

<script>
export default {
  methods: {
    selectMenuItem (url, indexPath) {
      if (this.$route.fullPath === url) {
        // 点击的是当前路由 手动重定向页面到 '/redirect' 页面
        this.$router.replace({
          path: '/redirect',
          query: {
            path: encodeURI(url)
          }
        })
      } else {
        // 正常跳转
        this.$router.push({
          path: url
        })
      }
    }
  }
}
</script>

11.查看项目中vue和cli版本号

 npm list vue

 vue -V

12.使用脚手架搭建vue项目

(1)检查npm 版本

node -v
npm -v

npm config set registry "https://registry.npm.taobao.org"   // 修改为淘宝镜像(可选操作)

(2)安装

npm install webpack -g    // 全局安装 webpack
npm install webpack webpack-cli -g    // 安装 webpack-cli 依赖

webpack -v    // 查看版本号

npm install -g vue-cli    // 全局安装vue-cli
vue -V    // 查看版本号

若出现“Unexpected end of JSON input while parsing near”错误,
  命令行输入: npm cache clean --force

(3)创建项目(命令行方式)

cd E:\vue\vue-demo     //  命令行进入该目录

vue init webpack vue-demo     //  下载模板

【进入交互页面,根据自己情况选择】
?Project name vue-demo # 项目名称,直接回车,按照括号中默认名字(注意这里的名字不能有大写字母,如果有会报错Sorry, name can no longer contain capital letters)。


? Project description A Vue.js project # 项目描述,随便写
? Author # 作者名称
? Vue build standalone # 我选择的运行加编译时
    Runtime + Compiler: recommended for most users


? Install vue-router? Yes # 是否需要 vue-router
? Use ESLint to lint your code? Yes # 是否使用 ESLint 作为代码规范.
? Pick an ESLint preset Standard # 一样的ESlint 相关
? Set up unit tests Yes # 是否安装单元测试
? Pick a test runner 按需选择 # 测试模块


? Setup e2e tests with Nightwatch? 安装选择 # e2e 测试
? Should we run `npm install` for you after the project has been created? (recommended) npm # 包管理器,我选的NPM

(4)安装完成后进入项目目录

cd E:\vue\vue-demo      //  命令行进入目录

 npm install           //  初始化项目

 npm run dev        //  启动项目

npm run build       //   项目打包

将打包后生成的dist目录中的文件拷贝到服务器的相应地址即可(比如tomcat的webapps目录下)

13.修改滚动条样式(css)

        /*滚动条样式*/
        textarea::-webkit-scrollbar {
            width: 4px;    
        }
        textarea::-webkit-scrollbar-thumb {
            border-radius: 10px;
            box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
            background: rgba(0,0,0,0.2);
        }
        textarea::-webkit-scrollbar-track {
            box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
            border-radius: 0;
            background: rgba(0,0,0,0.1);

        }

::-webkit-scrollbar 滚动条整体部分,可以设置宽度啥的
::-webkit-scrollbar-button 滚动条两端的按钮
::-webkit-scrollbar-track 外层轨道
::-webkit-scrollbar-track-piece 内层滚动槽
::-webkit-scrollbar-thumb 滚动的滑块
::-webkit-scrollbar-corner 边角
::-webkit-resizer 定义右下角拖动块的样式

14.post请求下载文件

methods:{
  //导出模板
  exportTem(){  //最初的方法
    let url="/pmkpi/v1/restapi/file/download";  //后端的接口
    let param = this.downloadPam;  //项目中的请求参数
    axios.post(url,param,{
      // responseType: 'arraybuffer'
      'responseType':'blob'
      }
    ).then(res=>{
      console.log('res=>',res); 
      if(res.status==200){
        this.exportFile(res)
      }else{  
        this.$message({
          message: '服务器错误',
          type: 'error',
          duration:2000
        });
      }
    }) 
  },
  exportFile(result){
    let contentDisposition = result.headers['content-disposition'];
    // 这里后端给的内容中,文件名字可能是驼峰式名称的 fileName ,或者是全部小写的 filename
    let filename = decodeURI(contentDisposition.split('fileName=')[1] || contentDisposition.split('filename=')[1]);
    // 注意这里的 result.data ,如果只传 result 的话,最后下载出来的excel文件,里面显示的是 [object Object]
    let blob = new Blob([result.data],{type: result.headers['content-type']});
    // let blob = new Blob([result.data],{type: "application/x-msdownload;charset=GBK"});
    // let blob = new Blob([result.data],{type: "application/x-msdownload"});
    // let blob = new Blob([result.data]);
    // let blob = new Blob([result.data],{type: "application/vnd.ms-excel"});
    let url = window.URL.createObjectURL(blob);
    if (window.navigator.msSaveBlob) {  //IE
      try {
        window.navigator.msSaveBlob(blob, filename);
      }
      catch (e) {
        console.log(e);
      }
    }
    else {  //非IE
      let link = document.createElement('a');
      link.style.display = 'none';
      link.href = url;
      link.setAttribute('download', filename);
      document.body.appendChild(link);
      link.click();
    }
    URL.revokeObjectURL(url); // 释放内存
  }
}

15.proxyTable配置解决跨域

(1)为什么会跨域

因为浏览器同源策略的限制,不是同源的脚本不能操作其他源下面的对象

(2)什么是同源策略

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

简单的来说:协议、IP、端口三者都相同,则为同源

(3)proxyTable配置

proxyTable: {
      '/apis': {
        // 测试环境
        target: 'http://www.baidu.cn/',    // 接口域名
        changeOrigin: true,    // 是否跨域
        pathRewrite: {
            '^/apis': ''     // 需要rewrite重写的
        }              
}

target:就是需要请求地址的接口域名

(4)两种请求方式

//   fetch方式

fetch("/apis/test/testToken.php", {
      method: "POST",
      headers: {
        "Content-type": "application/json",
        token: "f4c902c9ae5a2a9d8f84868ad064e706"
      },
      body: JSON.stringify(data)
})
      .then(res => res.json())
      .then(data => {
        console.log(data);
      });

//   axios方式

import Vue from 'vue'
import App from './App'
import axios from 'axios'
Vue.config.productionTip = false
 
Vue.prototype.$axios = axios   //  将axios挂载在Vue实例原型上
 
//  设置axios请求的token
axios.defaults.headers.common['token'] = 'f4c902c9ae5a2a9d8f84868ad064e706'
//  设置请求头
axios.defaults.headers.post["Content-type"] = "application/json"

//  axios请求页面代码

this.$axios.post('/apis/test/testToken.php',data).then(res=>{
        console.log(res)
})

16.Vue修改版本命令

npm i vue@2.6.11 vue-template-compiler@2.6.11

17.F5刷新当前页面更改时间

需求:在首页F5刷新或右键重新加载时更改时间选框的时间和接口传参,并且跳转页面后取消刷新更改时间功能,以及从其他页面跳转到首页后可以把时间带到首页。

// 在首页index.vue文件中添加代码:

mounted(){

        window.addEventListener("beforeunload",this.unloadFn)

}

destroyed(){

        window.removeEventListener("beforeunload",this.unloadFn)

}

beforeRouteLeave(to,from,next){

        document.cookie = "new_time=;expires=Thu,01 Jan 1970 00:00:00 UTC;path=/;"

}

// 每次刷新时更新cookie值

methods:{

        unloadFn(){

                setCookie('new_time',new Date(),1)

        }

}

// 在created中判断是否有new_time

if(getCookie('new_time')){

        this.value1 = [new Date(getCookie('new_time')).setTime(new Date(getCookie('new_time')).getTime() - 60 * 1000 * 15),new Date(getCookie('new_time'))]

        let date = new Date(this .value1[0]

        let date2 = new Date(this .value1[1]

        date.setMilliseconds(0)

        date2.setMilliseconds(0)

        this.selectsTime = {start time: newTimeHour(date), end time: newTimeHour(date2))

}else if(getCookie('listTimestart')){

        this.value1 = [new Date(getCookie('listTimestart')),new Date(getCookie('listTimeEnd'))]    

        this.selectsTime = {start time: newTimeHour(date), end time: newTimeHour(date2))

}else{

        this.value1 = [new Date(getCookie('allDate')).setTime(new Date(getCookie('allDate')).getTime() - 60 * 1000 * 15),new Date(getCookie('allDate'))]

        let date = new Date(this .value1[0]

        let date2 = new Date(this .value1[1]

        date.setMilliseconds(0)

        date2.setMilliseconds(0)

        this.selectsTime = {start time: newTimeHour(date), end time: newTimeHour(date2))

}

18.Vue中使用addEventListener和removeEventListener

(1)methods中添加方法

// 和上一个例子一样

methods:{

        unloadFn(){

                setCookie('new_time',new Date(),1)

        }

}

(2)mounted中添加

mounted(){

        window.addEventListener("beforeunload",this.unloadFn)

}

(3)destroyed中删除

destroyed(){

        window.removeEventListener("beforeunload",this.unloadFn)

}

19.vue tab切换保持数据状态

实现方法:使用<keep-alive></keep-alive>包裹组件

<el-tabs v-model="activeName" @tab-click="handleClick">

  <el-tab-pane label="记录">

    <keep-alive>

      <child1 v-if="isChildUpdate"></child1>

    </keep-alive>

  </el-tab-pane>

</el-tabs>

三、elementUI

1.table选择框禁止选中

<template>
  <el-table ref="multipleTable"  :data="tableData"  tooltip-effect="dark"
    style="width: 100%"  @selection-change="handleSelectionChange">
        <el-table-column  type="selection"   :selectable="checkSelectable" width="55">
        </el-table-column>
         ......
  </el-table>
</template>

// 设置禁止选中的条件

checkSelectable(row) {
  return row.date == '2016-05-03'
},

若返回为 true, 则可以选中,否则禁止选中

2.table点击获取当前行索引

在el-table上添加:row-class-name和@row-click:

<el-table :row-class-name="tableRowClassName" @row-click = "onRowClick">

js方法:

tableRowClassName ({row, rowIndex}) {
   //  把每一行的索引放进row
   row.index = rowIndex;
},
onRowClick (row, event, column) {
   //  点击获取索引
  const index = row.index;
  console.log(index)
}

3.elementUI默认勾选表格

使用 toggleRowSelection 

toggleRowSelection(row, selected)接受2个参数,row传递被勾选行数据,selected设置是否选中

(1)渲染表格

<el-table :data="listPowerSupplyTab" border ref="listPowerSupplyTab" width="100%"
       @selection-change="handleSelectionChange">
           <el-table-column  type="selection"  width="55"></el-table-column>
           <el-table-column prop="contacts" label="联系人"></el-table-column>
           <el-table-column prop="telephone" label="电话"></el-table-column>
           <el-table-column prop="powerSupplyMode" label="供电方式 "></el-table-column>     
</el-table>               

(2)watch监听数据

//  ref引用到Dom元素上,再执行dom上的toggleRowSelection方法

watch:{
   listPowerSupplyTab(n,o){
      this.$nextTick( ()=> {
         this.$refs.listPowerSupplyTab.toggleRowSelection(this.listPowerSupplyTab[0],true);
       })
    },
},

4.表格数据更新保持历史选中

(1)给表格添加row-key

<el-table :data="data" ref="tabData" @selection-change="onSelectionItem"

        :row-key="(row) => row.id" @select-all="onSelectAll">        

</el-table>

  注意:id需唯一

(2)给多选框添加默认选中

<el-table-column  type="selection" :reserve-selection="true"  width="55"></el-table-column>

(3)其他可能用到的方法

@selection-change     会返回所有选中的数据
@select     会返回所有选中的数据及当前操作的数据

this.$refs.table.clearSelection()     清空所有选中

this.$refs.table.toggleRowSelection(this.list[index])     默认选中

5.表格每次只展开一行

(1)表格部分

<el-table :data="tableData" @expand-change="rowExpand" :expand-row-keys="expands" :row-key="getRowKeys">
      <!-- 展开行 是另一个表格 begin -->
      <el-table-column type="expand" prop="" >
        <template slot-scope="props">
          <el-table :data="tableData2">
            <el-table-column prop="id" label="任务ID"></el-table-column>
            <el-table-column prop="taskName" label="任务名称"></el-table-column>
          </el-table>
        </template>
      </el-table-column>
      <!-- 展开行 是另一个表格 end -->
      <el-table-column prop="taskName" label="任务名称"></el-table-column>
      <el-table-column prop="taskFlag" label="任务状态"></el-table-column>
</el-table>

(2)data数据部分

data(){

        return{

                expands:[],     //  只展开一行放入当前行id

                getRowKeys(row){

                        return row.id

                }

        }

}

(3)方法部分

// 展开父表格数据 并查询该数据下的子数据
rowExpand(row, expandedRows) {
     console.log(row)
     let params = {
        taskId: row.id
      };

      // 获取子表格数据
      getSearchSubTask(params).then(res => {
        this.tableData2 = res.results;
      });
       let that = this
      if(expandedRows.length){
          that.expands = []

          if(row){

             that.expands.push(row.id)       //  只展开当前行

          }
      }else{    //   说明收起了

          that.expands = []

      }   
},

6.表格点击某行改变背景色

(1)表格部分

<el-table :data="data"  border  style="width: 100%"
    @row-click="selectRow"        // 给行添加鼠标点击事件
    :row-style="rowStyle"            // 设置行样式
>

</el-table>

(2)方法部分

// 鼠标点击行事件
selectRow(row, column, event) {
      console.log(row);
      console.log(column);
      console.log(event);
      this.name = row.name;
},
// 更改选中行背景色
rowStyle({ row }) {
      if (this.name === row.name) {
        return { 'background-color': '#F7EDED', cursor: 'pointer' };
      }
      return { cursor: 'pointer' };
},

(3)取消鼠标进入高亮显示

不然会影响rowStyle中自定义的行背景色效果

// 取消表格鼠标进入高亮显示
.el-table__row:hover > td {
    background-color: transparent;
}

7.表格某些行可展开某些行不可展开

(1)表格添加自定义属性名

<el-table :data="data" ......  :row-class-name="setClassName"></el-table>

(2)根据某个属性的值定义类名

// 设置表格某行是否有展开功能

setClassName({row,index}){

        return row.status==1 ?  ' '  :  'notExpand'  

}

(3)css控制notExpand隐藏

.notExpand .el-icon{

        display:none;

}

8.点击行选中取消选中当前行

(1)表格部分

<el-table :data="data" ...... @selection-change="handleSelectionChange"

   @row-click="selectRow"  ref="multipleTable">

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

</el-table>

(2)数据部分

data(){

        return{

                batchDeleteArr:[],

        }

}

(3)方法部分

//  选中当前行将当前行数据赋值给空数组

handleSelectionChange(val) {
    this.batchDeleteArr = val
},

//   判断选中行是否与数组内相同 根据是否为-1判断该行是否可选中
handleRowClick(row) {
   let that = this
   let findResult = that.batchDeleteArr.findIndex((value,index)=>{
      return value == row
   })
   if(findResult != -1){
       self.$refs.multipleTable.toggleRowSelection(row,false);
   }else {
       self.$refs.multipleTable.toggleRowSelection(row,true);
   }
}

9.弹框拖拽边界线问题

(1)新建elDialog.js文件

import Vue from 'vue'
// v-dialogDrag: 弹窗拖拽属性
Vue.directive('dialogDrag', {
  bind(el, binding, vnode, oldVnode) {
    const dialogHeaderEl = el.querySelector('.el-dialog__header');
    const dragDom = el.querySelector('.el-dialog');
    //dialogHeaderEl.style.cursor = 'move';
    dialogHeaderEl.style.cssText += ';cursor:move;'
    dragDom.style.cssText += ';top:0px;'

    // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
    const sty = (function () {
      if (window.document.currentStyle) {
        return (dom, attr) => dom.currentStyle[attr];
      } else {
        return (dom, attr) => getComputedStyle(dom, false)[attr];
      }
    })()

    dialogHeaderEl.onmousedown = (e) => {
      // 鼠标按下,计算当前元素距离可视区的距离
      const disX = e.clientX - dialogHeaderEl.offsetLeft;
      const disY = e.clientY - dialogHeaderEl.offsetTop;

      const screenWidth = document.body.clientWidth; // body当前宽度
      const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取) 

      const dragDomWidth = dragDom.offsetWidth; // 对话框宽度
      const dragDomheight = dragDom.offsetHeight; // 对话框高度

      const minDragDomLeft = dragDom.offsetLeft;
      const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;

      const minDragDomTop = dragDom.offsetTop;
      const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight;


      // 获取到的值带px 正则匹配替换
      let styL = sty(dragDom, 'left');
      let styT = sty(dragDom, 'top');

      // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
      if (styL.includes('%')) {
        styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100);
        styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100);
      } else {
        styL = +styL.replace(/\px/g, '');
        styT = +styT.replace(/\px/g, '');
      };

      document.onmousemove = function (e) {
        // 通过事件委托,计算移动的距离 
        let left = e.clientX - disX;
        let top = e.clientY - disY;

        // 边界处理
        if (-(left) > minDragDomLeft) {
          left = -(minDragDomLeft);
        } else if (left > maxDragDomLeft) {
          left = maxDragDomLeft;
        }

        if (-(top) > minDragDomTop) {
          top = -(minDragDomTop);
        } else if (top > maxDragDomTop) {
          top = maxDragDomTop;
        }

        // 移动当前元素  
        dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
      };

      document.onmouseup = function (e) {
        document.onmousemove = null;
        document.onmouseup = null;
      };
      return false
    }
  }
})

(2)main.js引入全局

import '@/utils//elDialog.js'     // el-dialog拖拽

(3)页面使用

<el-dialog title="审核信息" v-dialogDrag :visible.sync="dialogFormVisible" ></el-dialog>

10.表格展开行第一次打开没数据第二次打开有数据

<el-table :data="tableData"  style="width: 100%" border  row-key="id"
     @expand-change="changeRow">
     <el-table-column type="expand">
          <template #default="{ row }">
            <el-table :data="row.compareList"  border  style="width: 100%">
                 <el-table-column prop="modelId" label="model_id"></el-table-column>
                 <el-table-column prop="benchmarkName" label="benchmarkName">

                 </el-table-column>
            </el-table>
          </template>
     </el-table-column>
</el-table>  

changeRow(val) {
      const arr = [];
      this.compareList.splice(0);
      if (val.info.wait_for && val.info.wait_for.length) {
        val.info.wait_for.forEach((item) => {
          if (item.length) {
            arr.push(...item);
          }
        });
      }

      //  getLinkTestRend  封装的方法
      getLinkTestRend(arr).then((res) => {
        if (res && res.results && res.results.length) {
          const data = res.results.map((item) => {
            const obj = {
              modelId: item.info.model_id,
              benchmarkName: item.info.benchmark_name,
            };
            return obj;
          });
          // this.compareList.push(...data);
          // compareList = data

          const td = this.tableData.slice();
          td.forEach((item) => {
            if (item.id === val.id) {
              const e = item;
              e.compareList = data;
            }
          });
          this.tableData = td;
        }
      })

},

11.表格表头设置背景色

表格的header-cell-style属性是表头单元格的 style 的回调方法,也可以使用一个固定的 Object 为所有表头单元格设置一样的 Style

<el-table :data='list' border :header-cell-style="{background:'#f5f7fa',color:'#606266'}">

12.表格展开行默认全部展开

(1)表格部分

<el-table-column type="expand">
     <template slot-scope="props">
         <div class="material_box">
             <div class="material_item flex" v-for="(item,index) in props.row.material"                 :key="index">
                 <div>{{item.key}}</div>
                 <div>{{item.val}}</div>
             </div>
         </div>
     </template>
</el-table-column>

(2)方法部分

// 需要在updated周期函数中调用methods里的方法 否则methods里面获取不到页面元素
updated(){
    this.expandAll();
},
methods:{
     // 获取到页面元素  模拟点击可实现让树形表格展开
     expandAll () {

        // 获取点击的箭头元素
        var els = document.getElementsByClassName('el-table__expand-icon')  
        console.log(els)
        for (let i = 0; i < els.length; i++) {
           els[i].click()
        }
     },
}

13.表格数据滚动懒加载

scrollHeight:指元素的总高度 包含滚动条中的内容 只读属性 不带px单位

scrollTop:当元素出现滚动条时 向下拖动滚动条 内容向上滚动的距离 可读可写属性 不带px单位 如果该元素没有滚动条 则scrollTop的值为0 该值只能是正值

clientHeight:元素客户区的大小 指的是元素内容及其边框所占据的空间大小 实际上就是可视区域的大小 

scrollHeight-scrollTop-clientHeight=0,这个时候可以就是滚动条滚到底部的时候了

(1)第一次请求数据时设置1个变量记录请求次数

this.currentPage = 1

fun().then(res=>{

 this.totalPage = res.totalPage // 这里需要知道总页数

 this.tableData = res.data // 表格数据

})

(2)监听表格dom对象的滚动事件

let dom = document.querySelector(targetDom);  

dom.addEventListener("scroll", function() {

  const scrollDistance =dom.scrollHeight - dom.scrollTop - dom.clientHeight;

  if(scrollDistance <=0){ // 等于0证明已经到底,可以请求接口

   if(this.currentPage < this.totalPage){ // 当前页数小于总页数就请求

      this.currentPage++  // 当前页数自增

     // 请求接口

     fun().then(res=>{

        // 将请求回来的数据和当前展示的数据合并在一起

      this.tableData = this.tableData.concat(res.data)

     })   

   }

 }

})

14.dropdown下拉复选框+全选+搜索功能

(1)html部分

<template>
  <div>
    <!-- 下拉有多选功能  还能输入搜索 -->
    <el-dropdown trigger="click" @visible-change="onVisibleChange" class="dropdown">
      <span class="el-dropdown-link">
        下拉菜单<i class="el-icon-arrow-down el-icon--right"></i>
      </span>
      <el-dropdown-menu slot="dropdown" :hide-on-click="false">
        <div class="drop">
          <div style="width: 100%">
            <el-input v-model="input" @input="inputEvent" class="input" size="mini"
              prefix-icon="el-icon-search"  placeholder="搜索" clearable style="width: 100%">
            </el-input>
          </div>
          <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll"
            @change="handleCheckAllChange" class="checkAlls">
            全选

          </el-checkbox>
          <div class="checkAllLine"></div>
          <el-checkbox-group v-model="isCheckIdList" v-if="checkboxLists.length > 0"
            @change="handleCheckedChange">
             <div class="checkboxLists">
                 <el-checkbox  v-for="item in checkboxLists" :label="item[keys]" :key="item[keys]"
                   style="display: block" class="checiboxItem">
                   {{ item.label }}
                 </el-checkbox>
            </div>
          </el-checkbox-group>
          <div v-if="checkboxLists.length === 0"  class="noData">无数据</div>
          <div class="footer">
             <el-button type="primary" plain size="mini" class="footer_close">关 闭</el-button>
             <el-button type="primary" size="mini" class="footer_sure" @click="determine">
               确 定
             </el-button>
          </div>
        </div>
      </el-dropdown-menu>
    </el-dropdown>
  </div>
</template>

(2)js部分

<script>
/*
 *
 * 数据说明
 * 传进来的数据
 * checkBoxList 里面item一定有key是id,表示唯一值,label用来展示
 * checkBoxList: [{ id: "1", label: "张三", age: 5 },{ id: "2", label: "李四", age: 6 }] // 表示传进来的列表
 * defaultCheckBoxList:['1', '2', '3'] // 默认选中的值
 * keys: "id" // 表示 表示唯一值字段名称
 *
 * 向父级传值:
 * let obj = {
 *  initList, // 原始数组值
 *  initIsCheckId, // 原始id列表值
 *  isCheckIdList, // 选中的id列表值
 *  isCheckEdItem, // 选中的item列表值
 * };
 * this.$emit("checked", obj); // 把选中的信息抛出
 */

export default {
  data() {
    return {
      input: "",
      state2: "",
      checkAll: false,
      isCheckIdList: [], // 选中的
      isIndeterminate: false,
      checkboxLists: [],
      initList: [], // initList: [{ id: "1", label: "张三11", age: 5 }, { id: "2", label: "李四", age: 6 },],
      initIsCheckId: [], // 初始化id列表
    };
  },
  props: {
    keys: {
      type: String,
      default: "id", // 模拟数据 唯一值 是id
    },
    checkBoxList: {
      type: Array,
      default: [
        // 模拟数据 从父组件传进来的数据格式
        { id: "1", label: "张三", age: 5 },
        { id: "2", label: "李四", age: 6 },
        { id: "3", label: "王五", age: 7 },
        { id: "4", label: "赵六 ", age: 8 },
        { id: "5", label: "小英", age: 9 },
        { id: "6", label: "王麻子", age: 10 },
        { id: "7", label: "王小二", age: 11 },
        { id: "8", label: "老王", age: 12 },
        { id: "9", label: "小李", age: 13 },
      ],
    },
    defaultCheckBoxList: {
      type: Array,
      default: ["3", "4", "5"], // 模拟数据 默认选中的id列表
    },
  },

  mounted() {
    this.init();
  },

  methods: {
    init() {
      let { defaultCheckBoxList = [], checkBoxList = [] } = this;
      this.initList = checkBoxList;
      this.checkboxLists = this.deepClone(checkBoxList); // 深拷贝一下
      if (defaultCheckBoxList.length === 0) return;
      let arr = this.getIdList();
      this.initIsCheckId = this.deepClone(arr);
      this.isCheckIdList = arr;
      this.defaultCheckAllStatus();
      // 默认选中 end
    },

    // 提取id列表
    getIdList() {
      let { defaultCheckBoxList, keys = "id" } = this;
      // 默认选中 start
      let item = defaultCheckBoxList[0];
      let types = Object.prototype.toString.call(item);
      let arr = [];
      // 传的是id字符串
      if (types === "[object String]") arr = defaultCheckBoxList;
      // 传的是数组对象包含id
      if (types === "[object Object]") arr = defaultCheckBoxList.map((x) => x[keys] + "");
      // 传的是id数字
      if (types === "[object Number]") arr = defaultCheckBoxList.map((x) => x + "");
      return arr;
    },

    // 确定
    determine() {
      console.log("isCheckIdList", this.isCheckIdList);
      let { keys, isCheckIdList, checkBoxList, initIsCheckId } = this;
      let isCheckEdItem = checkBoxList.filter((x) => isCheckIdList.includes(x[keys]));
      let initList = this.deepClone(this.initList);
      let obj = {
        initList, // 原始数组值
        initIsCheckId, // 原始id列表值
        isCheckIdList, // 选中的id列表值
        isCheckEdItem, // 选中的itemList值
      };
      console.log("obj", obj);
      this.$emit("checked", obj); // 把选中的信息抛出
    },

    onVisibleChange(v) {
      console.log("是否展示:", v);
      if (!v) {
        // 关闭后
        let initArId = this.initIsCheckId.sort().toString();
        let isCheckIdList = this.isCheckIdList.sort().toString();
        console.log("关闭dropdown,前后选项是否相同:", initArId === isCheckIdList);
        if (initArId === isCheckIdList) return; // 选中的值相同 可不请求
        this.determine();
      }
    },

    // 输入事件
    inputEvent(val = "") {
      val = (val + "").toLowerCase();
      let arr = [];
      if (val === "") {
        // 输入为空 把原始数组赋值
        let ars = this.deepClone(this.initList);
        this.checkboxLists = ars;
      } else {
        // 有输入的内容 提取和输入的内容 匹配列表的label 相关内容
        arr = this.checkboxLists.filter((x) => x.label.includes(val));
        this.checkboxLists = arr;
      }
      this.defaultCheckAllStatus();
    },

    // 默认全选状态
    defaultCheckAllStatus() {
      // 选中的和原始值长度一样 全选
      this.checkAll = this.isCheckIdList.length === this.initList.length;

      // 选中的大于0 并且小于原始数组长度,半选状态
      this.isIndeterminate =
        this.isCheckIdList.length > 0 && this.isCheckIdList.length < this.initList.length;
    },

    // 点击全选
    handleCheckAllChange(val) {
      let { keys, checkboxLists } = this;
      let idList = checkboxLists.map((x) => x[keys]);
      this.isCheckIdList = val ? idList : [];
      this.isIndeterminate = false;
      //
      this.$emit("isCheckEdfn", { isCheckIdList: this.isCheckIdList });
    },

    // 点击 某一项
    handleCheckedChange(value) {
      let checkedCount = value.length;
      this.checkAll = checkedCount === this.checkboxLists.length;
      this.isIndeterminate = checkedCount > 0 && checkedCount < this.checkboxLists.length;
    },

    // 深拷贝
    deepClone(source) {
      if (typeof source !== "object" || source == null) {
        return source;
      }
      const target = Array.isArray(source) ? [] : {};
      for (const key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
          if (typeof source[key] === "object" && source[key] !== null) {
            target[key] = this.deepClone(source[key]);
          } else {
            target[key] = source[key];
          }
        }
      }
      return target;
    },
  },
};
</script>

(3)css部分

<style lang="scss" scoped>
.dropdown {
  cursor: pointer;
}
.drop {
  padding: 10px;
}
.input {
  width: 100px;
  margin: 0 auto;
  width: 100%;
}
.checkAlls {
  margin-top: 5px;
  padding-bottom: 5px;
  display: block;
}
.checkAllLine {
  width: 75%;
  border-bottom: 1px solid #e4e4e4;
  margin: 0 auto;
}
.checkboxLists {
  max-height: 260px;
  padding-right: 10px;
  overflow-y: scroll;
  .checiboxItem {
    margin: 3px 0;
  }
}
.noData {
  margin: 20px 0;
  font-size: 14px;
  color: #ccc;
  width: 100%;
  text-align: center;
}
.footer {
  margin-top: 15px;
  width: 100%;
  text-align: center;
  .footer_sure {
    margin-left: 20px;
  }
}
</style>

15.table展开行动态更新数据时视图没有自动更新

这是因为在给table的数据赋值时,展开的视图对应的字段不存在  (动态增加属性)
拿到table数据后,先把展开字段初始化,然后再赋值

先调一个接口拿list的数据,然后再掉一个接口拿list[i].subTable的数据,第一个接口的数据没有subTable这个字段,所以后来再赋值的时候视图没有自动更新,只要在第一次拿数据的时候给每个数据加上这个字段就可以了

(1)table部分

<template>
    <el-table ref="table" :data="list" @expand-change="onExpandChange">
        <el-table-column type="expand">
            <template slot-scope="scope">
                <el-table :data="scope.row.subTable" size="mini">
                    <el-table-column label="姓名" prop="name"></el-table-column> 
                </el-table> 
                <el-pagination  layout="prev,pager,next"  :current-page="scope.row.page||1"
                      :total="scope.row.total||0"   @current-change="(page)=>
                       onSubtablePageChange(page,scope.row)">

                </el-pagination>
            </template> 
        </el-table-column> 
    </el-table>
</template>

(2)js部分

method: {
    // 拿外层table数据
    async getList() {
        let params = {
            page: this.page,
        }
        let res = await task.getTaskList(params)

        /*这里是要加的代码,把展开的字段加上去就好了*/
        res.rows.forEach(row => {
            row.subTable = []
            row.total = 0
        })

        this.list = res.rows
        this.total = res.total
    },

············································
    // 拿展开的subtable数据
    async getSubtable(row) {
        let params = {
            id: row.id,
            page: row.page
        }
        if (!row || !row.id) {
            return
        }
        let res = await task.getSubtable(params)
        row.subTable = res.rows
        row.total = res.total
    },
}

16.el-select下拉框宽度自适应

思路:focus时获取到select框的宽度,复制个一个变量,将这个宽度绑定到option上

<el-select v-model="item.text" @focus="setOptionWidth">
      <el-option  :style="{width:selectOptionWidth}"  v-for="(item, index) in arr"
          :key="index" :label="item.name"  :value="item.name">
      </el-option>
</el-select>

data(){

        return{

                selectOptionWidth:' '

        }

}

setOptionWidth(event){
    // 下拉框弹出时,设置弹框的宽度
      this.$nextTick(() => {
        this.selectOptionWidth = event.srcElement.offsetWidth + "px";
      });      
}

17.表格根据接口返回参数动态生成表头和数据(行+列)

<el-row :gutter="15">
   <el-col :span="24">
      <el-table class="tableClass" :data="formData.result" border height='350' width='500'>
          <el-table-column v-for="key in formData.listkey" :key="key" :prop="key"
                :label="key"></el-table-column>
          </el-table>
    </el-col>
</el-row>

data() {
    return {
        formData: {
           result: [],
           listkey:[],
        },

    }
}
methods: {
    batchSql(){
      this.formData.listkey=[]
      this.formData.result=[]
      let reSql = this.formData.sql.split("\n");
      let prot = parseInt(this.formData.prot)
      this.$axios.post('/batchSql/', { "workspaceEnv":"rests",
        "tenant":this.formData.tenant})
        .then((res)=>{
            this.formData.result =res.data 
            // 提取表头字段 
            for (let i = 0, l = this.formData.result.length; i < l; i++) {
               for (let key in this.formData.result[i]) {
                  if (this.formData.listkey.indexOf(key)==-1){
                      this.formData.listkey.push(key)
                  }else{
                      console.log("============xxxx===========")
                  }
               }
             }
             console.log(this.formData.listkey,"==============",this.formData.result);   
        })
    }, 
 }

}

18.el-tree中图片展示

el-tree中的数据属于循环的,如果直接在el-tree内引入图片,打包后在测试上是不显示图片的,需要先在data中定义变量,require引入图片,然后再在标签内绑定变量:

data(){

        return {

                newImgPng:require('@/assets/images/zhibiao.png')

        }

}

<el-tree>

        ......

        <img :src="newImgPng">

</el-tree>

19.表格某列背景色高亮

<el-table :cell-style="columnbackgroundStyle">

// columnIndex为列下标
columnbackgroundStyle({ row, column, rowIndex, columnIndex }) {
    if (columnIndex == 1) {
        / / 让下标为1的列数背景颜色显示为红色
        return 'background:red;'
    }
},
 

20.表格调接口全局排序

(1)标签中定义排序方法

<el-table ref="reset"  v-loading="loading" :data="tableData"
        height="520" border  @sort-change="sortChange">
</el-table>

(2)定义排序关键字

<el-table-column prop="sumNum" label="次数" sortable="true" />

(3)实现方法

sortChange(column) {
      this.tableData = []
      if (column) {
        if (column.prop === 'sumNum' && column.order === 'ascending') {
          this.params.sort = 'sumNum,asc'
        } else if (column.prop === 'sumNum' && column.order === 'descending') {
          this.params.sort = 'sumNum,desc'
        }
        api({ ...this.params }).then(res => {
          this.tableData = res.frequency.content
        })
      }
    }

(4)清除排序状态

this.$refs.reset.clearSort()

21.表格滚动条切换页码后回到顶部

在切换页码方法内:

handleCurrentChange(page){

        this.page = page

        this.$nextTick(()) =>{

               this.$refs.tables.bodyWrapper.scrollTop = 0

        }

}

22.表格多选默认选中

使用 toggleRowSelection  在调用接口前就开始多选绑定

this.$nextTick(() =>{

        this.selectList.forEach(item =>{

                this.$refs.tables.toggleRowSelection(item)

        })

})

// 获取数据列表

this.getDataList()

23.el-tree选中高亮更改字体颜色

(1)给标签添加highlight-current属性

<el-tree ...... highlight-current>

(2)添加class样式

.org_con .el-tree--highlight-current .el-tree-node.is-current .el-tree-node content{

        background-color: rgba(135,26,235,.2);
        color:#000;
        font-weight: bold;

}

(3)还原子节点样式

.org con .el-tree-highligt-current .el-tree-node.is-current .el-tree-node_children .el-tree-node.is-expanded .el-tree-node_content{
        background-color: #fff!important;
        color: #606266!important;
        font-weight:1g0!important;

}

24.el-tab切换时table抖动

(1)给el-table设置ref

 <el-tabs v-model="activeName" @tab-click="handleTabClick">
   <el-tab-pane v-for="(item, i) in metadata" :key="i" :label="`${item.tableName}`" :name="`multipleTable${i}`">
     <el-table row-key="id" :key="i" :data="item.tableColumns" :ref="`multipleTable${i}`" style="width: 100%">
     </el-table>
   </el-tab-pane>
 </el-tabs>
 

(2)使用doLayout()方法

handleTabClick(tab) {
   const refName = `multipleTable${tab.index || 0}`
   this.$nextTick(() => {
     if (this.$refs[refName] && this.$refs[refName][0]) {
       this.$refs[refName][0].doLayout()
     }
   })
 },

25.改写el-timeline时间显示在左侧

<template>
  <div class="time-line">
    <el-timeline :reverse="true">
      <el-timeline-item
        v-for="(activity, index) in list"
        :key="index"
        color="#2991FF"
        size="large"
        type="primary"
      >
        <div class="time">
          <div>
            <span class="year">
              {{ activity.time.substring(5, 11) }}
            </span>
          </div>
          <div class="day">{{ activity.time.substring(0, 4) }}年</div>
        </div>
        <div class="ml10">
          <div class="list-title">{{ activity.title }}</div>
          <div class="list-company">{{ activity.name }}</div>
          <div class="list-desc">{{ activity.content }}</div>
        </div>
      </el-timeline-item>
    </el-timeline>
  </div>
</template>
 
<script>
  export default {
    data() {
      return {
        list: [
          {
            title: '欧洲天然气期货价格下跌13%至296欧元',
            content: '虚拟电厂概念股震荡走强,恒实科技(300)',
            name: '成都有限公司',
            time: '2022年10月25日',
          },
          {
            title: '欧洲天然气期货价格下跌13%至296欧元',
            content: '虚拟电厂概念股震荡走强,恒实科技(300)',
            name: '成都有限公司',
            time: '2022年10月24日',
          },
          {
            title: '欧洲天然气期货价格下跌13%至296欧元',
            content: '虚拟电厂概念股震荡走强,恒实科技(300)',
            name: '成都有限公司',
            time: '2022年10月23日',
          },
          {
            title: '欧洲天然气期货价格下跌13%至296欧元',
            content: '虚拟电厂概念股震荡走强,恒实科技(300)',
            name: '成都有限公司',
            time: '2022年10月22日',
          },
          {
            title: '欧洲天然气期货价格下跌13%至296欧元',
            content: '虚拟电厂概念股震荡走强,恒实科技(300)',
            name: '成都有限公司',
            time: '2022年10月21日',
          },
        ],
      }
    },
  }
</script>
 
<style lang="scss" scoped>
  .time-line {
    margin-top: 50px;
    margin-left: 200px;
  }
  .list-title {
    font-size: 16px;
    font-family: PingFangSC-Medium, PingFang SC;
    font-weight: 500;
    color: #181b1e;
  }
  .list-company {
    font-size: 14px;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #2991ff;
    margin-top: 15px;
    margin-bottom: 15px;
  }
  .list-desc {
    font-size: 14px;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #596878;
  }
  //左侧时间
  .time {
    color: #409eff;
    position: absolute;
    left: -94px;
    top: 1px;
    .year {
      font-size: 18px;
      font-family: PingFangSC-Regular, PingFang SC;
      font-weight: 400;
      color: #20354a;
    }
    .day {
      font-size: 14px;
      font-family: PingFangSC-Regular, PingFang SC;
      font-weight: 400;
      color: #596878;
      text-align: center;
      margin-top: 10px;
    }
  }
</style>

26.el-tree初始化默认选中第一个

(1)设置node-key和default-expanded-keys

<el-tree :data="treeData" node-key="id"  ref="orgTree"  lazy

        :default-expanded-keys="expandDefault"   @node-click="handleNodeClick">
</el-tree>

(2)data中定义默认选中的key

data(){

        return{

                treeData:[],

                expandDefault:[],

        }

}

(3)获取treeData数据时给默认数组赋值

getMoudle(){

        this.treeData= []

        this.expandDefault = []

        link_moudle_query().then(res =>{

                this.treeData = JSON.parse(JSON.stringify(res.data))

                this.expandDefault.push(this.treeData[0].id)

        }).catch(err =>{

                console.log(err)

        })

}

(4)watch监听数组

  watch: {
     'expandDefault':function(newVal, oldVal) {
       if(newVal){
         this.$nextTick(() => {
              document.querySelector('.el-tree-node__content').click()
          })
       }
     }
  },

27.el-switch开关点击相关问题

需求:点击开关时,原来的状态不改变,弹出确认框,选择确认:状态改变;取消:保持原状

但:使用v-model 点击时状态先改变,之后点击确认框失效

(1)将v-model改为:value=""

<template slot-scope="scope">
            // 修改前:v-model="scope.row.templateState"
            <el-switch
              :value="scope.row.templateState"
              active-text="有效"
              inactive-text="失效"
              @change="updateState(scope.row)"
            />
 </template>

(2)修改点击方法

// 状态处理
updateState(row) {
      this.$confirm(
        `确定执行${!row.templateState ? "有效" : "失效"}操作, 是否继续?`, "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
        }
      )
        .then(async () => {
          const query = {
            templateId: row.templateId,
            templateState: !row.templateState, // 修改后
            // 修改前:templateState: row.templateState,
          };
          updateState(query).then((res) => {
            if ( res.message === "操作成功") {
              this.apiList();
            }
          });
        })
        .catch(() => {
          this.$message.error("取消操作");
        });
},

28.在表格内点击el-popover中内容后关闭弹框

<el-table-column>
    <template slot-scope="{row}">
        <el-popover placement="bottom" title="更多" width="100" trigger="click" :ref="'popover' + row.id">
          <el-button type="primary" size="mini" @click="handleConfirm(row)">确定</el-button>
        </el-popover>
   </template>
</el-table-column>

这里ref使用变量的形式,因为是多个循环的el-popover
这里需要点击确定来关闭el-popover窗口,发现如下代码不生效:

handleConfirm(row) {
    this.$refs['popover' + row.id].doClose();
}

发现vue 不能检测到ref的值变化 不能触发视图更新,原因是表格中添加lazy 懒加载
通过如下代码解决:

handleConfirm() {
    // 模拟点击页面其它部分关掉弹层,因为该页面列表使用懒加载导致doClose无效
    document.body.click() 
}

29.el-tabs切换闪屏问题

现象:点击切换element ui中el-tabs时候,table会出现闪一下的状况;

// 初始element ui中el-tabs组件代码如下:

<el-tabs type="card" v-model="activeName">
  <el-tab-pane label="线路配置" name="first"><lineDetail /></el-tab-pane>
  <el-tab-pane label="车站配置" name="second"> <stationDetail /></el-tab-pane>
  <el-tab-pane label="特殊路段配置" name="three"><specialRoadDetail /></el-tab-pane>
  <el-tab-pane label="管界配置" name="four"><workManagementDetail /></el-tab-pane>
</el-tabs>

使用v-if="activeName==='first'"解决闪屏:

<el-tabs type="card" v-model="activeName">
  <el-tab-pane label="线路配置" name="first"><lineDetail v-if="activeName==='first'"/></el-tab-pane>
  <el-tab-pane label="车站配置" name="second"> <stationDetail v-if="activeName==='second'"/></el-tab-pane>
  <el-tab-pane label="特殊路段配置" name="three"><specialRoadDetail v-if="activeName==='three'"/></el-tab-pane>
  <el-tab-pane label="管界配置" name="four"><workManagementDetail v-if="activeName==='four'"/></el-tab-pane>
</el-tabs>

30.el-select实现全选和多选

<template>
  <div>
    <el-form ref="form" label-width="80px" :model="test">
      <el-row :gutter="20">
        <el-col :span="6">
          <el-form-item label="测试">
            <el-select  v-model="test.code" multiple collapse-tags v-bind="$attrs"
                 v-on="$listeners">
                 <el-checkbox  v-model="check"  class="m-l-20" @change="selectAll"
                  :indeterminate="test.code.length !== options.length">全选</el-checkbox>
                 <el-option  v-for="item in options" :key="item.value"
                    :label="item.label" :value="item.value" />
            </el-select>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
  </div>
</template>
...
data () {
    return {
      test: {
        code: ['选项1', '选项2', '选项3', '选项4', '选项5']
      },
      options: [
        { value: '选项1', label: '黄金糕' },
        { value: '选项2', label: '双皮奶' },
        { value: '选项3', label: '蚵仔煎' },
        { value: '选项4', label: '龙须面' },
        { value: '选项5', label: '北京烤鸭' }
      ]
    }
  },
  computed: {
    check: {
      get () {
        if (this.test.code.length === this.options.length) {
          return true
        }
        return false
      },
      set () {}
    }
  },
  methods: {
    ...
    selectAll (checked) {
      if (checked) {
        this.test.code = this.options.map(d => d.value)
      } else {
        this.test.code = []
      }
    }
  }

31.tooltip和dropdown弹框时定位问题

(1)tooltip

<template>
    <div>
        <el-tooltip
                placement="top"
                :append-to-body="false" <!-- 尤其重要参数 -->
                content="你好ToolTip"
                ref="mypop">  <!-- 为方便寻找,使用ref直接拿 -->
            <el-button>提示</el-button>
        </el-tooltip>
        <!-- 希望将tooltip的弹出部分内容的dom放在这里面 -->
        <div ref="here"></div>
    </div>
</template>
<script>
    export default {
        mounted() {
            // 在mounted的时候只需要使用这句话。
            this.$refs.here.appendChild(
                this.$refs.mypop.popperVM.$el
            )
        }
    }
</script>

(2)dropdown

<template>
    <div>
        <el-dropdown>
            <span class="el-dropdown-link">
                下拉菜单<i class="el-icon-arrow-down el-icon--right"></i>
            </span>
            <!--同样是将append-to-body参数设置为false-->
            <el-dropdown-menu slot="dropdown" :append-to-body="false" ref="mydropd">
                <el-dropdown-item>黄金糕</el-dropdown-item>
                <el-dropdown-item>狮子头</el-dropdown-item>
                <el-dropdown-item>螺蛳粉</el-dropdown-item>
                <el-dropdown-item disabled>双皮奶</el-dropdown-item>
                <el-dropdown-item divided>蚵仔煎</el-dropdown-item>
            </el-dropdown-menu>
        </el-dropdown>
        <div ref="here"></div>
    </div>
</template>
<script>
    export default {
        mounted() {
            this.$refs.here.appendChild(
                this.$refs.mydropd.popperElm
            )
        }
    }
</script>

32.el-tree只有最后一级可以选中

(1)template内

<el-tree
    class="filter-tree"
    :data="treeData" // 树形data数据,具体按照官方文档格式
    :props="defaultProps" // 自定义props配置,如严格按照官方格式无需添加此项,
    @check="checkChange" // checkbox 选项变化事件
    node-key="id" // 勾选时按照哪个值显示,必须是唯一的值
    accordion 
    check-strictly
    highlight-current
    show-checkbox 
    :default-expanded-keys="defaultArr"
    :default-checked-keys="defaultArr"
    :filter-node-method="filterNode"
    ref="tree">
</el-tree>

(2)script内

<script>
import ArrayUtils from "../../../../libs/utils/ArrayUtils"; // 处理只能选择最后一个节点

export default {
    name: "tree-dialog",
    data() {
        return {
            filterText: '', // 检索字段
            defaultProps: {
                children: 'children',
                label: 'name'
            },//过滤使用字段
            treeData: [],//资产大类树形结构数据
            checkedData: {},//当前点击的数据
        }
    },
    watch:{
        /** 监听检索字段变化 */
        filterText(val) {
            this.$refs.tree.filter(val);
        },
    },
    mounted(){
        //获取到treeData后 此处已省略请求数据过程,请自行添加  处理只能选择最后一个节点
        ArrayUtils.filterTreeData(this.treeData);
    },
    methods: {
        /** 控制树形单选 */
        checkChange(data, checked) {
            if (checked) {
                if (!!data.children && data.children.length>0) {
                    console.log("有子节点不可选")
                }else{
                    this.checkedData = data;
                    // 注意!!!
                    //1、下方的id和属性中 node-key="id"必须是同一个字段  
                    //2、$refs.tree 也需要和上方的属性匹配 ref="tree"

                    this.$refs.tree.setCheckedKeys([data.id]);
                }
            }
            console.log("checked data",data,this.checkedData)
        },
        /** 树形数据检索 */
        filterNode(value, data) {
            if (!value) return true;
            return data.name.indexOf(value) !== -1;
        },
    },
}
</script>

(3)处理只能选择最后一个节点 ArrayUtils 中的数据

/** 过滤树形数组,包含children的选项均禁用 */
function filterTreeData(treeData) {
    return treeData.filter(item => {
        if (isNotEmpty(item.children)) {
            item.disabled = true;
            item.children = filterTreeData(item.children)
        }
        return item
    })
}
export default {
    filterTreeData
}

33.el-dialog弹框拖拽边界线问题

(1)建一个js文件 elDialog.js文件

import Vue from 'vue'
// v-dialogDrag: 弹窗拖拽属性
Vue.directive('dialogDrag', {
  bind(el, binding, vnode, oldVnode) {
    const dialogHeaderEl = el.querySelector('.el-dialog__header');
    const dragDom = el.querySelector('.el-dialog');
    //dialogHeaderEl.style.cursor = 'move';
    dialogHeaderEl.style.cssText += ';cursor:move;'
    dragDom.style.cssText += ';top:0px;'

    // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
    const sty = (function () {
      if (window.document.currentStyle) {
        return (dom, attr) => dom.currentStyle[attr];
      } else {
        return (dom, attr) => getComputedStyle(dom, false)[attr];
      }
    })()

    dialogHeaderEl.onmousedown = (e) => {
      // 鼠标按下,计算当前元素距离可视区的距离
      const disX = e.clientX - dialogHeaderEl.offsetLeft;
      const disY = e.clientY - dialogHeaderEl.offsetTop;

      const screenWidth = document.body.clientWidth; // body当前宽度
      const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取) 

      const dragDomWidth = dragDom.offsetWidth; // 对话框宽度
      const dragDomheight = dragDom.offsetHeight; // 对话框高度

      const minDragDomLeft = dragDom.offsetLeft;
      const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;

      const minDragDomTop = dragDom.offsetTop;
      const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight;


      // 获取到的值带px 正则匹配替换
      let styL = sty(dragDom, 'left');
      let styT = sty(dragDom, 'top');

      // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
      if (styL.includes('%')) {
        styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100);
        styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100);
      } else {
        styL = +styL.replace(/\px/g, '');
        styT = +styT.replace(/\px/g, '');
      };

      document.onmousemove = function (e) {
        // 通过事件委托,计算移动的距离 
        let left = e.clientX - disX;
        let top = e.clientY - disY;

        // 边界处理
        if (-(left) > minDragDomLeft) {
          left = -(minDragDomLeft);
        } else if (left > maxDragDomLeft) {
          left = maxDragDomLeft;
        }

        if (-(top) > minDragDomTop) {
          top = -(minDragDomTop);
        } else if (top > maxDragDomTop) {
          top = maxDragDomTop;
        }

        // 移动当前元素  
        dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
      };

      document.onmouseup = function (e) {
        document.onmousemove = null;
        document.onmouseup = null;
      };
      return false
    }
  }
})

(2)main.js全局引入

import './elDialog'   // el-dialog拖拽

(3)页面使用

<el-dialog title="审核信息" v-dialogDrag :visible.sync="dialogFormVisible" ></el-dialog>

34.el-select多选增加全选功能

 <el-select filterable clearable v-model="tableHeadArr" multiple placeholder="请选择"         @change="selectChange" >
          <el-option label="全选" value="selectAll"  v-if="tableHeadList.length > 0"></el-option>
          <el-option
                v-for="item in tableHeadList"
                :key="item.id"
                :label="item.name"
                :value="item.id">
          </el-option>
</el-select>

// 首先要到data中定义tableHeadList:[],  tableHeadArr: [], oldSeleValue:[], 
// allSeleValue为下拉框的所有值可以直接在computed中定义

computed:{
    allSeleValue(){
      return this.tableHeadList.map(v=>v.id);
    }
  },


// methods中selectChange的方法
 selectChange(val){
       // 用来储存上一次的值,可以进行对比
        const oldVal = this.oldSeleValue.length === 1 ? this.oldSeleValue[0] : [];
        // 若是全部选择
        if (val.includes('selectAll')) {
            this.tableHeadArr = Object.assign([],this.allSeleValue);
            this.tableHeadArr.push('selectAll');
        }
        // 取消全部选中 上次有 当前没有 表示取消全选
        if (oldVal.includes('selectAll') && !val.includes('selectAll')) this.tableHeadArr = [];
        // 点击非全部选中 需要排除全部选中 以及 当前点击的选项
        // 新老数据都有全部选中

        if (oldVal.includes('selectAll') && val.includes('selectAll')) {

            const index = val.indexOf('selectAll');
            val.splice(index, 1); // 排除全选选项
            this.tableHeadArr = val
        }
        // 全选未选 但是其他选项全部选上 则全选选上 上次和当前 都没有全选
        if (!oldVal.includes('selectAll') && !val.includes('selectAll')) {

            if (val.length ===  this.allSeleValue.length) {

                this.tableHeadArr.push('selectAll');
            };
        }
        // 储存当前最后的结果 作为下次的老数据
        this.oldSeleValue[0] = this.tableHeadArr;

    },

35.el-upload上传文件后如何清空

<el-upload ......  ref="upload" :file-list="fileList" ......></el-upload>

this.$refs.upload.clearFiles()

36.表格展开行有子数据才显示展开按钮

<el-table
   :data="dataList"  border 
    ref="topicTable"
    :default-expand-all="false"    // 所有子菜单是否展开

    :row-class-name="getRowClass">  // 获取每一行的信息

     @expand-change="handledetail"   // 控制是否可以点击展开
</el-table>

// 对小箭头做了隐藏
 getRowClass(row,rowIndex){
       console.log(row)
       console.log(row.row.orderChildEntities)
       console.log(typeof(row.row.orderChildEntities))
       if(row.row.orderChildEntities===null){    // 判断当前行是否有子数据
          return 'row-expand-cover'
        }
 },
 //之前做了隐藏 ,但是还是可以点击展开下级的,加此方法屏蔽点击展开功能
  handledetail(row,expandedRows){
    if(row.orderChildEntities==null){
         this.$refs.topicTable.toggleRowExpansion(row,false)
       }
    },

 <style>
   .row-expand-cover td:first-child .el-icon-arrow-right{visibility: hidden;}
  </style>

37.解决el-tabs跳转卡死问题

(1)使用el-row、el-col包裹组件

<tempalte>
  <div class="log-box">
    <el-row>
      <el-col :span="24">
        <el-tabs>
          <el-tab-pane>1111</el-tab-pane>
          <el-tab-pane>22222</el-tab-pane>
        </el-tabs>
      </el-col>
    </el-row>
  </div>
</template>

(2)在el-tabs上方加一个兄弟节点-空的块级元素

<tempalte>
  <div class="log-box">
     <div>&nbsp;</div>
     <el-tabs>
        <el-tab-pane>1111</el-tab-pane>
        <el-tab-pane>22222</el-tab-pane>
     </el-tabs> 
  </div>
</template>

38.在el-select与el-input前添加icon图标

(1)el-input

<div class="demo-input-suffix">
  属性方式:
  <el-input
    placeholder="请选择日期"
    suffix-icon="el-icon-date"
    v-model="input1">
  </el-input>
  <el-input
    placeholder="请输入内容"
    prefix-icon="el-icon-search"
    v-model="input2">
  </el-input>
</div>
<div class="demo-input-suffix">
  slot 方式:
  <el-input
    placeholder="请选择日期"
    v-model="input3">
    <i slot="suffix" class="el-input__icon el-icon-date"></i>
  </el-input>
  <el-input
    placeholder="请输入内容"
    v-model="input4">
    <i slot="prefix" class="el-input__icon el-icon-search"></i>
  </el-input>
</div>

<script>
export default {
  data() {
    return {
      input1: '',
      input2: '',
      input3: '',
      input4: ''
    }
  }
}
</script>

(2)el-select

<template slot="menuLeft">
      <el-select v-model="deviceDataId" filterable
            size="small" @visible-change="deviceVisibleChange"
            @change="deviceSelectChange" placeholder="请选择设备生成图表">
            <template slot="prefix">
               <span style="padding: 5px;line-height: 33px;font-size: 18px;         
                    color:#409eff;">
                    <i class="el-icon-s-data"></i>
               </span>
            </template>
            <el-option v-for="item in devOptions" :key="item.deviceId"
                :label="item.deviceName" :value="item.deviceId">
            </el-option>
      </el-select>
 </template>

39.el-dropdown绑定click点击事件不生效和样式修改

<el-dropdown trigger="click" placement="bottom-end">
     <el-dropdown-menu   slot="dropdown"  :append-to-body="false"
          class="popper-dropdown" >
          <el-dropdown-item @click.native="changePasswordt">
             <span @mouseover="mouseOverFirst" @mouseleave="mouseLeaveFirst">

                    修改密码

             </span>
          </el-dropdown-item>
          <el-dropdown-item @click.native="modifyMailbox">
              <span @mouseover="mouseOverSecond" @mouseleave="mouseLeaveSecond">

                     修改邮箱

              </span>
          </el-dropdown-item>
          <el-dropdown-item @click.native="logout">
               <span @mouseover="mouseOverThird" @mouseleave="mouseLeaveThird">

                     退出登录

               </span>
          </el-dropdown-item>
     </el-dropdown-menu>
</el-dropdown>

40.表格选中+分页,保存已选中的数据

(1)添加row-key和ref

<el-table ref="table"  v-loading="loading" :data="dataList"  row-key="id"
       @select="selectItem" @select-all="selectAll">
        <el-table-column  key="1" type="selection"  width="40" reserve-selection />
</el-table>

(2)定义单选和全选方法

selectItem(list,row){

        this.checkList = list

}

selectAll(selection) {
      // 若取消全选,当前页的选中数据移除
      if (selection.length === 0) {
        const ids = this.dataList.map((i) => {
          return i.id
        })
        for (var i = 0; i < this.checkList.length; i++) {
          if (ids.indexOf(this.checkList[i].id) > -1) {
            this.checkList.splice(i, 1)
            i--
          }
        }
      }
      const arr = [...selection, ...this.checkList]
      this.checkList = Array.from(new Set(arr))
},

(3)清空所有选中的数据

this.$refs.table.clearSelection()
this.checkList = []

41.修改面包屑字体颜色

<el-breadcrumb separator-class="el-icon-arrow-right">
  <el-breadcrumb-item class="myColor">第一层</el-breadcrumb-item>
  <el-breadcrumb-item class="myColor">第二层</el-breadcrumb-item>
</el-breadcrumb>

// 重写面包屑的字体颜色
.myColor /deep/ .el-breadcrumb__inner {
  color: #3A6DF3 ;
}
// 或者这样写
.myColor >>> .el-breadcrumb__inner {
  color: #3A6DF3 ;
}

四、Echarts

1.Echarts折线图样式修改

option = {
    title: {
        text: '堆叠区域图'
    },
    tooltip : {
        trigger: 'axis',
        axisPointer: {
            type: 'cross',
            label: {
                backgroundColor: '#6a7985'
            }
        }
    },
    legend: {
        data:['邮件营销','联盟广告','视频广告','直接访问','搜索引擎']
    },
    toolbox: {
        feature: {
            saveAsImage: {}
        }
    },
    grid: {
        left: '3%',
        right: '4%',
        bottom: '3%',
        containLabel: true
    },
    xAxis : [
        {
            type : 'category',
            boundaryGap : false,
            data : ['周一','周二','周三','周四','周五','周六','周日']
        }
    ],
    yAxis : [
        {
            type : 'value'
        }
    ],
    series : [
      
        {
            name:'搜索引擎',
            type:'line',
            symbol:'circle',//拐点设置为实心
            symbolSize:8,//拐点大小
            stack: '总量',
            animation:true,//false: hover圆点不缩放 .true:hover圆点默认缩放
            lineStyle:{
                normal:{
                    color:'red',//折线的颜色
                    width:'2'//折线粗细
                }
            },
            itemStyle:{
              normal:{
                  color:'red',//拐点颜色
                  borderColor:'#000000',//拐点边框颜色
                  borderWidth:3//拐点边框大小
              },
              emphasis: {
                    color: '#000000'//hover拐点颜色定义
                }
            },
            areaStyle: {normal: {
                color:'#999999'//折线下面区块的颜色
            }},
            data:[820, 932, 901, 934, 1290, 1330, 1320]
        }
    ]
};

2.隐藏坐标轴

xAxis: {
    show:false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
    axisTick:{
          show:false // 不显示坐标轴刻度线
    },
    axisLine: {
          show: false, // 不显示坐标轴线
    },
    axisLabel: {
          show: false, // 不显示坐标轴上的文字
    },
},
yAxis: {
    splitLine:{
         show:false // 不显示网格线
     },
},

3.图表切换后缩成一团

 this.$nextTick(function () {
  	var myEvent = new Event('resize');
    window.dispatchEvent(myEvent);
});

4.Echarts实现伪3D柱状图

var xData = ["测试1", "测试2", "测试3", "测试4", "测试5", "测试6"]
var line = ["581", "870", "684","1568","608","2684"];
var attr ={
       'name':'月平均单价',
       'unit':'元/单'
}
var colors = []
option = {
   tooltip: {
       textStyle: {
        fontSize: 20
      },
      trigger: '',
      padding: 1,
        
      formatter: function(param) {
            
            var resultTooltip =
                "<div style='background:rgba(13,5,30,.6);border:1px solid                 rgba(255,255,255,.2);padding:5px;border-radius:3px;'>" +
                "<div style='text-align:center;'>" +  param.name + "</div>" +
                "<div style='padding-top:5px;'>"+
                "<span style=''> " +attr.name + ": </span>" +
                "<span style=''>" + param.value + "</span><span>" + attr.unit + "</span>"+
                "</div>" +
                "</div>";
            return resultTooltip
        }
    },
   
    grid: {
         left:"12%",
    right:'4%',
    top:'10%',
    bottom:"13%"
    },
    legend: {
        show: true,
        icon: 'circle',
        orient: 'horizontal',
        top: '90.5%',
        right: 'center',
        itemWidth: 16.5,
        itemHeight: 6,
        // itemGap: 30,
        textStyle: {
            color: '#C9C8CD',
            fontSize: 14
        }
    },
    xAxis: [{
        data: xData,
        axisLabel: {
            show:true,
            textStyle: {
                color: '#97ABEA',
                fontSize:12
            },
            margin: 10, //刻度标签与轴线之间的距离。
        },
 
        axisLine: {
            show: true, //不显示x轴
            lineStyle: {
                type: "solid",
                color: "#97ABEA"
            }
        },
        axisTick: {
            show: false //不显示刻度
        },
        boundaryGap: true,
        splitLine: {
            show: false,
            width: 0.08,
            lineStyle: {
                type: "solid",
                color: "#97ABEA"
            }
        }
    }],
    yAxis: [{
        show: true,
        splitLine: {
            show: true,
            lineStyle: {
                color: '#97ABEA',
                type: 'solid'
            }
        },
        axisTick: {
            show: false
        },
        axisLine: {
            show: true,
            lineStyle: {
                type: "solid",
                color: "#97ABEA"
            }
        },
        axisLabel: {
            textStyle: {
                color: '#97ABEA'
            },
        }
    }],
    series: [
        {//柱底圆片
            name: "",
            type: "pictorialBar",
            symbolSize: [30, 11],//调整截面形状
            symbolOffset: [0, 5],
            z: 12,
            itemStyle: {
                    'normal':{
                        color: function(params){
                            var colorArr = [ '#C1232B','#B5C334',
                            '#FCCE10','#E87C25','#27727B',
                            '#FE8463','#9BCA63'];
                            return colorArr[params.dataIndex]
                        },
                    }
                },
            data: line
        }, 
        
        //柱体
        {
            name: '',
            type: 'bar',
            barWidth: 30,
            barGap: '0%',
            itemStyle: {
                    normal: {
                            color: function(params) {
 
                                        // build a color map as your need.
 
                                        var colorList = [
 
                                          '#C1232B','#B5C334','#FCCE10','#E87C25','#27727B',
 
                                           '#FE8463','#9BCA63','#FAD860'
                                           
 
                                        ];
 
                                        return colorList[params.dataIndex]
 
                                    },
                            opacity: .7
                        }
                },
           
            data: line
        }, 
        
        //柱顶圆片
        {
            name: "",
            type: "pictorialBar",
            symbolSize: [30, 11],//调整截面形状
            symbolOffset: [0, -5],
            z: 12,
            symbolPosition: "end",
                "itemStyle": {
                    'normal':{
                        color: function(params){
                            var colorArr = [ '#C1232B','#B5C334',
                            '#FCCE10','#E87C25','#27727B',
                            '#FE8463','#9BCA63'];
                            return colorArr[params.dataIndex]
                        },
                    }
                },
            data: line
        }
    ]
};

5.页面报错  "echarts.graphic is undefined"

原代码:

itemStyle: {
     color: new echarts.graphic.LinearGradient(
         0, 0, 0, 1,
         [
           { offset: 0, color: '#83bff6' },
           { offset: 0.5, color: '#188df0' },
           { offset: 1, color: '#188df0' }
         ]
     )
}

需要将new echarts.graphic.LinearGradient 改成:new this.echarts.graphic.LinearGradient

6.设置 tooltip 背景框颜色文字颜色

未完待续......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值