1.常用数组方法
.filter()
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
是否改变原数组:否
是否对空数组进行检测:否
语法:
const arr= [32, 33, 16, 40];
const arr1 = arr.filter(item => item >= 18)
console.log(arr) // [32, 33, 16, 40]
console.log(arr1) // [32, 33, 40]
.map()
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
map() 方法按照原始数组元素顺序依次处理元素。
是否改变原数组:否
是否对空数组进行检测:否
语法:
const arr= [4, 9, 16, 25];
const arr1 = arr.map(item => item+2)
console.log(arr) // [4, 9, 16, 25]
console.log(arr1) // [6, 11, 18, 27]
.forEach()
forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。
注意: forEach() 对于空数组是不会执行回调函数的。
tips: forEach()中不支持使用break(报错)和return(不能结束循环),有需要时可使用常规的for循环。
语法:
const arr= [4, 9, 16, 25];
const arr1 = [];
arr.forEach(item => arr1.push(item))
console.log(arr) // [4, 9, 16, 25]
console.log(arr1) // [4, 9, 16, 25]
.find()
find() 方法返回通过测试(函数内判断)的数组的第一个元素的值。
find() 方法为数组中的每个元素都调用一次函数执行:
当数组中的元素在测试条件时返回 true 时, find() 返回符合条件的元素,之后的值不会再调用执行函数。
如果没有符合条件的元素返回 undefined
注意: find() 对于空数组,函数是不会执行的。
注意: find() 并没有改变数组的原始值。
语法:
const arr= [4, 9, 16, 25];
const b = arr.find(item => item>10)
const c = arr.find(item => item<1)
console.log(arr) // [4, 9, 16, 25]
console.log(b) // 16
console.log(c) // undefined
.findIndex()
findIndex() 方法返回传入一个测试条件(函数)符合条件的数组第一个元素位置。
findIndex() 方法为数组中的每个元素都调用一次函数执行:
当数组中的元素在测试条件时返回 true 时, findIndex() 返回符合条件的元素的索引位置,之后的值不会再调用执行函数。
如果没有符合条件的元素返回 -1
注意: findIndex() 对于空数组,函数是不会执行的。
注意: findIndex() 并没有改变数组的原始值。
语法:
const arr= [4, 9, 16, 25];
const b = arr.findIndex(item => item>10)
const c = arr.findIndex(item => item<1)
console.log(arr) // [4, 9, 16, 25]
console.log(b) // 2
console.log(c) // -1
.some()
some() 方法用于检测数组中的元素是否满足指定条件(函数提供)。
some() 方法会依次执行数组的每个元素:
如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。
如果没有满足条件的元素,则返回false。
注意: some() 不会对空数组进行检测。
注意: some() 不会改变原始数组。
语法:
const arr= [4, 9, 16, 25];
const b = arr.some(item => item>10)
const c = arr.some(item => item<1)
console.log(arr) // [4, 9, 16, 25]
console.log(b) // true
console.log(c) // false
.every()
every() 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)。
every() 方法使用指定函数检测数组中的所有元素:
如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测。
如果所有元素都满足条件,则返回 true。
注意: every() 不会对空数组进行检测。
注意: every() 不会改变原始数组。
语法:
const arr= [4, 9, 16, 25];
const b = arr.every(item => item>10)
const c = arr.every(item => item>1)
console.log(arr) // [4, 9, 16, 25]
console.log(b) // false
console.log(c) // true
2.父子组件传值
父组件:
<span @click="handleRun()">调用子组件</span>
<operatingCity v-if="showCity" :showCity="showCity" @setCityValue="getCityValue"/>
data() {
return {
showCity: false,
};
},
handleRun(){
this.showCity = true;
},
getCityValue(val){
this.showCity = val;
}
子组件:
<template>
<div>
<el-dialog title="提示" :visible.sync="dialogCity" width="30%">
<div>
<span>子组件内容</span>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="handleSubmit">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
props: {
showCity: {
type: Boolean,
default: false,
},
},
data() {
return {
dialogCity: false,
param: {},
};
},
created() {},
mounted() {
this.dialogCity = this.showCity;
},
methods: {
handleSubmit() {
this.dialogCity = false;
this.$emit("setCityValue", false);
},
handleClose() {
this.dialogCity = false;
this.$emit("setCityValue", false);
},
},
};
</script>
3.Computed的使用
<template>
<div class="hello">
<!-- 写法1 -->
<div>
<label v-if="count < 0">111</label>
<label v-else-if="count === 0">222</label>
<label v-else-if="count <= 3">333</label>
<label v-else-if="count < 15">444</label>
<label v-else>555</label>
</div>
<!-- 写法2 -->
<div>
<label>{{countMsg}}</label>
</div>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
count: -21,
};
},
methods: {},
computed: {
// 写法2
countMsg() {
if (this.count < 0) {
return "111";
} else if (this.count === 0) {
return "222";
} else if (this.count <= 3) {
return "333";
} else if (this.count < 15) {
return "444";
} else {
return "555";
}
},
},
};
</script>
<view class="expired" v-if="isExpired(item)">已过期</view>
computed: {
// 计算过期的状态
isExpired() {
return function(item) {
return new Date(item.expireTime) <= new Date();
}
}
// 使用ES6的解构赋值,优化代码
// isExpired: () => ({ expireTime }) => new Date(expireTime) < new Date()
},
优化前:
<el-table-column prop="productStatus" label="状态" min-width="120">
<template slot-scope="scope">
<span v-if="scope.row.productStatus === 'on_shelves' && scope.row.isSell == 0">停售</span>
<span v-else-if="scope.row.productStatus === 'on_shelves' && scope.row.isSell == 1">在售</span>
<span v-else-if="scope.row.productStatus === 'for_sale'">待发售</span>
<span v-else-if="scope.row.productStatus === 'off_shelves'">已下架</span>
</template>
</el-table-column>
优化后:
<el-table-column prop="productStatus" label="状态" min-width="120">
<template slot-scope="scope">
<span>{{ getStatusMsg(scope.row) }}</span>
</template>
</el-table-column>
methods: {
getStatusMsg(row) {
if (row.productStatus === 'on_shelves' && row.isSell == 0) {
return '停售';
} else if (row.productStatus === 'on_shelves' && row.isSell == 1) {
return '在售';
} else if (row.productStatus === 'for_sale') {
return '待发售';
} else if (row.productStatus === 'off_shelves') {
return '已下架';
}
return '';
},
}
4.Watch的使用
//1.监听简单数据类型
<template>
<div>
<el-input v-model="mergeText"></el-input>
</div>
</template>
<script>
export default {
data() {
return {
mergeText:'',
};
},
watch:{
// mergeText值变化即触发
mergeText(newval,oldVal){
console.log(this.mergeText,newval,oldVal);
}
},
};
</script>
//2.监听复杂数据(深度监听 deep)
<template>
<div>
<el-input v-model="obj.text"></el-input>
</div>
</template>
<script>
export default {
data() {
return {
obj:{
text:'hello'
}
};
},
watch:{
// 监听对象obj的变化
obj:{
handler (newVal,oldval) {
console.log(newVal,oldval)
},
deep: true,
immediate: true
}
},
};
</script>
5.NextTick的使用
<template>
<div class="box">{{msg}}</div>
</template>
<script>
export default {
name: "index",
data() {
return {
msg: "hello",
};
},
mounted() {
// console.log(box.innerHTML) // hello
// 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
this.$nextTick(() => {
console.log(box.innerHTML); // world
});
this.msg = "world";
let box = document.getElementsByClassName("box")[0];
},
};
</script>
6.Vue中实现函数的防抖和节流
// 防抖
function _debounce(fn, delay = 500) {
var timer = null;
return function () {
var _this = this;
var args = arguments;
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(_this, args);
}, delay);
};
}
// 节流
function _throttle(fn,delay = 1000){
var lastTime, timer, delay;
return function(){
var _this = this;
var args = arguments;
var nowTime = Date.now();
if(lastTime && nowTime - lastTime < delay){
if (timer) clearTimeout(timer);
timer = setTimeout(function(){
lastTime = nowTime;
fn.apply(_this,args);
},delay)
}else{
lastTime = nowTime;
fn.apply(_this,args);
}
}
}
export {
_debounce,
_throttle,
}
<template>
<div class="about">
<el-input v-model="inputVal" placeholder="请输入内容" @input="inputChange"></el-input>
</div>
</template>
<script>
import {_debounce, _throttle} from '@/utils/index.js'
export default {
data() {
return {
inputVal:'',
count:0,
};
},
methods: {
// input值改变时触发
inputChange:_debounce(function(){
console.log(this.inputVal)
},1000),
// 滚动条滚动时触发
scroll(){
this.count += 1;
console.log('scroll触发了'+ this.count +'次')
}
},
mounted() {
window.addEventListener('scroll', _throttle(this.scroll,5000));
},
};
</script>
<style lang="stylus" scoped>
.about{
width:100%;
height:800px;
}
</style>
7.Vue中获取当前时间并实时刷新
<template>
<div>
{{nowDate}}{{nowWeek}}{{nowTime}}
</div>
</template>
<script>
export default {
data() {
return {
nowDate: "", // 当前日期
nowTime: "", // 当前时间
nowWeek: "", // 当前星期
};
},
methods: {
dealWithTime(data) {
// 获取当前时间
let Y = data.getFullYear();
let M = data.getMonth() + 1;
let D = data.getDate();
let H = data.getHours();
let Min = data.getMinutes();
let S = data.getSeconds();
let W = data.getDay();
H = H < 10 ? "0" + H : H;
Min = Min < 10 ? "0" + Min : Min;
S = S < 10 ? "0" + S : S;
switch (W) {
case 0:
W = "日";
break;
case 1:
W = "一";
break;
case 2:
W = "二";
break;
case 3:
W = "三";
break;
case 4:
W = "四";
break;
case 5:
W = "五";
break;
case 6:
W = "六";
break;
default:
break;
}
this.nowDate = Y + "年" + M + "月" + D + "日 ";
this.nowWeek = "周" + W;
this.nowTime = H + ":" + Min + ":" + S;
},
},
mounted() {
// 页面加载完后显示当前时间
this.dealWithTime(new Date());
// 定时刷新时间
this.timer = setInterval(() => {
this.dealWithTime(new Date()); // 修改数据date
}, 500);
},
destroyed() {
if (this.timer) {
// 注意在vue实例销毁前,清除我们的定时器
clearInterval(this.timer);
}
},
};
</script>
8.Vue中iframe的内容加载慢,实现加载(Loading)效果
<template>
<div style="height:1000px;" v-loading="loading">
<iframe ref="Iframe" src="https://www.taobao.com/" width="100%" height="100%" frameborder="0">
</iframe>
</div>
</template>
<script>
export default {
data() {
return {
loading: false,
};
},
methods: {
iframeLoad() {
this.loading = true;
const iframe = this.$refs.Iframe;
if (iframe.attachEvent) {
// IE
iframe.attachEvent("onload", () => {
this.loading = false;
});
} else {
// 非IE
iframe.onload = () => {
this.loading = false;
};
}
},
},
mounted() {
this.iframeLoad();
},
};
</script>
9.Vue中动态添加class
//添加单个
:class="name1 == '名称1' ? 'class1' : 'class2'"
//添加多个
:class="[name1 == '名称1' ? 'class1' : 'class2', name2 == '名称2' ? 'new1' : 'new2']"
10.Vue中时间格式转化
/*
1.转换带T的时间格式
举例:formDateT('2019-01-01T08:01:01')
结果:2019-01-01 08:01:01
*/
export const formDateT = (data) => {
if (!data) return;
let dates = new Date(data).toJSON();
return new Date(+new Date(dates) + 8 * 3600 * 1000)
.toISOString()
.replace(/T/g, " ")
.replace(/.[\d]{3}Z/, "");
};
/*
2.计算两个时间相差的天、小时、分、秒
举例:timediff("2022-01-06 05:18:34", "2022-01-06 07:10:34")
结果:0天1小时52分0秒
*/
export const timediff = (startDate, endDate) => {
if (!startDate || !endDate) return;
//时间差的毫秒数
let date3 = new Date(endDate).getTime() - new Date(startDate).getTime();
//计算出相差天数
let days = Math.floor(date3 / (24 * 3600 * 1000));
//计算出小时数
let leave1 = date3 % (24 * 3600 * 1000); //计算天数后剩余的毫秒数
let hours = Math.floor(leave1 / (3600 * 1000));
//计算相差分钟数
let leave2 = leave1 % (3600 * 1000); //计算小时数后剩余的毫秒数
let minutes = Math.floor(leave2 / (60 * 1000));
//计算相差秒数
let leave3 = leave2 % (60 * 1000); //计算分钟数后剩余的毫秒数
let seconds = Math.round(leave3 / 1000);
return days + "天" + hours + "小时" + minutes + "分" + seconds + "秒";
};
/*
3.时间戳转换成,yyyy-mm-dd hh:ii:ss格式
举例:formatDate(1641417514502)
结果:2022-01-06 05:18:34
*/
export const formatDate = (date) => {
if (!date) return;
let time = new Date(date);
return (
time.getFullYear() +
"-" +
(time.getMonth() + 1).toString().padStart(2, "0") +
"-" +
time.getDate().toString().padStart(2, "0") +
"\xa0" +
time.getHours().toString().padStart(2, "0") +
":" +
time.getMinutes().toString().padStart(2, "0") +
":" +
time.getSeconds().toString().padStart(2, "0")
);
};
11.Element-ui中表格(Table)** 实现跨页多选数据——功能实现**
解决方案
1.在table一定要定义以下事件和列表属性:
row-key //写在table标签上
reserve-selection // 写在有选择框的那一列上
<el-table @selection-change="handleSelectionChange" :row-key="getRowKeys">
......
</el-table> //写在table标签上
<el-table-column type="selection" :reserve-selection="true" width="40" align="center">
</el-table-column> // 写在有选择框的那一列上 type 必须为 selection
2、在data上定义row-key绑定的
getRowKeys(row) {
return row.id;
},
3、把勾选的数据传到后台所以在methods定义
handleSelectionChange(val) {
this.multipleSelection = val;//勾选放在multipleSelection数组中
},
注:此时问题已解决,但是怎样进行清空已经选择的数据呢,代码如下。
使用后怎样清空数据
1、在表格上操作dom元素,设置ref属性
<el-table @selection-change="handleSelectionChange" ref="multiTable" :row-key="getRowKeys">
......
</el-table>
2、清空数据
在你点完确定后,调用此方法。比如是弹框,有个确定按钮,绑定的click事件为confirm,在methods里写confirm方法。
confirm(){
this.dialogvisible=false //关闭弹框
this.$refs.multiTable.clearSelection() //清除选中的数据
}
注:也可以在弹框刚打开的时候进行清空,在这里加个判断,判断是否有选中的数据,如果有执行this.$refs.multiTable.clearSelection() ,如果没有就不用清空。
12.Element-ui中表格(Table)实现表头、表格内容,任意格都可编辑实现
<template>
<div class="app-container">
<el-table :data="tableData" @cell-click="handleCellClick" @header-click="handleHeaderClick" :cell-class-name="cellClassName" style="width: 90%;align: center;cursor: pointer;" :header-cell-style="{ height: '50px' }" :row-style="{ height: '50px' }">
<el-table-column :label="item.propName" :property="item.prop" v-for="item in tableColumnList" :key="item.prop" align="center">
<template slot-scope="scope">
<span>{{scope.row[scope.column.property]}}</span>
</template>
</el-table-column>
<el-table-column label="添加项目流程" width="120" prop="addTableHeaderName" align="center" />
</el-table>
<el-dialog :visible.sync="dialogForHeader" title="修改项目流程名称" width="800">
<el-form ref="form" :model="tableHeader" label-width="80px">
<el-form-item label="表头名称">
<el-input v-model="tableHeader.tableHeaderName" placeholder="请输入表头名称" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleHeaderSubmit">确 定</el-button>
<el-button @click="handleHeaderCancel">取 消</el-button>
</div>
</el-dialog>
<el-dialog :visible.sync="dialogForTable" title="修改项目流程内容" width="800">
<el-form ref="form" :model="tableCell" label-width="120px">
<el-form-item label="流程内容名称">
<el-input v-model="tableCell.tableCellData" placeholder="流程内容名称" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleCellSubmit">确 定</el-button>
<el-button @click="handleCellCancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
tableCellIndex: 0,
TableColumnIndex: 0,
tableCell: { tableCellData: "" },
dialogForTable: false,
num: 6,
tableHeader: { tableHeaderName: "", property: "" },
dialogForHeader: false,
// 扩展:将tableColumnList和tableData当作字符串传给后端
// 1.数组转化成字符串:JSON.stringify(tableData)
// 2.字符串转化成数组:JSON.parse(tableData);
tableColumnList: [
{ prop: "0", propName: "编号" },
{ prop: "1", propName: "名字" },
{ prop: "2", propName: "保质期" },
{ prop: "3", propName: "特点1" },
{ prop: "4", propName: "特点2" },
{ prop: "5", propName: "特点3" },
],
tableData: [
{
0: "2016-05-01",
1: "王小虎1",
2: "上海市普陀区金沙江路 1518 弄",
3: "2016-05-02",
4: "王小虎",
5: "上海市普陀区金沙江路 1518 弄",
},
{
0: "2016-05-02",
1: "王小虎2",
2: "上海市普陀区金沙江路 1518 弄",
3: "2016-05-02",
4: "王小虎",
5: "上海市普陀区金沙江路 1518 弄",
},
{
0: "2016-05-03",
1: "王小虎3",
2: "上海市普陀区金沙江路 1518 弄",
3: "2016-05-02",
4: "王小虎",
5: "上海市普陀区金沙江路 1518 弄",
},
{
0: "2016-05-04",
1: "王小虎4",
2: "上海市普陀区金沙江路 1518 弄",
3: "2016-05-02",
4: "王小虎",
5: "上海市普陀区金沙江路 1518 弄",
},
{
0: "2016-05-05",
1: "王小虎5",
2: "上海市普陀区金沙江路 1518 弄",
3: "2016-05-06",
4: "王小虎",
5: "上海市普陀区金沙江路 1518 弄",
},
{
0: "2016-05-07",
1: "王小虎6",
2: "上海市普陀区金沙江路 1518 弄",
3: "2016-05-02",
4: "王小虎",
5: "上海市普陀区金沙江路 1518 弄",
},
],
};
},
methods: {
// 给每一行数据添加index,用来定位修改单元格
cellClassName({ row, column, rowIndex, columnIndex }) {
row.index = rowIndex;
column.index = columnIndex;
},
// 修改表头
handleHeaderClick(val) {
if (val.property == "addTableHeaderName") {
this.tableColumnList.push({
prop: this.num.toString(),
propName: "点击编辑项目流程名称",
});
for (let i = 0; i < this.tableData.length; i++) {
this.$set(this.tableData[i], [parseInt(this.num)], "请添加内容");
}
this.num = this.num + 1;
} else {
this.tableHeader.tableHeaderName = val.label;
this.tableHeader.property = val.property;
this.dialogForHeader = true;
}
},
// 修改单元格
handleCellClick(row, column) {
this.tableCellIndex = row.index;
this.TableColumnIndex = column.index;
this.tableCell.tableCellData = row[this.TableColumnIndex];
this.dialogForTable = true;
},
handleHeaderSubmit() {
this.tableColumnList.map((item, index) => {
if (item.prop === this.tableHeader.property) {
item.propName = this.tableHeader.tableHeaderName;
}
});
this.dialogForHeader = false;
},
handleCellSubmit() {
this.tableData[Number(this.tableCellIndex)][
Number(this.TableColumnIndex)
] = this.tableCell.tableCellData;
this.rush();
this.dialogForTable = false;
},
//强制刷新数据
rush() {
this.$set(this.tableData);
},
handleHeaderCancel() {
this.dialogForHeader = false;
},
handleCellCancel() {
this.dialogForTable = false;
},
},
};
</script>
13.Element-ui中表格(Table)单元格内添加换行转义符
<template>
<div class="home">
<el-table :data="tableData" border style="width: 80%">
<el-table-column align="center" prop="number" label="编号" width="180"></el-table-column>
<el-table-column align="center" prop="name" label="姓名" width="180"></el-table-column>
<el-table-column align="center" prop="address" label="地址"></el-table-column>
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [
{
number: "20160503",
name: "王小虎",
address: "2016-05-03" + "\n" + "武汉市江夏区文化大道",
},
{
number: "20160504",
name: "张小虎",
address: "2019-05-04" + "\n" + "武汉市洪山区洪山侧路",
},
{
number: "20160501",
name: "李小虎",
address: "2020-05-01" + "\n" + "南京市建邺区白龙江东街",
},
{
number: "20160502",
name: "宋小虎",
address: "2021-05-02" + "\n" + "南京市江宁区水阁路",
},
],
};
},
};
</script>
<style lang="scss" scoped>
.home {
::v-deep .el-table {
.cell {
white-space: pre-line;
}
}
}
</style>
14.Element-ui中表格(Table)组件中滚动条样式修改
//1.修改单个滚动条样式
<style lang="scss" scoped>
.el-table {
/deep/ .el-table__body-wrapper::-webkit-scrollbar {
width: 10px; /*滚动条宽度*/
height: 10px; /*滚动条高度*/
}
/*定义滚动条轨道 内阴影+圆角*/
/deep/ .el-table__body-wrapper::-webkit-scrollbar-track {
box-shadow: 0px 1px 3px #071e4a inset; /*滚动条的背景区域的内阴影*/
border-radius: 10px; /*滚动条的背景区域的圆角*/
background-color: #071e4a; /*滚动条的背景颜色*/
}
/*定义滑块 内阴影+圆角*/
/deep/ .el-table__body-wrapper::-webkit-scrollbar-thumb {
box-shadow: 0px 1px 3px #00a0e9 inset; /*滚动条的内阴影*/
border-radius: 10px; /*滚动条的圆角*/
background-color: #00a0e9; /*滚动条的背景颜色*/
}
}
</style>
//2.修改全局滚动条样式(推荐)
<style lang="scss">
::-webkit-scrollbar {
width: 6px;
height: 8px;
background-color: #ebeef5;
}
::-webkit-scrollbar-thumb {
box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
background-color: #ccc;
}
::-webkit-scrollbar-track{
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
border-radius: 3px;
background: rgba(255, 255, 255, 1);
}
</style>
15.Element-ui中表格 (Table) 组件中动态合并单元格
<template>
<div class>
<el-table
:data="listData"
:span-method="objectSpanMethod"
border
class="tableArea"
style="width: 40%;"
>
<el-table-column label="商品类别" prop="productType" align="center" width="200"></el-table-column>
<el-table-column label="商品数量" prop="amount" align="center"></el-table-column>
<el-table-column label="商品价格" prop="price" align="center"></el-table-column>
<el-table-column label="商品名称" prop="productName" width="200px" align="center"></el-table-column>
<el-table-column label="更新时间" prop="updateTime" align="center"></el-table-column>
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
listData: [],
testArr1: [],
testArr2: [],
testPosition1: 0,
testPosition2: 0,
};
},
methods: {
// 获取数据
queryData() {
this.listData = [
{
id: "201808300001",
productType: "纺织品",
amount: 20,
productName: "上衣",
price: "80",
updateTime: "2018-08-30",
},
{
id: "201808300002",
productType: "纺织品",
amount: 20,
productName: "裤子",
price: "76",
updateTime: "2018-08-31",
},
{
id: "201808300003",
productType: "皮制品",
amount: 100,
productName: "挎包",
price: "150",
updateTime: "2018-08-31",
},
{
id: "201808300004",
productType: "皮制品",
amount: 180,
productName: "鞋子",
price: "76",
updateTime: "2018-08-29",
},
{
id: "201808300005",
productType: "绸缎",
amount: 80,
productName: "旗袍",
price: "106",
updateTime: "2018-08-31",
},
{
id: "201808300006",
productType: "纺织品",
amount: 20,
productName: "短裙",
price: "36",
updateTime: "2018-08-30",
},
{
id: "201808300007",
productType: "纺织品",
amount: 80,
productName: "短袖",
price: "36",
updateTime: "2018-08-30",
},
{
id: "201808300008",
productType: "纺织品",
amount: 20,
productName: "短袖",
price: "36",
updateTime: "2018-08-30",
},
{
id: "201808300009",
productType: "皮制品",
amount: 20,
productName: "钱包",
price: "60",
updateTime: "2018-08-30",
},
{
id: "201808300011",
productType: "纺织品",
amount: 90,
productName: "手套",
price: "60",
updateTime: "2018-08-30",
},
{
id: "201808300012",
productType: "纺织品",
amount: 90,
productName: "袜子",
price: "36",
updateTime: "2018-08-30",
},
{
id: "201808300013",
productType: "饮料",
amount: 100,
productName: "雪碧",
price: "5",
updateTime: "2018-08-31",
},
{
id: "201808300013",
productType: "纺织品",
amount: 100,
productName: "风衣",
price: "50",
updateTime: "2018-08-31",
},
];
this.rowspan(this.testArr1, this.testPosition1, "productType");
this.rowspan(this.testArr2, this.testPosition2, "amount");
},
rowspan(spanArr, position, spanName) {
this.listData.forEach((item, index) => {
if (index === 0) {
spanArr.push(1);
position = 0;
} else {
if (
this.listData[index][spanName] ===
this.listData[index - 1][spanName]
) {
spanArr[position] += 1;
spanArr.push(0);
} else {
spanArr.push(1);
position = index;
}
}
});
},
// 表格合并行
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (columnIndex === 0) {
const _row = this.testArr1[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col,
};
}
if (columnIndex === 1) {
const _row = this.testArr2[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col,
};
}
},
},
mounted() {
this.queryData();
},
};
</script>
16.Element-ui中选择器(Select)解决数据量大导致渲染慢、页面卡顿的问题
// utils.js
function _debounce(fn, delay = 300) {
var timer = null;
return function () {
var _this = this;
var args = arguments;
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(_this, args);
}, delay);
};
}
export {
_debounce
}
<template>
<div class="content">
<el-select
v-model="chooseValue" clearable filterable :filter-method="filterMethod"
v-el-select-loadmore="loadMore(rangeNumber)"
@visible-change="visibleChange">
<el-option
v-for="(item, index) in options.slice(0, rangeNumber)"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
</template>
<script>
import {_debounce} from '@/utils/index.js'
export default {
data() {
return {
chooseValue: "",
options: [],
rangeNumber: 10,
resOptions:[],
};
},
methods: {
// 模拟获取大量数据
getList() {
// 测试数据15000条数据, 这里数据多少条无所谓,options.slice(0, rangeNumber)方法只会默认加载初始的10条数据
for (let i = 0; i < 25000; i++) {
this.resOptions.push({label: "选择"+i,value:"选择"+i});
}
},
loadMore(n) {
// n是默认初始展示的条数会在渲染的时候就可以获取,具体可以打log查看
// elementui下拉超过7条才会出滚动条,如果初始不出滚动条无法触发loadMore方法
return () => (this.rangeNumber += 5); // 每次滚动到底部可以新增条数 可自定义
},
// 筛选方法
filterMethod:_debounce(function(filterVal){
if(filterVal){
let filterArr = this.resOptions.filter((item)=>{
return item.label.toLowerCase().includes(filterVal.toLowerCase())
})
this.options = filterArr;
}else{
this.options = this.resOptions;
}
},500),
// 下拉框出现时,调用过滤方法
visibleChange(flag){
if(flag){
this.filterMethod()
}
},
},
beforeMount() {
this.getList();
},
directives:{
'el-select-loadmore':(el, binding) => {
// 获取element-ui定义好的scroll盒子
const SELECTWRAP_DOM = el.querySelector(".el-select-dropdown .el-select-dropdown__wrap");
if(SELECTWRAP_DOM){
SELECTWRAP_DOM.addEventListener("scroll", function () {
/**
* scrollHeight 获取元素内容高度(只读)
* scrollTop 获取或者设置元素的偏移值,
* 常用于:计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
* clientHeight 读取元素的可见高度(只读)
* 如果元素滚动到底, 下面等式返回true, 没有则返回false:
* ele.scrollHeight - ele.scrollTop === ele.clientHeight;
*/
const condition = this.scrollHeight - this.scrollTop <= this.clientHeight;
if (condition) binding.value();
});
}
},
}
};
</script>
17.Element-ui中树形控件(Tree)实现只显示某一层级复选框且单选
<template>
<div class="wrap">
<el-tree :data="treeData" ref="tree" show-checkbox :check-strictly="true" node-key="id" :props="defaultProps" @check-change="treeCheckedChange">
</el-tree>
</div>
</template>
<script>
export default {
data() {
return {
defaultProps: {
children: "children",
label: "label",
},
treeData: [],
testdata: [
{
id: 1,
label: "一级 1",
children: [
{
id: 3,
label: "二级 1-1",
children: [
{
id: 7,
label: "二级 1-1-1",
},
],
},
],
},
{
id: 2,
label: "一级 2",
children: [
{
id: 4,
label: "二级 2-1",
children: [
{
id: 5,
label: "三级 2-1-1",
},
{
id: 6,
label: "三级 2-1-2",
},
],
},
],
},
],
};
},
methods: {
formatData(params) {
let data = params;
data.map((item) => {
if (item.hasOwnProperty("children")) {
item.disabled = true;
this.formatData(item.children);
}
});
return data;
},
treeCheckedChange(data, isChecked) {
if (isChecked) {
const checked = [data.id]; // id为tree的node-key属性
this.$refs.tree.setCheckedKeys(checked);
}
},
},
mounted() {
this.treeData = this.formatData(this.testdata);
},
};
</script>
<style lang="scss" scoped>
.wrap {
/deep/.el-checkbox__input.is-disabled {
display: none;
}
}
</style>
18.Element-ui中树形控件(Tree) 搜索目标子节点展示
<template>
<div>
<el-input
placeholder="输入关键字进行过滤"
v-model="filterText">
</el-input>
<div style="display: flex;justify-content: space-around">
<div>
<p style="color: red">修改后的查询</p>
<el-tree :data="data1"
default-expand-all
ref="tree">
</el-tree>
</div>
<div>
<p style="color: red">element-ui 提供的查询</p>
<el-tree :data="data1"
default-expand-all
:filter-node-method="filterNode"
ref="tree1">
</el-tree>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
filterText: '',
data1: [{
id: 100,
label: '1263',
children: [
{
id: 100,
label: '852',
}, {
id: 111,
label: '369',
}, {
id: 852,
label: 'ki',
children: [
{
id: 96,
label: 'pp',
}
]
},
]
}, {
id: 1,
label: '一级 1',
children: [{
id: 4,
label: 'gf',
children: [{
id: 23,
label: 'lk',
children: [
{
id: 9,
label: 'abnc'
}, {
id: 11,
label: 'abnc43'
}, {
id: 10,
label: '三级 1-1-2'
}
]
}]
}]
}, {
id: 2,
label: '一级 2',
children: [{
id: 5,
label: '二级 2-1',
}, {
id: 6,
label: '二级 2-2',
}]
}, {
id: 3,
label: '一级 3',
children: [{
id: 56,
label: 'test',
children: [
{
id: 7,
label: '二级 3-1'
}, {
id: 8,
label: '二级 3-2'
}
]
}]
}],
}
},
watch: {
filterText(val) {
this.filter(val)
this.$refs.tree1.filter(val);
}
},
methods: {
/**
* 遍历节点
**/
filterNode(value, data, node) {
if (data.label.indexOf(value) !== -1) {
return true
}
},
/**
* 递归遍历设置那些节点展示,那些节点不展示
**/
filter(value) {
const traverse = (node) => {
const childNodes = node.root ? node.root.childNodes : node.childNodes;
childNodes.forEach((child) => {
child.visible = this.filterNode(value, child.data, child);
traverse(child);
});
// node.visible为真,子节点也为真,就进行递归遍历设置子节点内容为展示状态
if (node.visible && node.childNodes.length) {
this.findChildNodes(node.childNodes);
}
if (!node.visible && childNodes.length) {
let allHidden = true;
allHidden = !childNodes.some(child => child.visible);
if (node.root) {
node.root.visible = allHidden === false;
} else {
node.visible = allHidden === false;
}
}
if (!value) return;
if (node.visible && !node.isLeaf) node.expand();
};
traverse(this.$refs.tree.store);
},
/**
* 递归循环子节点
* 设置过滤目标节点下面的子节点为展示状态
**/
findChildNodes(data){
for (let item of data) {
item.visible = true;
if (item.childNodes.length) {
return this.findChildNodes(item.childNodes);
}
}
}
},
}
</script>
19.Element-ui中级联选择器 (Cascader)组装数据
<template>
<div>
<span>单选选择任意一级选项</span>
<el-cascader v-model="areaId" :options="options" :props="areaProps" clearable></el-cascader>
<span>{{areaId}}</span>
</div>
</template>
<script>
export default {
data() {
return {
areaId: "yizhi",
areaProps: {
label: "areaName",
value: "areaId",
children: "child",
checkStrictly: true,
emitPath: false,
},
options: [
{
areaId: "zhinan",
areaName: "指南",
child: [
{
areaId: "shejiyuanze",
areaName: "设计原则",
child: [
{
areaId: "yizhi",
areaName: "一致",
},
{
areaId: "fankui",
areaName: "反馈",
},
{
areaId: "xiaolv",
areaName: "效率",
},
{
areaId: "kekong",
areaName: "可控",
},
],
},
{
areaId: "daohang",
areaName: "导航",
child: [
{
areaId: "cexiangdaohang",
areaName: "侧向导航",
},
{
areaId: "dingbudaohang",
areaName: "顶部导航",
},
],
},
],
},
],
};
},
};
</script>
20.Element-ui中表格(Table) 多选改为单选功能
<template>
<el-table :data="tableData" :row-key="row => row.id" :highlight-current-row="highlightCurrentRow" @row-click="handleRowClick">
<!-- 将 type 属性设为 'selection' 的列移除,并在第一列中使用自定义的 radio 组件来实现单选功能 -->
<el-table-column width="55" align="center">
<template slot-scope="scope">
<el-radio v-model="selectedRowId" :label="scope.row.id">
<span class="radio-no-label"></span>
</el-radio>
</template>
</el-table-column>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="age" label="年龄"></el-table-column>
<el-table-column prop="sex" label="性别"></el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
tableData: [
{ id: 1, name: "张三", age: 18, sex: "男" },
{ id: 2, name: "李四", age: 20, sex: "女" },
{ id: 3, name: "王五", age: 22, sex: "男" },
],
selectedRowId: null,
highlightCurrentRow: true,
};
},
methods: {
// 处理行点击事件,将点击的行数据更新为选中的行数据
handleRowClick(row) {
this.selectedRowId = row.id;
},
},
};
</script>
<style scoped>
.radio-no-label {
display: none;
}
</style>
21.vue实现日历备忘录
<template>
<div class="vue-calendar">
<div class="calendar-title">
<div>
<p>
<i class="icon-arrow-left-year calendar-icon" @click="lastYear"><<</i>
<i class="icon-arrow-left calendar-icon" @click="lastMonth"><</i>
</p>
<p>
<span>{{ year }} 年 </span>
<span> {{ month + 1 }} 月</span>
</p>
<p>
<i class="icon-arrow-right calendar-icon" @click="nextMonth">></i>
<i class="icon-arrow-right-year calendar-icon" @click="nextYear">>></i>
</p>
</div>
</div>
<table id="table">
<thead>
<tr>
<th v-for="item in weekArray" :key="item">{{ item }}</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in dateArr" :key="index">
<td v-for="(val, num) in item" :key="num" @click="handle(val)"
:class="{'today':setClassToday(val)}">
<span :class="`${val.class}`">{{ val.day }}</span>
<div v-for="(textItem, index) in infoArr" :key="index">
<template v-if="textItem.day === val.day && textItem.month === val.month && textItem.year === val.year">
<span v-show="textItem.count">({{ textItem.count }} 条)</span>
<div>
<p v-for="(value, num) in textItem.taskCalendarList" :key="num">
{{ value }}
</p>
</div>
</template>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
name: 'calendar',
data() {
return {
activeIndex: null,
dateArr: [],
weekArray: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
month: new Date().getMonth(),
year: new Date().getFullYear(),
day: new Date().getDate(),
currentDate: new Date(),
infoArr: [
{
year: new Date().getFullYear(),
month: new Date().getMonth() + 1,
day: 14,
count: 5,
taskCalendarList: ['07:00 嗷嗷嗷', '08:00 酷酷酷', '13:35 水水水水水', '18:20 斤斤计较', '20:00 噢噢噢噢']
}
]
}
},
mounted() {
this.createDate()
},
methods: {
/**
* 日期计算逻辑
**/
createDate() {
this.dateArr = [];
let arr = [];
let count = 0;
let date = new Date(this.year, this.month);
// setMonth(4) === 5月份,4 + 1 = 6月份
// setDate(0) 为 setMonth(4) 设置月份的上个月的最后一天
// 如:当前为5月份,setMonth(4 + 1)为6月份,setDate(0)设置的就是5月份的最后一天
date.setMonth(this.month + 1);
date.setDate(0);
let lastDay = date.getDate(); // 获取最后一天
// 按当前月份共有多少天循环创建数组
for (let i = 0; i < lastDay; i++) {
date.setDate(i + 1); // 设置date,用于获取星期
// 每7条数据生成一个数组
if (count < 6) {
count = date.getDay() === 0 ? 6 : date.getDay() - 1; // 一周中的某一天作为数组的下标,因为每月1号的周数不一样。0 是星期天
arr[count] = {day: i + 1, week: date.getDay(), month: this.month + 1, year: this.year};
}
if (arr.length === 7 || i === lastDay - 1) {
this.dateArr.push(arr); // 生成二维数组
count = 0; // 置0,从新开始
arr = [];
}
}
/**
* 表格第一行,计算上个月日期
**/
let firstWeek = null;
let firstArr = this.dateArr[0];
date.setDate(0);
// 计算第一行数组还需要循环几次填充满
for (let item of firstArr) {
if (item) {
firstWeek = item.week === 0 ? 6 : item.week - 1; // 计算还差几列没有数据
break;
}
}
let day = date.getDate();
// 循环填充满第一列数组
for (let i = firstWeek; i > 0; i--) {
date.setDate(day--);
firstArr[date.getDay() - 1] = {
day: date.getDate(),
week: date.getDay(),
month: this.month,
year: this.month === 0 ? this.year - 1 : this.year,
class: 'not-current-month',
};
}
/**
* 表格最后一行,计算下个月日期
**/
let lastDate = new Date(this.year, this.month + 1);
let lastWeek = null; // 获取最后一个周数
let lastArr = this.dateArr[this.dateArr.length - 1];
let lastDateArray = []; // 用于新增一行数组
// 计算最后一行数组还需要循环几次填充满
for (let i = 0; i < 7; i++) {
if (typeof lastArr[i] === "undefined") {
lastWeek = 7 - lastArr[i - 1].week; // 计算还差几列没有数据
break;
}
}
if (lastWeek > 0) {
// 循环填充满最后一行数组
for (let i = 0; i < lastWeek; i++) {
lastDate.setDate(i + 1);
lastArr[lastDate.getDay() === 0 ? 6 : lastDate.getDay() - 1] = {
day: lastDate.getDate(),
week: lastDate.getDay(),
month: this.month + 2,
year: this.month + 2 === 12 ? this.year + 1 : this.year,
class: 'not-current-month',
};
}
}
// dateArr新增一行数组
if (this.dateArr.length < 6) {
for (let i = 0; i < 7; i++) {
lastDate.setDate(lastWeek + i + 1);
lastDateArray.push({
day: lastDate.getDate(),
week: lastDate.getDay(),
class: 'not-current-month',
month: this.month + 2,
year: this.month + 2 === 12 ? this.year + 1 : this.year
});
}
}
if (lastDateArray.length > 0) {
this.dateArr.push(lastDateArray);
}
},
/**
* 当天日期设置高亮
**/
setClassToday(val) {
return val.month === (this.currentDate.getMonth() + 1) && val.day === this.day && val.year === this.currentDate.getFullYear();
},
/**
* 日期点击事件
**/
handle(val) {
this.activeIndex = val.day;
// 点击灰色的日期,跳转月份
if (val.class === 'not-current-month') {
if (val.month > this.month) {
this.nextMonth()
} else {
this.lastMonth()
}
}
},
/**
* 上个月
**/
lastMonth() {
this.month--;
if (this.month === -1) {
this.month = 11;
this.year--;
}
this.$nextTick(() => {
this.createDate()
})
},
/**
* 下个月
**/
nextMonth() {
this.month++;
if (this.month === 12) {
this.month = 0;
this.year++
}
this.$nextTick(() => {
this.createDate()
})
},
/**
* 下一年
**/
nextYear() {
this.year += 1;
this.$nextTick(() => {
this.createDate()
})
},
/**
* 上一年
**/
lastYear() {
this.year -= 1;
this.$nextTick(() => {
this.createDate()
})
}
}
}
</script>
<style lang="scss">
.vue-calendar {
height: 800px;
.calendar-icon {
cursor: pointer;
}
.icon-arrow-right-year {
margin-left: 20px;
}
.icon-arrow-left-year {
margin-right: 20px;
}
.calendar-title {
font-size: 20px;
text-align: center;
margin-bottom: 10px;
& > div {
padding: 10px;
display: flex;
align-items: center;
justify-content: space-between;
}
}
#table {
height: 100%;
width: 100%;
border-collapse: collapse;
thead {
text-align: center;
tr {
border: 1px #e2e2e2 solid;
height: 50px;
}
}
tbody {
text-align: center;
.today {
background: #fb0;
color: #ffffff;
}
td {
cursor: pointer;
width: 210px;
border: 1px #e2e2e2 solid;
padding: 0;
font-size: 20px;
position: relative;
&:not(.today):hover {
background: #e2e2e2;
}
& > span {
position: absolute;
top: 0;
left: 10px;
}
.not-current-month {
color: #c0c4cc;
}
div {
height: 75%;
position: absolute;
width: 100%;
bottom: 0;
span {
font-size: 20px;
position: absolute;
left: 30px;
top: -32px;
}
div {
position: relative;
/*left: 23px;*/
width: 100%;
height: 100%;
overflow: auto;
p {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-bottom: 10px;
font-size: 13px;
}
}
}
}
}
}
}
</style>
22.vue实现点击全屏效果,可具体让某个容器全屏
<template>
<div>
<el-button type="primary" @click="screen">全屏</el-button>
<div id="con_lf_top_div" style="background: #ffffff;">
<el-button type="primary">111</el-button>
<el-button type="primary">222</el-button>
</div>
</div>
</template>
<script>
export default {
name: "indexAss",
data() {
return {
fullscreen: false,
};
},
methods: {
screen() {
// let element = document.documentElement; //设置后就是我们平时的整个页面全屏效果
let element = document.getElementById("con_lf_top_div"); //设置后就是 id==con_lf_top_div 的容器全屏
if (this.fullscreen) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
} else {
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.msRequestFullscreen) {
// IE11
element.msRequestFullscreen();
}
}
this.fullscreen = !this.fullscreen;
},
},
};
</script>
23.vue中实现滚动时钟效果
<template>
<div class="wraper">
<div class="column" :style="{transform: `translateY(${-lineHeight*index6}px)`}">
<div class="num" v-for="(item, index) in arr6" :key="index">{{ item }}</div>
</div>
<div class="column" :style="{transform: `translateY(${-lineHeight*index5}px)`}">
<div class="num" v-for="(item, index) in arr5" :key="index">{{ item }}</div>
</div>
<div>:</div>
<div class="column" :style="{transform: `translateY(${-lineHeight*index4}px)`}">
<div class="num" v-for="(item, index) in arr4" :key="index">{{ item }}</div>
</div>
<div class="column" :style="{transform: `translateY(${-lineHeight*index3}px)`}">
<div class="num" v-for="(item, index) in arr3" :key="index">{{ item }}</div>
</div>
<div>:</div>
<div class="column" :style="{transform: `translateY(${-lineHeight*index2}px)`}">
<div class="num" v-for="(item, index) in arr2" :key="index">{{ item }}</div>
</div>
<div class="column" :style="{transform: `translateY(${-lineHeight*index1}px)`}">
<div class="num" v-for="(item, index) in arr1" :key="index">{{ item }}</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
lineHeight: 64, //跟字体大小和wraper的高度相关!
// 秒
arr1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
index1: 0, //就是获取真实时间后的起始数字
arr2: [0, 1, 2, 3, 4, 5],
index2: 0,
// 分
arr3: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
index3: 0,
arr4: [0, 1, 2, 3, 4, 5],
index4: 0,
// 时
arr5: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
index5: 0,
arr6: [0, 1, 2],
index6: 0,
}
},
created() {
this.getTime()
},
watch: {
index5(newVal) {
// 超过24小时
if (this.index6 === 2 && newVal===4) {
console.log('out')
for (let i=1; i<7; i++) {
this[`index${i}`] = 0
}
}
}
},
methods: {
getTime() {
const date = new Date()
let hour = this.bu0(date.getHours())
let minute = this.bu0(date.getMinutes())
let second = this.bu0(date.getSeconds())
// 测试用
// let hour = ['1', '9']
// let minute = ['5', '9']
// let second = ['5', '5']
// 秒
this.index1 = +second[1]
this.index2 = +second[0]
// 分
this.index3 = +minute[1]
this.index4 = +minute[0]
// 时
this.index5 = +hour[1]
this.index6 = +hour[0]
this.turnSecond(this.arr1.length)
},
bu0(num) {
let str
if (num < 10) str = `0${num}`
else str = `${num}`
return str.split('')
},
turnSecond (length) {
setInterval(()=> {
if (this.index1 === length-1) {
// console.log(1)
// 通知前一位移动
this.turnOther( 2, this.arr2.length)
this.index1 = -1
}
this.index1++
}, 1000)
},
turnOther(type, length) {
// type代表第几组数列,例如2,就是从右往左第二列
if (this[`index${type}`] === length-1) {
// console.log(type)
// 通知前一位移动
let next = type+1
this.turnOther( next, this[`arr${next}`].length)
this[`index${type}`] = -1
}
this[`index${type}`]++
}
}
}
</script>
<style scoped>
.wraper {
text-align: center;
background: #ffffff;
height: 64px;
font-size: 48px;
font-weight: bolder;
letter-spacing: 7px;
margin-top: 7px;
display: flex;
justify-content: center;
overflow:hidden;
}
.column {
transition: transform 300ms;
}
.num {
height: 64px;
}
</style>
24.vue表单校验
<template>
<el-form ref="submitForm" :model="form" :rules="rules">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="form.password"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="validateUser">校验-全部字段</el-button>
<el-button type="primary" @click="validateUsername">校验-用户名字段</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
form: {
username: "",
password: "",
},
rules: {
username: [
{ required: true, message: "请输入用户名", trigger: "blur" },
],
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
},
};
},
methods: {
validateUser() {
// 校验用户名和密码字段
this.$refs.submitForm.validate((valid) => {
if (valid) {
this.$message.success("校验密码登录成功");
}
});
},
validateUsername() {
// 校验用户名字段,不检验密码字段
this.$refs.submitForm.validateField("username", (valid) => {
if (!valid) {
this.$message.success("不校验密码登录");
}
});
},
},
};
</script>
25.vue弹框和分页查询(高频使用)
<template>
<div>
<el-button type="primary" @click="handleOpenDialog">弹框-表格</el-button>
<el-dialog title="提示" :visible.sync="dialogVisible" width="60%">
<el-form :inline="true" class="demo-form-inline" size="medium">
<el-form-item label="名称">
<el-input v-model="searchInput" placeholder="请输入" @keyup.enter.native="handleQueryForm"></el-input>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" @click="handleQueryForm">查询</el-button>
</el-form-item>
</el-form>
<!-- 普通表格 -->
<el-table :data="dataTable" :row-key="getRowKey" border height="400px" style="width: 100%">
<el-table-column label="序号" width="60" align="center">
<template v-slot="scope">{{ ( pageParam.pageNum - 1) * pageParam.pageSize + (scope.$index + 1) }}</template>
</el-table-column>
<el-table-column label="编号" prop="merchantCode" align="center"></el-table-column>
<el-table-column label="名称" prop="merchantName" align="center"></el-table-column>
</el-table>
<!-- 单选表格 -->
<!-- <el-table ref="multiTable" :data="dataTable" @row-click="handleRowClick" :row-key="getRowKey" :highlight-current-row="true" border height="400px" style="width: 100%">
<el-table-column width="60" align="center">
<template slot-scope="scope">
<el-radio v-model="radio" :label="scope.row.merchantId">
<span></span>
</el-radio>
</template>
</el-table-column>
<el-table-column label="商家编号" prop="merchantCode" align="center"></el-table-column>
<el-table-column label="商家名称" prop="merchantName" align="center"></el-table-column>
</el-table> -->
<!-- 多选表格 -->
<!-- <el-table ref="multiTable" :data="dataTable" @selection-change="handleSelectionChange" :row-key="getRowKey" border height="400px" style="width: 100%">
<el-table-column type="selection" width="60" :reserve-selection="true" align="center"></el-table-column>
<el-table-column label="编号" prop="merchantCode" align="center"></el-table-column>
<el-table-column label="名称" prop="merchantName" align="center"></el-table-column>
</el-table> -->
<div class="pagination">
<el-pagination :current-page="pageParam.pageNum" :page-size="pageParam.pageSize" :page-sizes="[10, 20, 50, 100, 200, 1000]" :total="pageParam.total" background layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" @current-change="handleCurrentChange"></el-pagination>
</div>
<span slot="footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
dialogVisible: false, // 弹框
pageParam: {
pageNum: 1,
pageSize: 10,
total: 0,
},
dataTable: [], // 表格的数据
selectedRows: [], // 选中的行
searchInput: "", // 输入框查询条件
radio: null, // 单选按钮
};
},
created() {},
methods: {
// 点击按钮弹框
handleOpenDialog() {
this.initQuery();
this.dialogVisible = true;
},
initQuery() {
// 打开弹窗时重置radio状态
// this.radio = null;
// 打开弹窗时重置勾选状态
// this.$refs.multiTable && this.$refs.multiTable.clearSelection();
this.pageParam.pageNum = 1;
this.handleQueryForm();
},
// 查询表格
handleQueryForm() {
let requestData = {
pageNum: this.pageParam.pageNum,
pageSize: this.pageParam.pageSize,
param: {
merchantName: this.searchInput,
},
};
this.$http
.requestPost({
url: "/customer/merchant/page",
param: requestData,
})
.then((res) => {
this.dataTable = res.data.list;
this.pageParam.total = res.data.total;
})
.catch((err) => {
console.log(err);
});
},
// pageSize改变时会触发
handleSizeChange(size) {
this.pageParam.pageNum = 1;
this.pageParam.pageSize = size;
this.handleQueryForm();
},
// currentPage改变时会触发
handleCurrentChange(page) {
this.pageParam.pageNum = page;
this.handleQueryForm();
},
// 行数据的Key,用来优化Table的渲染
getRowKey(row) {
return row.merchantId;
},
// 当某一行被点击时会触发该事件
handleRowClick(row) {
// 更新选中状态
this.radio = row.merchantId;
this.selectedRows = row;
console.log("单选======", this.selectedRows);
},
// 当选择项发生变化时会触发该事件
handleSelectionChange(row) {
this.selectedRows = row;
console.log("多选======", this.selectedRows);
},
},
};
</script>
<style lang="scss" scoped>
</style>
26.vue中导出Execl
async handleReport(){
var res;
let param = {
year: this.inquire.year,
month: this.inquire.month
}
// res将文件转成Blob二进制流
res = await zyExportDetails(param, "post")
try{
this.$public.downloadFile(res);
this.$message.success("导出成功!");
}catch(error){
console.log(error)
this.$message.error("导出失败!");
}
},
// 流文件下载
function downloadFile(res) {
var blob = res.data;
console.log(res)
// FileReader主要用于将文件内容读入内存
var reader = new FileReader();
console.log(reader)
reader.readAsDataURL(blob);
// onload当读取操作成功完成时调用
reader.onload = function(e) {
var a = document.createElement('a');
// 获取文件名fileName
var fileName = res.headers.filename;
a.download = fileName;
a.href = e.target.result;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
}
export default {
downloadFile,
}
27.用axios跨域调用的接口
<template>
<div class="container">
<el-form :inline="true" size="medium">
<el-form-item label="名称">
<el-input v-model="searchInput" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" @click="handleQueryForm">查询</el-button>
</el-form-item>
</el-form>
<!-- 普通表格 -->
<el-table :data="dataTable" border height="400px" style="width: 100%">
<el-table-column label="序号" width="60" align="center" type="index"></el-table-column>
<el-table-column label="编号" prop="merchantCode" align="center"></el-table-column>
<el-table-column label="名称" prop="merchantName" align="center"></el-table-column>
</el-table>
<div class="pagination">
<el-pagination :current-page="pageParam.pageNum" :page-size="pageParam.pageSize" :page-sizes="[10, 20, 50, 100, 200, 1000]" :total="pageParam.total" background layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" @current-change="handleCurrentChange"></el-pagination>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
pageParam: {
pageNum: 1,
pageSize: 10,
total: 0,
},
dataTable: [], // 表格的数据
searchInput: "", // 输入框查询条件
};
},
created() {
this.initQuery();
},
methods: {
initQuery() {
this.pageParam.pageNum = 1;
this.handleQueryForm();
},
// 查询表格
handleQueryForm() {
let requestData = {
pageNum: this.pageParam.pageNum,
pageSize: this.pageParam.pageSize,
param: {
merchantName: this.searchInput,
},
};
axios({
method: "post",
url: "http://dev-manager-api.638yipin.uyaoku.com/management/customer/merchant/page",
data: requestData,
responseType: "application/json;charset=utf-8",
headers: { Authorization: "d817b9e319fe46a189b642c137ea196b" },
}).then((res) => {
this.dataTable = res.data.data.list;
this.pageParam.total = res.data.data.total;
});
},
// pageSize改变时会触发
handleSizeChange(size) {
this.pageParam.pageNum = 1;
this.pageParam.pageSize = size;
this.handleQueryForm();
},
// currentPage改变时会触发
handleCurrentChange(page) {
this.pageParam.pageNum = page;
this.handleQueryForm();
},
},
};
</script>
<style lang="scss" scoped>
.container {
padding: 20px;
}
.pagination {
margin-top: 10px;
text-align: end;
}
</style>
28.vue封装普通表格+分页+操作栏(高频)
<template>
<div class="container">
<el-form :inline="true" size="medium">
<el-form-item label="名称">
<el-input v-model="searchInput" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" @click="fetchData">查询</el-button>
</el-form-item>
</el-form>
<!-- 普通表格 -->
<TableList :tableData="dataTable" :tableHeader="tableHeader" :pageNum="pageParam.pageNum" :total="pageParam.total" :isShowPage="true" :isShowIndex="true">
<!-- #operation 插槽对应的名称(列配置项声明的插槽名称) data插槽返回的行数据 -->
<template #operation='{data}'>
<el-button size="mini" icon="el-icon-edit" @click="handleEdit(data)" type="success">编辑</el-button>
</template>
</TableList>
</div>
</template>
<script>
import axios from "axios";
import TableList from "@/components/TableList";
export default {
components: {
TableList,
},
data() {
return {
pageParam: {
pageNum: 1,
pageSize: 10,
total: 0,
},
tableHeader: [
{
label: "编号",
prop: "merchantCode",
},
{
label: "名称",
prop: "merchantName",
},
{
label: "操作",
type: "slot", //slot插槽
slotName: "operation", //插槽名称(html表格组件内声明此插槽)
},
],
dataTable: [], // 表格的数据
searchInput: "", // 输入框查询条件
};
},
created() {
this.initQuery();
},
methods: {
initQuery() {
this.pageParam.pageNum = 1;
this.fetchData();
},
// 查询表格
fetchData() {
let requestData = {
pageNum: this.pageParam.pageNum,
pageSize: this.pageParam.pageSize,
param: {
merchantName: this.searchInput,
},
};
axios({
method: "post",
url: "http://dev-manager-api.638yipin.uyaoku.com/management/customer/merchant/page",
data: requestData,
responseType: "application/json;charset=utf-8",
headers: { Authorization: "53ea34b9a74c4660b4a982f24699f243" },
}).then((res) => {
this.dataTable = res.data.data.list;
this.pageParam.total = res.data.data.total;
});
},
//表格每页数量改变触发
setSize(size) {
this.pageParam.pageNum = 1;
this.pageParam.pageSize = size;
this.fetchData();
},
//表格当前页数改变触发
setPage(page) {
this.pageParam.pageNum = page;
this.fetchData();
},
// 编辑按钮
handleEdit(row) {
console.log("row======", row);
},
},
};
</script>
<style lang="scss" scoped>
.container {
padding: 20px;
}
</style>
<template>
<div id="tables">
<!-- table 表格 -->
<el-table id="ou" size="mini" :cell-style="{ textAlign: 'center' }" :header-cell-style="{ background: '#4e9aef', color: '#fff', textAlign: 'center' }" :border="true" :data="tableData" ref="multipleTable" style="width: 100%" max-height="400px">
<el-table-column v-if="isShowIndex" type="index" label="序号" width="50"></el-table-column>
<el-table-column v-for="(item, index) in tableHeader" :key="index" :prop="item.prop" :label="item.label" :min-width="item.width">
<template v-if="item.type === 'slot'" #default="{ row }">
<slot :name="item.slotName" :data="row"></slot>
</template>
</el-table-column>
</el-table>
<!-- table end -->
<!-- 分页器 -->
<div class="pagination" v-if="isShowPage">
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="pageNum" :page-sizes="[10, 20, 50, 100]" :page-size="10" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
</template>
<script>
export default {
props: {
// 表格数据
tableData: {
type: Array,
default: () => [],
},
// 表格头部
tableHeader: {
type: Array,
default: () => [],
},
// 分页器页数
pageNum: {
type: Number,
default: 0,
},
// 总条数
total: {
type: Number,
default: 0,
},
// 是否显示分页器
isShowPage: {
type: Boolean,
default: true,
},
// 是否显示表格序号
isShowIndex: {
type: Boolean,
default: true,
},
},
data() {
return {};
},
methods: {
//每页条数
handleSizeChange(val) {
this.$parent.setSize(val);
},
//当前页数/页数切换
handleCurrentChange(val) {
this.$parent.setPage(val);
},
},
};
</script>
<style scoped lang="scss">
.pagination {
margin-top: 10px;
text-align: end;
}
</style>
29.uniapp刷新前一个页面的数据
setTimeout(() => {
let pages = getCurrentPages(); //获取所有页面栈实例列表
let prevPage = pages[pages.length - 2]; //上一页页面实例
prevPage.$vm.initData(); //$vm后面是需要调用的上一个页面的方法和对象
uni.navigateBack({
delta:1
})
}, 1500)
30.uniapp在小程序和app使用视频播放组件
// 小程序
<!-- enable-play-gesture:双击暂停或播放 show-mute-btn:静音按钮 -->
<!-- #ifdef MP-WEIXIN -->
<video style="width:100%;height:100%;" :src="videoAddress" :show-mute-btn="true" :enable-play-gesture="true" title="名医科普"></video>
<!-- #endif -->
// app
<!-- #ifdef APP-PLUS -->
<view v-if="videoAddress">
<!-- 处理video在APP中层级过高问题 -->
<view style="width:100%;height:100%;" v-html="videoContent"></view>
</view>
<!-- #endif -->
data(){
return{
videoAddress:'', // 小程序:字段是.map4格式
videoContent: '', // app:video标签转html
}
}
methods:{
getVideoDetail(){
this.videoAddress = res.videoAddress;
this.videoContent = res.videoAddress ? `<video src="${res.videoAddress}" controls style="width:100%;height:400px;z-index: 1;" mode="aspectFill"></video>` : '';
}
}
31.uniapp自定义弹框
<u-popup v-model="modelShow" :maskCloseAble="false" mode="center" width="540rpx" border-radius="20">
<view style="padding: 20rpx;">
<view style="font-size: 32rpx;text-align: center;font-weight: bold;">服务协议和隐私政策</view>
<view style="font-size: 28rpx;margin-top: 20rpx;">
请你务必审慎阅读,充分理解“服务协议”和“隐私政策”各条款,包括但不限于:为了向你提供即时通讯、内容分享等服务,我们需要收集你的设备信息、操作日志等个人信息。你可以在“设置”中查看、变更、删除个人信息并管理你的授权。<br/>你可阅读
<text style="color:#2979ff;">《服务协议》</text>
和
<text style="color:#2979ff;">《隐私政策》</text>
了解详细信息。如你同意,请点击“同意”开始接收我们的服务。
</view>
<view style="display: flex;justify-content: space-between;padding: 20rpx;font-size: 28rpx;margin: 10rpx 0 10rpx 0;">
<view style="width: 200rpx;height: 60rpx;border-radius: 32rpx;text-align: center;color: #6d9fe8;background: #fff;border: 1px solid #6d9fe8;line-height: 60rpx;">暂不使用</view>
<view style="width: 200rpx;height: 60rpx;border-radius: 32rpx;text-align: center;color: #fff;background: #6d9fe8;line-height: 60rpx;">同意</view>
</view>
</view>
</u-popup>
32.响应式布局-媒体查询
// 1.设置 meta 标签
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
// 2.使用 @media 设置样式
// 屏幕大于 1024px 或小于 1440px 时应用该样式
@media screen and (min-width: 1024px) and (max-width: 1440px) {
...
}
// 3.依据要求并结合屏幕尺寸设置布局分界点
// 屏幕大于 1440px 时应用该样式
@media screen and (min-width: 1441px) {
...
}
// 屏幕大于 1024px 或小于 1440px 时应用该样式
@media screen and (min-width: 1024px) and (max-width: 1440px) {
...
}
// https://www.strerr.com/screen.html 手机屏幕尺寸大全
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<!-- 浏览器需要下面一行才能正确响应响应式布局 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
<style>
/* 公共样式 */
body {
margin: 0;
padding: 0;
}
/* 移动端样式 */
@media (max-width: 767px) {
.container {
background: #f0f8ff;
}
.title {
font-size: 24px;
text-align: center;
}
}
/* PC 端样式 */
@media (min-width: 768px) {
.container {
background: #ffffff;
}
.title {
font-size: 36px;
text-align: center;
}
}
</style>
</head>
<body>
<div class="container">
<h1 class="title">PC/Mobile Demo</h1>
</div>
</body>
</html>
33.uniapp添加隐私协议弹框
// 打开项目的manifest.json文件,切换到“App启动界面配置”,在“Android启动界面样式”中勾选“使用原生隐私政策提示框”
// 勾选后会在项目中自动添加androidPrivacy.json文件
{
"version" : "1",
"prompt" : "template",
"title" : "用户协议和隐私政策",
"message" : " 请你务必审慎阅读、充分理解“用户协议”和“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。<br/> 你可阅读<a href="static\htmls\userAgreement.html?type=1" >《用户协议》</a>和<a href="static\htmls\userAgreement.html?type=2">《隐私政策》</a>了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。",
"buttonAccept" : "同意",
"buttonRefuse" : "暂不使用",
"hrefLoader" : "system|default",
"second" : {
"title" : "确认提示",
"message" : " 进入应用前,你需先同意<a href="static\htmls\userAgreement.html?type=1">《用户协议》</a>和<a href="static\htmls\userAgreement.html?type=2">《隐私政策》</a>,否则将退出应用。",
"buttonAccept" : "同意并继续",
"buttonRefuse" : "退出应用"
},
"styles" : {
"backgroundColor" : "#fff",
"borderRadius" : "5px",
"title" : {
"color" : "#000"
},
"buttonAccept" : {
"color" : "#fff"
},
"buttonRefuse" : {
"color" : "#cccccc"
}
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>用户协议&隐私政策</title>
<meta
content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"
name="viewport" />
<style type="text/css">
* {
margin: 0;
padding: 0;
}
#title {
width: 100vw;
height: 50px;
/* background-color: #FFFFFF; */
display: flex;
align-items: center;
justify-content: center;
}
#text {
border: none;
width: 100vw;
height: 100vh;
box-sizing: border-box;
padding: 20px;
background-color: #ffffff;
color: #333333;
font-size: 14px;
line-height: 20px;
}
</style>
</head>
<body>
<div id="title"></div>
<div disabled="true" id="text"></div>
</body>
</html>
<script type="text/javascript">
const url = "https://user-api.638yipin.com/mine/setting/protocol/";
let type = 1;
function parseQueryString(url) {
const urlKey = url.split('?')[1]
const objKeyValue = {}
if (!urlKey) return objKeyValue
const urlObj = urlKey.split('&')
for (let i = 0; i < urlObj.length; i++) {
objKeyValue[urlObj[i].split('=')[0]] = decodeURI(urlObj[i].split('=')[1])
}
return objKeyValue
}
const urlParams = parseQueryString(window.location.href)
type = urlParams.type;
const httpRequest = new XMLHttpRequest(); //第一步:创建需要的对象
httpRequest.open("GET", url + type, true); //第二步:打开连接/***发送json格式文件必须设置请求头 ;如下 - */
// httpRequest.setRequestHeader('Content-type',
// 'application/json') //设置请求头 注:post方式必须设置请求头(在建立连接后设置请求头
httpRequest.send(); //发送请求
// 获取数据后的处理程序
httpRequest.onreadystatechange = function () {
//请求后的回调接口,可将请求成功后要执行的程序写在其中
// console.log(httpRequest);
if (httpRequest.readyState == 4 && httpRequest.status == 200) {
//验证请求是否发送成功
const res = JSON.parse(httpRequest.responseText); //获取到服务端返回的数据
// console.log(res);
if (res.message == "OK") {
document.getElementById("text").innerHTML =
res.data.protocolContent;
document.getElementById("title").innerHTML =
res.data.protocolName;
}
}
};
</script>
34.处理video在App中层级过高的问题
<!-- #ifdef MP-WEIXIN -->
<!-- enable-play-gesture:双击暂停或播放 show-mute-btn:静音按钮 -->
<view class="video_wrapper">
<video style="width:100%;height:400rpx;" :poster="content.messageTopCover" object-fit="cover" :src="content.topVideo" :show-mute-btn="true" :enable-play-gesture="true"></video>
</view>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<view class="video_wrapper">
<!-- 处理video在APP中层级过高问题 -->
<view class="video-box" v-html="content.topVideoApp"></view>
</view>
<!-- #endif -->
this.content.topVideoApp = `<video src="${topVideo}" poster="${messageTopCover}" object-fit="cover" controls width="100%" height="720rpx" style="width:100%;height:100%; z-index: 1;" mode="aspectFill"></video>`;