1. el-table分页数据+回显+勾选状态+记录数据(map实战) 原以为js中即便是学到了map可实际上也不会用到map,可我今天就遇到一个el-table分页查询,然后需要勾选表格内容,切换页码后回显勾选项的需求。
一开始想的是,把所有已勾选的数据用list来维护,可稍微一思索就发现这样实际执行起来还是有缺陷的,比如用于来回切换页码等场景稍微一复杂就容易乱套。
还是应该记录每一条数据的信息,用户点击勾选的时候,用当前的勾选情况去跟已勾选的数据做一个比对。如果已记录的数据里存在当前列表中的勾选项,同时本次属于勾选状态,则不做处理。
如果处于未勾选状态,则从用于记录的总数据中删除该选项。如果总得记录结果没有改数据,同时该数据本次是勾选状态,则把新数据添加进去。
用map是最好的了,于是就实战一下,试试手~
1 2 3 4 5 6 7 8 9 10 11 12 <el-button @click ="query" > 获取新数据</el-button > <el-table ref ="myTable" :data ="tableData" style ="width: 100%" @selection-change ="handleSelectionChange" > <el-table-column prop ="date" label ="日期" width ="180" > </el-table-column > <el-table-column prop ="name" label ="姓名" width ="180" > </el-table-column > <el-table-column prop ="address" label ="地址" > </el-table-column > <el-table-column type ="selection" width ="55" > </el-table-column > </el-table >
选择selection-change ,它会把当前页码的勾选项列出来。 接下来就是它对应的handle函数了,我把处理逻辑用备注的形式写出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 const selectedMap = new Map ();handleSelectionChange (val ) { const currSelectMap = new Map (); for (let i = 0 ; i < val.length ; i++) { currSelectMap.set (val[i].name , true ); } const selectList = []; this .tableData .forEach ((item ) => { const name = item.name ; selectList.push ({ name, selected : currSelectMap.has (name) ? true : false , }); }); selectList.forEach ((item ) => { const name = item.name ; const selected = item.selected ; if (selectedMap.has (name) && !selected) { selectedMap.delete (name); } if (!selectedMap.has (name) && item.selected ) { selectedMap.set (name, item); } }); console .log ("selectedMap" , selectedMap); },
最后的最后,el-table切换页码时候还需要额外处理一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 getRowKey (row ) { return row.name ; }, query ( ) { this .tableData = [ { date : "2016-05-02" , name : "王小虎4" , address : "上海市普陀区金沙江路 1518 弄" , }, { date : "2016-05-04" , name : "王小虎5" , address : "上海市普陀区金沙江路 1517 弄" , }, { date : "2016-05-01" , name : "王小虎6" , address : "上海市普陀区金沙江路 1519 弄" , }, { date : "2016-05-03" , name : "王小虎7" , address : "上海市普陀区金沙江路 1516 弄" , }, ]; for (let i = 0 ; i < this .tableData .length ; i++) { const name = this .tableData [i].name ; if (selectedMap.has (name)) { this .$nextTick(() => { this .$refs .myTable .toggleRowSelection (this .tableData [i], true ); }); } } },
就是切换到新数据时,我们要打勾,但是通过代码打钩的过程会触发handleSelectionChange函数这样就导致,可能就跟我们期待的差很多了,具体差到哪里,读者朋友可以把 this.$nextTick(DOM 更新结束后执行其指定的回调)去掉试试。
2. 修改ElementUI默认样式最直接有效的方法 做项目的过程在难免会遇到要修改ElementUI的默认样式
解决方法:
方式一:全局修改 写一个单独的CSS文件,里面直接用element自带得类名进行样式修改(部分需要添加 !important)。这种方法会将整个项目用到的该组件样式全部修改了。一般用来放公共样式,如表格、弹框、表单会用到。
css文件单独在main.js中引入就可以了
1 import "./style/reset.css" ;
方式二:组件内修改 单独在要修改的组件内再写一对标签,不要加scoped。 然后在里面直接修改样式就行,为了防止可能影响到其他组件的样式,建议加一层父盒子的类名。例如:我想修改类名为login-form的盒子内的 input 样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <div class ="login-form" > <el-form ref ="form" :model ="form" > <el-form-item > <el-input placeholder ="身份证号码" prefix-icon ="el-icon-user" v-model.trim ="form.name" > </el-input > </el-form-item > <el-form-item > <el-input placeholder ="请输入密码" prefix-icon ="el-icon-lock" v-model.trim ="form.password" autocomplete ="off" type ="password" @keypress.native.13 ="login" /> </el-form-item > <el-form-item > <div :underline ="false" style ="float: right;cursor: pointer;" > 忘记密码? </div > </el-form-item > <el-form-item > <div class ="clickLogin" @click ="login" > 登录</div > </el-form-item > </el-form > </div >
1 2 3 4 5 .login-form { .el-input__inner { color : #999 ; } }
如果不生效,也请加上 !important
/deep/跟>>>快被淘汰了,不建议使用
3. flex布局 三个div 两个左对齐 一个右对齐 一、问题 有一个盒子flex 布局,子元素有 三个div,在不改变dom结构的情况下,实现 前两个左对齐 第三个右对齐。
二、实现方案 在flex布局中如果某个元素的margin为auto
,那么它的margin将会自动填充为 剩下的空间 。
三、代码如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > flex布局</title > <style > *{ margin : 0 ; padding : 0 ; } .box { display : flex; justify-content : flex-start; } .block { width : 100px ; height : 100px ; border :1px solid black; } </style > </head > <body > <div class ="box" > <div class ="block" > 块1</div > <div class ="block" > 块2</div > // 此地margin-left:auto;自动填充了剩余空间 <div class ="block" style ="margin-left: auto;" > 块3</div > <div class ="block" > 块4</div > </div > </body > </html >
效果如下:
4. echart 柱状图y轴要显示成百分比 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <template > <div id ="main" style ="width: 600px; height: 400px" > </div > </template > <script > import * as echarts from 'echarts' export default { data ( ) { return { option : { xAxis : { type : 'category' , boundaryGap : false , data : ['1月' , '2月' , '3月' , '4月' , '5月' , '6月' , '7月' , '8月' , '9月' , '10月' , '11月' , '12月' ], }, yAxis : { type : 'value' , axisLabel : { show : true , interval : 'auto' , formatter : '{value} %' , }, max : 100 , min : 0 , }, series : [ { data : [100 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ], type : 'line' , areaStyle : {}, }, ], }, } }, mounted ( ) { let myChart = echarts.init (document .getElementById ('main' )) let option = this .option myChart.setOption (option) }, }
5. ECharts在柱状图的柱子上方显示数量的方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 <template > <v-chart :options ="getOptions()" /> </template > <script > export default { methods : { getOptions ( ) { return { title : { text : '企业诊断区域分布' }, tooltip : { trigger : 'axis' , axisPointer : { type : 'shadow' }, }, legend : { right : '0' }, grid : { left : '3%' , right : '4%' , bottom : '3%' , containLabel : true }, xAxis : [ { type : 'category' , data : ['婺城区' , '金东区' , '武义县' , '浦江县' , '磐安县' , '兰溪市' , '义务市' , '东阳时' , '永康市' ], axisTick : { alignWithLabel : true } } ], yAxis : [ { type : 'value' , } ], series : [ { name : '诊断数' , type : 'bar' , barWidth : '30%' , data : [1361 , 4036 , 1776 , 1225 , 2565 , 1231 , 1523 , 1189 , 1956 ], itemStyle : { normal : { label : { show : true , position : 'top' , textStyle : { color : '#999' , fontSize : 12 } } } } }, { name : '改造数' , type : 'bar' , barWidth : '30%' , data : [582 , 1918 , 1015 , 669 , 1124 , 640 , 710 , 612 , 791 ], itemStyle : { normal : { label : { show : true , position : 'top' , textStyle : { color : '#999' , fontSize : 12 } } } } } ] } }, }, }; </script > <style > </style >
6. 滚动条样式修改 前言 浏览器中的滚动条样式大家一定都不陌生,其样式并不好康。可能很多小伙伴还不知道,这个东东的样式也可以修改(仅支持部分现代浏览器),本次就来带大家用 CSS
修改一下它的样式。
一、认识滚动条 首先我们先来简单看一下滚动条是由哪几部分组成的:
当横向和纵向都有滚动条时,还会有一个交汇的部分(见下图),但是因为一般网页开发中都不会让横向出现滚动条(因为影响美观),所以这个小方块出现的频率不算太高。下图为同时有垂直滚动条和水平滚动条时交汇的部分:
二、解决方案 CSS伪类 目前我们可以通过 CSS伪类 来实现滚动条的样式修改,以下为修改滚动条样式用到的CSS伪类:
::-webkit-scrollbar — 整个滚动条
::-webkit-scrollbar-button — 滚动条上的按钮 (上下箭头)
::-webkit-scrollbar-thumb — 滚动条上的滚动滑块
::-webkit-scrollbar-track — 滚动条轨道
::-webkit-scrollbar-track-piece — 滚动条没有滑块的轨道部分
::-webkit-scrollbar-corner — 当同时有垂直滚动条和水平滚动条时交汇的部分
::-webkit-resizer — 某些元素的corner部分的部分样式(例:textarea的可拖动按钮)
此处附上MDN文档传送门:https://developer.mozilla.org/zh-CN/docs/Web/CSS/::-webkit-scrollbar
兼容性问题 当然这种解决方案还存在一定的兼容性问题,仅仅在支持WebKit的浏览器 (例如, 谷歌Chrome, 苹果Safari)可以使用。其实一看到 -webkit- 前缀就能明白它是 CSS3 中的 私有属性前缀 ,特定前缀是为了适配特定浏览器内核的。我们前往Can I use对其兼容性一探究竟:
由上图我们可以看到,兼容性并不算太好,不过我们也不用过于在意,毕竟我们只是规则的使用者而非制定者。
三、进行测试 1. 整个滚动条 我们一条属性一条属性来进行测试,首先使用 ::-webkit-scrollbar
。先改变一下它的宽度,测试一下效果:
1 2 3 4 5 ::-webkit-scrollbar { width : 50px ; }
我们可以看到,滚动条似乎“消失”了,但是仍然能靠鼠标拖动来滚动页面。我们再给它加一个背景色康康效果:
1 2 3 4 5 ::-webkit-scrollbar { width : 50px ; background-color : skyblue; }
增加背景颜色后,滚动条又“出现”了。结合刚才的代码我们不难看出:设置 ::-webkit-scrollbar
属性会使滚动条默认样式失效。既然如此,我们就必须结合其他属性一起使用。
2. 滚动条上的箭头按钮 我们来使用一下 ::-webkit-scrollbar-button
属性,发现当此属性单独使用时无任何效果:
1 2 3 4 ::-webkit-scrollbar-button { background-color : slateblue; }
于是乎我们加上之前的代码再试试:
我们可以看出,两个箭头的按钮位置的背景颜色发生了变化。看来,滚动条的其他伪类属性需要配合第一步中的 ::-webkit-scrollbar
才能生效。
3. 滚动条上的滚动滑块 我们用 ::-webkit-scrollbar-thumb
来改变滚动条中滑块的样式:
1 2 3 4 5 6 7 8 9 10 ::-webkit-scrollbar { width : 50px ; background-color : skyblue; } ::-webkit-scrollbar-thumb { background-color : orange; }
4. 滚动条轨道 用 ::-webkit-scrollbar-track
属性修改滚动条轨道样式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ::-webkit-scrollbar { width : 50px ; background-color : skyblue; } ::-webkit-scrollbar-thumb { background-color : orange; } ::-webkit-scrollbar-track { background-color : hotpink; }
通过效果图我们可以发现,设置的滚动条轨道背景色遮住了设置的整个滚动条的背景色(天蓝)。那是否可以实现两种背景色里外嵌套的效果呢,目前做出了几种尝试都没有效果,只能暂时放弃,以下为经测试未实现嵌套背景色效果代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ::-webkit-scrollbar { padding : 4px ; width : 50px ; background-color : skyblue; box-sizing : border-box; } ::-webkit-scrollbar-track { width : 80% ; background-color : hotpink; }
既然如此,我们如果需要调整滚动条的背景颜色,只需要在 ::-webkit-scrollbar
和 ::-webkit-scrollbar-track
中任选其一即可。
5. 滚动条没有滑块的轨道部分 这次我们同时设置 ::-webkit-scrollbar-track
和 ::-webkit-scrollbar-track-piece
来看效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ::-webkit-scrollbar { width : 50px ; } ::-webkit-scrollbar-thumb { background-color : orange; } ::-webkit-scrollbar-track { background-color : hotpink; } ::-webkit-scrollbar-track-piece { background-color : purple; }
上述代码符合预期效果,但是我给滑块设置透明的背景色(transparent)则会全是 purple
颜色,也不会出现滑块底部呈现 pink
颜色。所以,如果要改背景色还是选择轨道来修改吧。
6. 测试总结
设置 ::-webkit-scrollbar 属性会使滚动条默认样式失效
其他修改滚动条样式的私有属性需要配合 ::-webkit-scrollbar 属性使用
如果要设置滚动条背景色, ::-webkit-scrollbar 、 ::-webkit-scrollbar-track 、 ::-webkit-scrollbar-track-piece 三个属性设置一个即可。
四、开始换装 1. 纯色系滚动条 在研究过滚动条修改的 CSS
属性后我们终于可以开始动工了,先来仿照Element 中的滚动条样式,修改一个纯色系滚动条:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ::-webkit-scrollbar { width : 10px ; height : 10px ; } ::-webkit-scrollbar-thumb { background-color : #49b1f5 ; border-radius : 32px ; } ::-webkit-scrollbar-track { background-color : #dbeffd ; border-radius : 32px ; }
效果还不错,比默认的样式要好上不少。此处使用蓝色,实际开发中可以使用项目的主题色作为滚动条的配色参考。
2. 花纹系滚动条 我们可以利用 background-image
这一属性来实现滚动条的花纹效果(此处效果非本人原创),直接上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ::-webkit-scrollbar { width : 10px ; height : 10px ; } ::-webkit-scrollbar-thumb { background-color : #49b1f5 ; background-image : -webkit-linear-gradient (45deg , rgba (255 , 255 , 255 , 0.4 ) 25% , transparent 25% , transparent 50% , rgba (255 , 255 , 255 , 0.4 ) 50% , rgba (255 , 255 , 255 , 0.4 ) 75% , transparent 75% , transparent); border-radius : 32px ; } ::-webkit-scrollbar-track { background-color : #dbeffd ; border-radius : 32px ; }
7. 用CSS画图形 三角形 首先第一步,搭出盒子模型,给它加上边框。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta http-equiv ="X-UA-Compatible" content ="IE=edge" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .triangle { width : 50px ; height : 50px ; border : 2px solid; border-color : #3fed9c #d8b423 #06433c #0ca9f1 ; } </style > </head > <body > <div class ="triangle" > </div > </body > </html >
如下图所示:
步骤二、 将盒子的border设置为50px 变更代码如下:
1 2 3 4 5 6 .triangle { width : 50px ; height : 50px ; border : 50px solid; border-color : #3fed9c #d8b423 #06433c #0ca9f1 ; }
如下图所示:
步骤三、 此时中间白色的区域就是宽高(height,width)只要将他们设置为0就可以得到四个三角形 变更代码如下:
1 2 3 4 5 6 .triangle { width : 0 ; height : 0 ; border : 50px solid; border-color : #3fed9c #d8b423 #06433c #0ca9f1 ; }
如下图所示:
步骤四、 虽然完成了以上方式可以达到视觉上实现了三角形,但实际上,隐藏的部分任然占据部分高度,需要将上方的宽度去掉,然后再将两侧的颜色设置透明。变更代码如下:
1 2 3 4 5 6 7 .triangle { width : 0 ; height : 0 ; border-bottom : 50px solid #06433c ; border-left : 50px solid transparent; border-right : 50px solid transparent; }
如下图所示:
想要什么方向的三角形就将对立面不设置宽度,两边设置宽度并为透明
空心三角 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <style> .triangle { width : 0 ; height : 0 ; border-bottom : 50px solid #06433c ; border-left : 50px solid transparent; border-right : 50px solid transparent; position : relative; } .triangle ::after { content : '' ; border-bottom : 40px solid #04be9c ; border-left : 40px solid transparent; border-right : 40px solid transparent; position : absolute; top : 0 ; left : 0 ; } </style>
如果想要实现一个只有边框是空心的三角形,由于这里不能再使用border
属性,所以最直接的方法是利用伪类新建一个小一点的三角形定位上去。效果图如下:
伪类元素定位参照对象的内容区域宽高都为0,则内容区域即可以理解成中心一点,所以伪元素相对中心这点定位 将元素定位进行微调以及改变颜色,就能够完成下方效果图:
最终全局效果代码(空心三角形)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <!DOCTYPE html > <html lang="en"> <head> <meta charset="UTF-8 "> <meta http-equiv="X-UA-Compatible" content ="IE=edge"> <meta name="viewport" content ="width =device-width , initial-scale=1.0 "> <title>Document</title> <style> .triangle { width : 0 ; height : 0 ; border-bottom : 50px solid #06433c ; border-left : 50px solid transparent; border-right : 50px solid transparent; position : relative; } .triangle ::after { content : '' ; border-bottom : 40px solid #fff ; border-left : 40px solid transparent; border-right : 40px solid transparent; position : absolute; top : 6px ; left : -40px ; } </style> </head> <body > <div class="triangle"></div > </body > </html >
原理 可以看到,边框是实现三角形的部分,边框实际上并不是一个直线,如果我们将四条边设置不同的颜色,将边框逐渐放大,可以得到每条边框都是一个梯形
当分别取消边框的时候,发现下面几种情况:
取消一条边的时候,与这条边相邻的两条边的接触部分会变成直的
当仅有邻边时, 两个边会变成对分的三角
当保留边没有其他接触时,极限情况所有东西都会消失
通过上图的变化规则,利用旋转、隐藏,以及设置内容宽高等属性,就能够实现其他类型的三角形
8. 自定义表格,带滚动动画 html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <div class ="statusList" > <ul class ="seTable" > <li > #</li > <li > 区县市</li > <li > 数量</li > <li > 用电(wkW/h)</li > </ul > <div id ="orderItems" class ="outlineBorder" @mouseenter ="mouseenter()" @mouseleave ="mouseleave()" ref ="table" > <ul v-show ="radio1 == '1'" class ="rolling" v-for ="(item, index) of tableData" :key ="index" > <li > {{ index + 1 }}</li > <li > {{ item.area }}</li > <li > {{ item.num }}</li > <li > {{ item.consumption }}</li > </ul > <ul v-show ="radio1 == '2'" class ="rolling" v-for ="(item, index) of tableData" :key ="index" > <li > {{ index + 1 }}</li > <li > {{ item.industry }}</li > <li > {{ item.num }}</li > <li > {{ item.consumption }}</li > </ul > </div > </div >
Css 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 .statusList { width : 94% ; margin : 0 auto; margin-top : 5px ; .seTable { width : 100% ; padding-bottom : 0px ; overflow : hidden; display : flex; li { float : left; font-size : 16px ; color : #a2a2a2 ; background : linear-gradient (to right, #eee , #f4f4f4 ); padding : 7px 0 ; text-align : center; } li :nth-child (1 ) { width : 15% ; } li :nth-child (2 ) { width : 25% ; } li :nth-child (3 ) { width : 25% ; } li :nth-child (4 ) { width : 35% ; } } .outlineBorder { font-size : 15px ; position : relative; width : 100% ; overflow : hidden; // 可视高度 height : 240px ; ul { width : 100% ; height : 40px ; display : flex; justify-content : flex-start; } ul li { font-size : 16px ; color : #7c7c7c ; height : 40px ; line-height : 40px ; padding : 7px 0 ; text-align : center; overflow : hidden; white-space : nowrap; text-overflow : ellipsis; } ul li :nth-child (1 ) { width : 15% ; } ul li :nth-child (2 ) { width : 25% ; // text-align : left; } ul li :nth-child (3 ) { width : 25% ; } ul li :nth-child (4 ) { width : 35% ; } } }
js js部分写js动画
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 export default { data ( ) { return { tableData : [], timer : null , enter : false , isScroll : true , }; }, mounted ( ) { this .getCityData (); this .tableScroll (); }, methods : { changeData ( ) { console .log (this .radio1 ); if (this .radio1 == '1' ) { this .getCityData (); this .tableScroll (); } else if (this .radio1 == '2' ) { this .getIndustryData (); this .tableScroll (); } else if (this .radio1 == '3' ) { this .getChainData (); this .tableScroll (); } }, mouseenter ( ) { this .enter = true ; if (!this .isScroll ) return ; clearInterval (this .timer ); }, mouseleave ( ) { this .enter = false ; if (!this .isScroll ) return ; clearInterval (this .timer ); this .tableScroll (); }, tableScroll ( ) { clearInterval (this .timer ); const divData = this .$refs .table ; this .timer = setInterval (() => { divData.scrollTop += 1 ; if (divData.clientHeight == divData.scrollHeight ) { this .isScorll = false ; return clearInterval (this .timer ); } if ( divData.clientHeight + divData.scrollTop + 1 > divData.scrollHeight ) { clearInterval (this .timer ); setTimeout (() => { if (this .enter ) return ; divData.scrollTop = 0 ; this .tableScroll (); }, 1000 ); } }, 40 ) } }, };
10. highcharts 地图显示 获取地图JSON 数据 首页 | GeoJSON.cn
将json 数据拷贝到本地。
项目如果是vue-cli2创建的就放置在 static 文件夹。
如果是vue-cli3创建就没有static文件夹,那就放置在 public 文件夹下。
渲染数据 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 <template > <div class ="com-container" > <div id ="map-container" > </div > <div class ="coverMap" > </div > </div > </template > <script > import HighCharts from 'highcharts/highmaps' export default { data ( ) { return { mapData : [ ['兰溪' , 728 ], ['婺城' , 710 ], ['金东' , 963 ], ['浦江' , 541 ], ['义乌' , 622 ], ['武义' , 866 ], ['永康' , 398 ], ['东阳' , 785 ], ['磐安' , 223 ], ] }; }, mounted ( ) { this .getData (); }, methods : { getData ( ) { let data = this .mapData ; $.getJSON ('../../../../static/jinhua.json' , function (geojson ) { console .log (geojson); HighCharts .mapChart ('map-container' , { title : { text : '' }, mapNavigation : { enabled : true , buttonOptions : { verticalAlign : 'bottom' } }, colorAxis : { tickPixelInterval : 150 , labels : { } }, series : [{ data : data, mapData : geojson, joinBy : 'name' , keys : ['name' , 'value' ], name : '不知道啥数据' , states : { hover : { color : '#a4edba' } }, dataLabels : { enabled : true , format : `{point.name} {point.value}` , style : { width : '80px' } } }] }); }); }, }, }; </script > <style lang ="less" scoped > .com-container { width : 100% ; height : 100% ; overflow : hidden; position : relative; #map-container { width : 100% ; height : 100% ; } .coverMap { position : absolute; bottom : 0px ; right : 0 ; width : 150px ; height : 30px ; background-color : #fff ; z-index : 99 ; } } </style >
11. echarts 图表 百分比精度问题解决 在数据那加 toFixed() 即可解决
1 valueFormatter : (value ) => (value * 100 ).toFixed (0 ) + '%'
12. 如何实现上拉加载,下拉刷新? 一、前言 下拉刷新和上拉加载这两种交互方式通常出现在移动端中
本质上等同于PC网页中的分页,只是交互形式不同
开源社区也有很多优秀的解决方案,如iscroll
、better-scroll
、pulltorefresh.js
库等等
这些第三方库使用起来非常便捷
我们通过原生的方式实现一次上拉加载,下拉刷新,有助于对第三方库有更好的理解与使用
二、实现原理 上拉加载及下拉刷新都依赖于用户交互
最重要的是要理解在什么场景,什么时机下触发交互动作
上拉加载 首先可以看一张图
上拉加载的本质是页面触底,或者快要触底时的动作
判断页面触底我们需要先了解一下下面几个属性
scrollTop
:滚动视窗的高度距离window
顶部的距离,它会随着往上滚动而不断增加,初始值是0,它是一个变化的值
clientHeight
:它是一个定值,表示屏幕可视区域的高度;
scrollHeight
:页面不能滚动时也是存在的,此时scrollHeight等于clientHeight。scrollHeight表示body
所有元素的总长度(包括body元素自身的padding)
综上我们得出一个触底公式:
1 scrollTop + clientHeight >= scrollHeight
简单实现
1 2 3 4 5 6 7 8 9 let clientHeight = document .documentElement .clientHeight ; let scrollHeight = document .body .scrollHeight ;let scrollTop = document .documentElement .scrollTop ; let distance = 50 ; if ((scrollTop + clientHeight) >= (scrollHeight - distance)) { console .log ("开始加载数据" ); }
下拉刷新 下拉刷新的本质是页面本身置于顶部时,用户下拉时需要触发的动作
关于下拉刷新的原生实现,主要分成三步:
监听原生touchstart
事件,记录其初始位置的值,e.touches[0].pageY
;
监听原生touchmove
事件,记录并计算当前滑动的位置值与初始位置值的差值,大于0
表示向下拉动,并借助CSS3的translateY
属性使元素跟随手势向下滑动对应的差值,同时也应设置一个允许滑动的最大值;
监听原生touchend
事件,若此时元素滑动达到最大值,则触发callback
,同时将translateY
重设为0
,元素回到初始位置
举个例子:
Html
结构如下:
1 2 3 4 5 6 7 8 9 10 11 <main> <p class ="refreshText" > </p > <ul id ="refreshContainer" > <li > 111</li > <li > 222</li > <li > 333</li > <li > 444</li > <li > 555</li > ... </ul > </main >
监听touchstart
事件,记录初始的值
1 2 3 4 5 6 7 8 9 10 var _element = document .getElementById ('refreshContainer' ), _refreshText = document .querySelector ('.refreshText' ), _startPos = 0 , _transitionHeight = 0 ; _element.addEventListener ('touchstart' , function (e ) { _startPos = e.touches [0 ].pageY ; _element.style .position = 'relative' ; _element.style .transition = 'transform 0s' ; }, false );
监听touchmove
移动事件,记录滑动差值
1 2 3 4 5 6 7 8 9 10 11 12 13 _element.addEventListener ('touchmove' , function (e ) { _transitionHeight = e.touches [0 ].pageY - _startPos; if (_transitionHeight > 0 && _transitionHeight < 60 ) { _refreshText.innerText = '下拉刷新' ; _element.style .transform = 'translateY(' +_transitionHeight+'px)' ; if (_transitionHeight > 55 ) { _refreshText.innerText = '释放更新' ; } } }, false );
最后,就是监听touchend
离开的事件
1 2 3 4 5 6 7 _element.addEventListener ('touchend' , function (e ) { _element.style .transition = 'transform 0.5s ease 1s' ; _element.style .transform = 'translateY(0px)' ; _refreshText.innerText = '更新中...' ; }, false );
从上面可以看到,在下拉到松手的过程中,经历了三个阶段:
当前手势滑动位置与初始位置差值大于零时,提示正在进行下拉刷新操作
下拉到一定值时,显示松手释放后的操作提示
下拉到达设定最大值松手时,执行回调,提示正在进行更新操作
三、案例 在实际开发中,我们更多的是使用第三方库,下面以better-scroll
进行举例:
HTML结构
1 2 3 4 5 6 7 8 9 <div id="position-wrapper" > <div > <p class ="refresh" > 下拉刷新</p > <div class ="position-list" > </div > <p class ="more" > 查看更多</p > </div > </div >
实例化上拉下拉插件,通过use
来注册插件
1 2 3 4 5 import BScroll from "@better-scroll/core" ;import PullDown from "@better-scroll/pull-down" ;import PullUp from '@better-scroll/pull-up' ;BScroll .use (PullDown );BScroll .use (PullUp );
实例化BetterScroll
,并传入相关的参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 let pageNo = 1 ,pageSize = 10 ,dataList = [],isMore = true ; var scroll= new BScroll ("#position-wrapper" ,{ scrollY :true , click :true , pullUpLoad :true , pullDownRefresh :{ threshold :50 , stop :0 } }); scroll.on ("pullingDown" ,pullingDownHandler); scroll.on ("scroll" ,scrollHandler); scroll.on ("pullingUp" ,pullingUpHandler); async function pullingDownHandler ( ){ dataList=[]; pageNo=1 ; isMore=true ; $(".more" ).text ("查看更多" ); await getlist (); scroll.finishPullDown (); scroll.refresh (); } async function pullingUpHandler ( ){ if (!isMore){ $(".more" ).text ("没有更多数据了" ); scroll.finishPullUp (); return ; } pageNo++; await this .getlist (); scroll.finishPullUp (); scroll.refresh (); } function scrollHandler ( ){ if (this .y >50 ) $('.refresh' ).text ("松手开始加载" ); else $('.refresh' ).text ("下拉刷新" ); } function getlist ( ){ let result=....; dataList=dataList.concat (result); if (result.length <pageSize) isMore=false ; }
注意点:
使用better-scroll
实现下拉刷新、上拉加载时要注意以下几点:
wrapper
里必须只有一个子元素
子元素的高度要比wrapper
要高
使用的时候,要确定DOM
元素是否已经生成,必须要等到DOM
渲染完成后,再new BScroll()
滚动区域的DOM
元素结构有变化后,需要执行刷新 refresh()
上拉或者下拉,结束后,需要执行finishPullUp()
或者finishPullDown()
,否则将不会执行下次操作
better-scroll
,默认会阻止浏览器的原生click
事件,如果滚动内容区要添加点击事件,需要在实例化属性里设置click:true
小结 下拉刷新、上拉加载原理本身都很简单,真正复杂的是封装过程中,要考虑的兼容性、易用性、性能等诸多细节
13. 没登录的功能做路由拦截 这里之前做的有个bug,向下面这么写,直接拿sessionStorage里的数据,如果sessionStorage为空,则会直接返回白屏,什么都没有的bug。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 router.beforeEach (async (to, from , next) => { let routerList = JSON .parse (sessionStorage.getItem ('routerList' )); routerList = routerList.filter (item => { return item.state === 0 ; }) let router = routerList.map (item => { return item.router ; }) let username = sessionStorage.getItem ('username' ); console .log ('vuex' , routerList); console .log ('router' , router); if (username) { console .log ('toPath' , to.path ); if (router.includes (to.path )) { alert ('您没有访问的权限' ); next ('/' ) } else { next (); } } else { let toPath = to.path ; if (toPath.includes ('/question' ) || toPath.includes ('/home/greenPlantsPage' )) { next ('/login?redirect=' + toPath) } else { next (); } } })
完美无错的写法应该看 garbage 写的,要结合 vuex。
Login.vue
要保存各个数据
TopBanner.vue
退出登录后要清除的数据
vuex 下的 user
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { getToken, getRouterList } from '../../utils/token' const state = { token : getToken (), routerList : JSON .parse (getRouterList ()) } const mutations = {} const actions = {}const getters = {}export default { state, mutations, actions, getters }
utils 下的 token 工具包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 export const setToken = (token ) => { sessionStorage.setItem ("token" , token); }; export const getToken = ( ) => { return sessionStorage.getItem ("token" ); }; export const removeToken = ( ) => { sessionStorage.removeItem ("token" ); } export const setRouterList = (routerList ) => { sessionStorage.setItem ('routerList' , routerList); } export const getRouterList = ( ) => { return sessionStorage.getItem ('routerList' ); } export const removeRouterList = ( ) => sessionStorage.removeItem ('routerList' );
最后要写的路由守卫
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 router.beforeEach (async (to, from , next) => { console .log ('store' , store.state .user .routerList ); if (store.state .user .routerList ) { let routerList = store.state .user .routerList ; routerList = routerList.filter (item => { return item.state === 0 ; }) router = routerList.map (item => { return item.router ; }) } let token = store.state .user .token ; console .log ('token' , token); if (token) { console .log ('toPath' , to.path ); if (router.includes (to.path )) { Message ({ message : "您没有访问的权限" , type : 'waring' }) next ('/' ) } else { next (); } } else { let toPath = to.path ; if (toPath.includes ('/question' ) || toPath.includes ('/home/greenPlantsPage' )) { next ('/login?redirect=' + toPath) } else { next (); } } })
14. vue 路由守卫及elementUI 的Message在路由守卫里的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import { Message } from 'element-ui' router.beforeEach (async (to, from , next) => { console .log ('store' , store.state .user .routerList ); if (store.state .user .routerList ) { let routerList = store.state .user .routerList ; routerList = routerList.filter (item => { return item.state === 0 ; }) router = routerList.map (item => { return item.router ; }) } let token = store.state .user .token ; console .log ('token' , token); if (token) { console .log ('toPath' , to.path ); if (router.includes (to.path )) { Message ({ message : "您没有访问的权限" , type : 'waring' }) next ('/' ) } else { next (); } } else { let toPath = to.path ; if (toPath.includes ('/question' ) || toPath.includes ('/home/greenPlantsPage' )) { next ('/login?redirect=' + toPath) } else { next (); } } })