一、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)方案二:借助重定向
- 创建一个空的页面:
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>
- 挂载路由:
src/router/index.js
{
path: '/redirect',
component: () => import('@/layout/components/redirect.vue')
},
- 菜单跳转的地方添加事件,进行相关处理
<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 -vnpm 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> </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 背景框颜色文字颜色
未完待续......