备份
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>
父组件 <BmjDialog :bmjShow="bmjShow" @close="bmjClose" :bmjTitle="'即将测试小程序'"></BmjDialog> import BmjDialog from "@/components/dialog/bmjDialog.vue"; components: {BmjDialog } // 定义变量 bmjShow: false // 方法 bmjClose(){ this.bmjShow = false; }, 子组件 <template> <!-- 弹窗 --> <view class="contact"> <u-popup v-model="show" mode="center" width="90%" @close="onClose" borderRadius="40"> <view class="content"> <view class="title"> <text> 提示 </text> <view class="color"></view> </view> <!-- 标题 --> <view class="phone">{{ bmjTitle }}</view> <view class="btn-box"> <view class="cancel" @click="onClose">取消</view> <view class="confirm" @click="confirm">确认</view> </view> </view> </u-popup> </view> </template> <script> export default { name: "contact", props: { bmjShow: { type: Boolean, default: false }, bmjTitle: { type: String, default: '' } }, data() { return { show: false, } }, watch: { bmjShow(val) { this.show = val; } }, methods: { onClose() { this.show = false; this.$emit('close', this.show); }, confirm() { console.log('跳转小程序'); uni.navigateToMiniProgram({ appId: "wx91d27dbf599dff74", // 其他小程序APPID path: "pages/gold/item/pages/detail/index?referer=http%3A%2F%2Fwq.jd.com%2Fwxapp%2Fpages%2Fsearch%2Flist%2Flist&sourceType=wx-search&originUrl=%2Fpages%2Fgold%2Fitem%2Fpages%2Fdetail%2Findex&gift_type=1&sku=10070450034072&pageId=W_jdgwxcx_searchresult&bbtf=1&ptag=138926.7.5", //其他小程序地址 success: (res) => { // 打开成功 console.log("打开成功", res); this.show = false; this.$emit('close', this.show); }, fail: (err) => { console.log(err); }, }); }, }, } </script> <style lang="scss" scoped> .content { margin: auto; height: 304rpx; background: linear-gradient( 175.11deg, rgb(126, 215, 217) -29.264%, rgb(255, 255, 255) 22.345% ); border-radius: 40rpx; display: flex; flex-direction: column; justify-content: space-evenly; font-family: PingFang SC; text-align: center; .title { position: relative; margin-bottom: 30rpx; text { position: absolute; left: 0; right: 0; // margin: 0 auto; color: #000; font-size: 32rpx; font-weight: 600; z-index: 5; } .color { position: absolute; width: 170rpx; height: 16rpx; left: 252rpx; top: 32rpx; bottom: 0; z-index: 4; background: linear-gradient( 90deg, rgb(243, 233, 129) 1.835%, rgba(243, 233, 129, 0) 100% ); border-radius: 32rpx; } } .phone { color: rgba(0, 0, 0, 0.85); font-size: 28rpx; font-weight: 400; } .btn-box { display: flex; padding: 0 32rpx; justify-content: space-between; .cancel, .confirm { width: 265rpx; height: 64rpx; display: flex; align-items: center; justify-content: center; font-family: PingFang SC; font-size: 28rpx; font-weight: 500; border-radius: 32rpx; border: 0px; } .cancel { background: rgba(93, 138, 163, 0.1); color: rgba(0, 0, 0, 0.3); margin-right: 16rpx; } .confirm { color: #fff; background: #32afb2; } } } </style>
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; } /* PC 端样式 */ @media (min-width: 768px) { .box-pc { .img { width: 100%; height: 100%; } } .box-mobile { display: none; } } /* 移动端样式 */ @media (max-width: 767px) { .box-pc { display: none; } .box-mobile { .img { width: 100%; height: 100%; } } } </style> </head> <body> <div class="container"> <!-- pc端页面 --> <div class="box-pc"> <div class="box1"> <img class="img" src="../images/banner1.jpg" alt="..." /> </div> </div> <!-- 移动端页面 --> <div class="box-mobile"> <div class="box1"> <img class="img" src="../images/bannerx1.png" alt="..." /> </div> </div> </div> </body> </html>
33.微信小程序添加隐私协议弹框
<template> <view class="content"> <view>主页面</view> <!-- 隐私协议 --> <!-- #ifdef MP-WEIXIN --> <PrivacyPopup ref="privacyComponent"></PrivacyPopup> <!-- #endif --> </view> </template> <script> // #ifdef MP-WEIXIN import PrivacyPopup from '@/components/privacy-popup/privacy-popup.vue'; // #endif export default { components: { // #ifdef MP-WEIXIN PrivacyPopup // #endif }, data() { }, }; </script>
<template> <view v-if="showPrivacy" class="privacy"> <view class="content"> <view class="title">隐私保护指引</view> <view class="des"> 在使用当前小程序服务之前,请仔细阅读 <text class="link" @tap="openPrivacyContract">{{privacyContractName}}</text> 。如你同意{{privacyContractName}},请点击“同意”开始使用。 </view> <view class="btns"> <button class="item reject" @tap="exitMiniProgram">拒绝</button> <button id="agree-btn" class="item agree" open-type="agreePrivacyAuthorization" @agreeprivacyauthorization="handleAgreePrivacyAuthorization">同意</button> </view> </view> </view> </template> <script> export default { name: 'PrivacyPopup', data() { return { privacyContractName: '', showPrivacy: false, // isRead: false, resolvePrivacyAuthorization: null, }; }, mounted() { if (wx.onNeedPrivacyAuthorization) { wx.onNeedPrivacyAuthorization((resolve) => { this.resolvePrivacyAuthorization = resolve; }); } if (wx.getPrivacySetting) { wx.getPrivacySetting({ success: (res) => { console.log(res, 'getPrivacySetting'); if (res.needAuthorization) { this.privacyContractName = res.privacyContractName; this.showPrivacy = true; } }, }); } }, methods: { openPrivacyContract() { wx.openPrivacyContract({ success: () => { // this.isRead = true; }, fail: () => { uni.showToast({ title: '遇到错误', icon: 'error', }); }, }); }, exitMiniProgram() { wx.exitMiniProgram(); }, handleAgreePrivacyAuthorization() { // if (this.isRead) { this.showPrivacy = false; if (typeof this.resolvePrivacyAuthorization === 'function') { this.resolvePrivacyAuthorization({ buttonId: 'agree-btn', event: 'agree', }); } // } else { // uni.showToast({ // title: '请先阅读隐私授权协议', // icon: 'error', // }); // } }, }, }; </script> <style> .privacy { position: fixed; top: 0; right: 0; bottom: 0; left: 0; background: rgba(0, 0, 0, .5); z-index: 9999999; display: flex; align-items: center; justify-content: center; } .content { width: 632rpx; padding: 48rpx; box-sizing: border-box; background: #fff; border-radius: 16rpx; } .content .title { text-align: center; color: #333; font-weight: bold; font-size: 32rpx; } .content .des { font-size: 26rpx; color: #666; margin-top: 40rpx; text-align: justify; line-height: 1.6; } .content .des .link { color: #32AFB2; text-decoration: underline; } .btns { margin-top: 48rpx; display: flex; } .btns .item { width: 244rpx; height: 80rpx; overflow: visible; display: flex; align-items: center; margin: 0 12px; justify-content: center; /* border-radius: 16rpx; */ box-sizing: border-box; border: none !important; } .btns .reject { background: #f4f4f5; color: #909399; } .btns .agree { background: #32AFB2; color: #fff; } </style>
manifest.json文件添加如下 "mp-weixin" : { "__usePrivacyCheck__" : true },
34.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>
35.处理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>`;
36.vue上传图片
<template> <div> <el-form size="small" :inline="true" label-width="68px"> <el-form-item label="上传图片" style="width:40%"> <d-upload upload-type="picture-card" :file-list="bannerImage" :limit="1" accept=".gif,.jpeg,.jpg,.png" @uploadSuccess="uploadSuccess" @removeFile="removeFile"> <div class="tip-box"> <i class="el-icon-plus" /> <span slot="tip" class="tip">上传图片</span> </div> </d-upload> <div style="color: #ccc;font-size: 12px;">建议图片比例1:1</div> </el-form-item> </el-form> </div> </template> <script> import dUpload from "@/components/d-upload/index"; export default { components: { dUpload, }, data() { return { backgroundUrl: '', bannerImage: [], } }, created() { this.getDetail() }, methods: { async getDetail() { const { code, data } = await getContactUsDetail() if (code === 200) { // ... this.backgroundUrl = data.backgroundUrl if (this.backgroundUrl) { this.bannerImage.push({ name: this.backgroundUrl.substring(this.backgroundUrl.lastIndexOf("/") + 1), url: this.backgroundUrl }) } } }, uploadSuccess(res, file, fileList) { this.backgroundUrl = res.url this.bannerImage.push({ name: res.originalFilename, url: res.url }) }, removeFile(file, fileList) { this.bannerImage = [] }, } } </script> <style lang="scss" scoped> .tip-box { position: relative; .tip { position: absolute; top: 26px; left: 34%; font-size: 12px; color: #ccc; } } /*去除upload组件过渡效果*/ ::v-deep .el-upload-list__item { transition: none !important; } </style>
<template> <div class="d-upload"> <el-upload class="upload-demo" :class="{styleA:fileList.length === 0,styleB:fileList.length === 1}" :action="action" :list-type="uploadType" :before-upload="beforeUpload" :on-preview="handlePreview" :on-remove="handleRemove" :before-remove="beforeRemove" :multiple="multiple" :limit="limit" :on-exceed="handleExceed" :drag="drag" :accept="accept" :file-list="fileList" :data="param" :on-success="uploadSuccess" :headers="headers" :show-file-list="showFileList" :on-error="uploadError" :auto-upload="autoUpload" :on-change="handleChange" > <slot /> <div v-if="tip" slot="tip" class="el-upload__tip">{{ tip }}</div> </el-upload> <!-- 弹框 --> <el-dialog title="图片预览" :visible.sync="dialogVisible" :modal="false" width="800" append-to-body > <div class="Popout_content"> <div v-if="fileType === 'image'" class="image-box"> <img :src="preview" alt=""> </div> <div v-else> <video id="video" autoplay :src="preview" controls="controls" width="100%"> 视频描述</video> </div> </div> <span slot="footer" class="dialog-footer"> <el-button @click="dialogVisible = false">关 闭</el-button> </span> </el-dialog> </div> </template> <script> import { getToken } from "@/utils/auth"; export default { name: 'DUpload', props: { action: { type: String, default: process.env.VUE_APP_BASE_API + '/file/upload' }, param: { type: Object, default: () => { } }, multiple: { // 是否多选 type: Boolean, default: false }, showFileList: { // 是否显示文件列表 type: Boolean, default: true }, drag: { // 是否拖拽上传 type: Boolean, default: false }, limit: { // 允许上传数量 type: Number, default: 1 }, accept: { // 接受上传文件类型 type: String, default: '' }, fileList: { // 上传文件列表 type: Array, default: () => [] }, size: { // 限制上传文件大小 type: Number, default: 10 }, uploadType: { type: String, default: '' }, tip: { type: String, default: '' }, headers: { type: Object, default: () => { return { 'Authorization': "Bearer " + getToken() } } }, autoUpload: { type: Boolean, default: true } }, data() { return { preview: '', // 预览图片路径 fileType: '', // 文件类型 dialogVisible: false, // 预览弹窗 removeB: true } }, methods: { // action和headers需要同步修改 handleChange(file,fileList){ console.log(file) this.removeB = true const fileSize = file.size / 1024 / 1024 > this.size if (fileSize) { this.$message({ message: '上传文件的大小不能大于' + this.size + 'M', type: 'warning' }) this.removeB = false return false } else { this.$emit('handleChange', file, fileList) this.removeB = false } }, // 文件上传之前 beforeUpload(file) { this.removeB = true const fileSize = file.size / 1024 / 1024 > this.size if (fileSize) { this.$message({ message: '上传文件的大小不能大于' + this.size + 'M', type: 'warning' }) this.removeB = false return false } else { this.$emit('beforeUpload', file) this.removeB = false } }, // 删除文件 handleRemove(file, fileList) { this.$emit('removeFile', file, fileList) }, // 预览图片 handlePreview(file) { if (file.raw) { console.log('file.raw',file.raw) const type = file.raw.type.split('/') this.fileType = type[0] const reader = new FileReader() reader.readAsDataURL(file.raw) reader.onload = (e) => { console.log(e) // _base64 this.preview = reader.result console.log('reader.result',reader.result) } } else if (file.url) { const imgT = ['.gif', '.jpeg', '.jpg', '.png', '.PNG'] const videoT = ['.wmv', '.asf', '.asx', '.rm', '.rmvb', '.rmvb', '.mpg', '.mpeg', '.mpe', '.3gp', '.mov', '.mp4', '.m4v'] const ind = file.url.lastIndexOf('.') const type = file.url.slice(ind) if (imgT.indexOf(type) !== -1) { this.fileType = 'image' } else if (videoT.indexOf(type) !== -1) { this.fileType = 'video' } this.preview = file.url } this.dialogVisible = true }, handleExceed(files, fileList) { this.$message.warning( `当前限制选择 ${this.limit} 个文件` ) }, // 删除文件之前 beforeRemove(file, fileList) { if (this.removeB) { return this.$confirm(`确定移除 ${file.name}?`) } else { return true } }, // 上传成功 uploadSuccess(response, file, fileList) { if(response.code == 200) { this.$emit('uploadSuccess', response, file, fileList) }else{ this.$emit('uploadError', response, file, fileList) } }, uploadError(err, file, fileList) { console.log(err) } } } </script> <style lang="scss"> .image-box { img { width: 100%; height: 100%; } } // 核心代码添加:class="{styleA:file_list.length === 0,styleB:file_list.length === 1}"(注意style标签不能带有scoped) .styleA .el-upload--picture-card{ width:120px; height:120px; line-height:120px; } .styleB .el-upload--picture-card{ display:none; } </style>
36.vue倒计时(设置为Vue响应式属性)
<!-- 倒计时 --> <text v-if="item.orderStatus == 'pending_payment'"> {{ item.temp_time }} <!-- {{ pending_payment_time }} --> </text> getLiveTime() { let that = this; this.timer2 = null; that.orderListx.forEach((order) => { if (order.orderStatus == 'pending_payment') { let time = String(order.orderTime).replace("-", "/").replace("-", "/"); let endTime = Date.parse(time); // 提交订单的时间 console.log("endTime00 = ", endTime); var now = new Date(); // 当前时间 var end = new Date(endTime + 15 * 60 * 1000); // 提交订单的时间,变成毫秒 // 两个时间相减,得到的是毫秒, 变成秒 let result = parseInt((end - now) / 1000); if (result > 0) { let second1 = Math.floor(result % 60); // 计算秒,取余 let minite1 = Math.floor((result / 60) % 60); // 计算分,换算有多少分,取余 this.$set(order, 'temp_time', '剩余时间' + minite1 + '分' + second1 + '秒'); // 将属性设置为Vue响应式属性 // that.pending_payment_time = '剩余时间' + minite1 + '分' + second1 + '秒'; // 单个倒计时,直接赋值 this.timer2 = setInterval(function() { result = result - 1; let second = Math.floor(result % 60); // 计算秒,取余 let minite = Math.floor((result / 60) % 60); // 计算分,换算有多少分,取余 that.$set(order, 'temp_time', '剩余时间' + minite + '分' + second + '秒'); // 将属性设置为Vue响应式属性 // that.pending_payment_time = '剩余时间' + minite + '分' + second + '秒'; that.newResult = result; }, 1000) } else { clearInterval(this.timer2); orderCancel(order.orderId).then(res => {}); this.arr(); // 刷新接口 this.$set(order, 'temp_time', ''); // 将属性设置为Vue响应式属性 } } }) },
this.timer2 = setInterval(function() { result = result - 1; if (result <= 0) { // 如果剩余时间小于等于0,则设置为-1 result = -1; that.$set(order, 'temp_time', ''); return } let second = Math.floor(result % 60); // 计算秒,取余 let minute = Math.floor((result / 60) % 60); // 计算分,换算有多少分,取余 that.$set(order, 'temp_time', '剩余时间' + minute + '分' + second + '秒'); // 将属性设置为Vue响应式属性 that.newResult = result; }, 1000)
37.uniapp实现一个简单的上(固定)中(滚动)下(固定)布局
<template> <view class="page"> <view class='wraper'> <view class='header'>header</view> <view class='main'> <scroll-view class='main-scroll' scroll-y style="height: 100%"> <view class='main-list'> <view class='card' v-for="(item,index) in cardList"> <view class='card-box'></view> <view>{{item.name}}</view> <view class='card-content'>{{item.content}}</view> </view> </view> </scroll-view> </view> <view class='footer'>footer</view> </view> </view> </template> <script> export default { data() { return { cardList: [{ name: 'aa', content: 'bb' }, { name: 'aa', content: 'bb' }, { name: 'aa', content: 'bb' }, { name: 'aa', content: 'bb' }, { name: 'aa', content: 'bb' }, { name: 'aa', content: 'bb' }, { name: 'aa', content: 'bb' }, { name: 'aa', content: 'bb' }, ] } }, methods: { } } </script> <style> .page { width: 100%; height: 100%; } .wraper { display: flex; flex-direction: column; width: 100%; height: 100%; } .header { background: rgb(8, 117, 94); color: #fff; line-height: 100rpx; flex: 0 0 100rpx; /* 不放大不缩小固定100rpx */ } .main { height: 690rpx; position: relative; } .main-scroll { position: absolute; left: 0; right: 0; top: 0; bottom: 0; } .main-list { display: flex; flex-wrap: wrap; justify-content: space-between; margin-left: 2vw; margin-right: 2vw; } .card { width: 47vw; margin-top: 10rpx; margin-bottom: 10rpx; } .card-box { width: 100%; height: 200rpx; border-radius: 6rpx; background: #ccc; } .card-content { color: blue; } .footer { background: rgb(8, 117, 94); color: #fff; line-height: 100rpx; flex: 0 0 100rpx; } </style>
38.uniapp上传视频或图片(手写原生)
<template> <!-- 上传视频或者图片 --> <view class="up-page"> <!--图片--> <view class="show-box" v-for="(item,index) in imageList" :key="index"> <image class="full" :src="item" :data-src="image" @tap="previewImage(item)"> </image> <view class="delect-icon" @tap="delect(index)"> <image class="full" :src="clearIcon" mode=""></image> <!--图片或者视频上传成功了,点击右上角叉号--> </view> </view> <!--视频--> <view class="show-box" v-for="(item1, index1) in videoList" :key="index1"> <video class="full" :src="item1"></video> <view class="delect-icon" @tap="delectVideo(index1)"> <image class="full" :src="clearIcon" mode=""></image> </view> </view> <view v-if="VideoOfImagesShow" @tap="chooseVideoImage" class="box-mode"> <image class="full" :src="selectfile" mode=""></image> <!-- 上传图标 懒得写,整个的图 --> </view> </view> </template> <script> var sourceType = [ ['camera'], ['album'], ['camera', 'album'] ]; export default { data() { return { // 图标 clearIcon: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCAwaDE2YTQgNCAwIDAgMSA0IDR2MTZINGE0IDQgMCAwIDEtNC00VjB6IiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXIpIiBmaWxsLW9wYWNpdHk9Ii45OCIgZmlsdGVyPSJ1cmwoI2ZpbHRlcjBfYikiLz48cGF0aCBkPSJNMTAuOTQgOS45OTlsMi44NjMtMi44NTdhLjY2OS42NjkgMCAxIDAtLjk0Ni0uOTQ2TDEwIDkuMDYgNy4xNDMgNi4xOTZhLjY2OS42NjkgMCAwIDAtLjk0Ni45NDZsMi44NjQgMi44NTctMi44NjQgMi44NTdhLjY2Ni42NjYgMCAwIDAgLjIxNyAxLjA5Mi42NjQuNjY0IDAgMCAwIC43MjktLjE0NkwxMCAxMC45MzhsMi44NTcgMi44NjRhLjY2Ny42NjcgMCAwIDAgMS4wOTItLjIxNy42NjYuNjY2IDAgMCAwLS4xNDYtLjcyOUwxMC45MzkgMTB6IiBmaWxsPSIjZmZmIi8+PGRlZnM+PGZpbHRlciBpZD0iZmlsdGVyMF9iIiB4PSItNCIgeT0iLTQiIHdpZHRoPSIyOCIgaGVpZ2h0PSIyOCIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPjxmZUZsb29kIGZsb29kLW9wYWNpdHk9IjAiIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4Ii8+PGZlR2F1c3NpYW5CbHVyIGluPSJCYWNrZ3JvdW5kSW1hZ2UiIHN0ZERldmlhdGlvbj0iMiIvPjxmZUNvbXBvc2l0ZSBpbjI9IlNvdXJjZUFscGhhIiBvcGVyYXRvcj0iaW4iIHJlc3VsdD0iZWZmZWN0MV9iYWNrZ3JvdW5kQmx1ciIvPjxmZUJsZW5kIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9ImVmZmVjdDFfYmFja2dyb3VuZEJsdXIiIHJlc3VsdD0ic2hhcGUiLz48L2ZpbHRlcj48bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXIiIHgxPSIyMCIgeDI9IjE1LjU4NiIgeTI9IjIyLjk0IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agc3RvcC1jb2xvcj0iIzBEMUUyOCIgc3RvcC1vcGFjaXR5PSIuOCIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzA1MEUxMiIgc3RvcC1vcGFjaXR5PSIuNjUiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48L3N2Zz4=', selectfile: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB4PSIuMjUiIHk9Ii4yNSIgd2lkdGg9IjYzLjUiIGhlaWdodD0iNjMuNSIgcng9IjMuNzUiIGZpbGw9IiNGMkYyRjIiIHN0cm9rZT0iI0YyRjJGMiIgc3Ryb2tlLXdpZHRoPSIuNSIvPjxyZWN0IHg9IjE2IiB5PSIzMSIgd2lkdGg9IjMyIiBoZWlnaHQ9IjIiIHJ4PSIxIiBmaWxsPSIjQkZCRkJGIi8+PHJlY3QgeD0iMzMiIHk9IjE2IiB3aWR0aD0iMzIiIGhlaWdodD0iMiIgcng9IjEiIHRyYW5zZm9ybT0icm90YXRlKDkwIDMzIDE2KSIgZmlsbD0iI0JGQkZCRiIvPjwvc3ZnPg==', VideoOfImagesShow: true, // 页面图片或视频数量超出后,拍照按钮隐藏 imageList: [], //存放图片的地址 videoList: [], //视频存放的地址 sourceType: ['拍摄', '相册', '拍摄或相册'], sourceTypeIndex: 2, cameraList: [{ value: 'back', name: '后置摄像头', checked: 'true' }, { value: 'front', name: '前置摄像头' }], cameraIndex: 0, //上传视频时的数量 maxCount:9//图片和视频允许上传的总数 } }, onUnload() { (this.imageList = []), (this.sourceTypeIndex = 2), (this.sourceType = ['拍摄', '相册', '拍摄或相册']); }, methods: { //点击上传图片或视频 chooseVideoImage() { uni.showActionSheet({ title: '选择上传类型', itemList: ['图片', '视频'], success: res => { console.log(res); if (res.tapIndex == 0) { this.chooseImages(); } else { this.chooseVideo(); } } }); }, //上传图片 chooseImages() { uni.chooseImage({ count: this.maxCount, //允许选择的数量 sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有 sourceType: ['album', 'camera'], //从相册选择 success: res => { this.imageList = this.imageList.concat(res.tempFilePaths); //console.log(this.imageList) if (this.imageList.length+this.videoList.length == this.maxCount) { this.VideoOfImagesShow = false; //图片上传数量和count一样时,让点击拍照按钮消失 } } }) }, //上传视频 chooseVideo(index) { uni.chooseVideo({ maxDuration: 60, //拍摄视频最长拍摄时间,单位秒。最长支持 60 秒 count: this.maxCount, camera: this.cameraList[this.cameraIndex].value, //'front'、'back',默认'back' sourceType: sourceType[this.sourceTypeIndex], success: res => { this.videoList = this.videoList.concat(res.tempFilePath); if (this.imageList.length+this.videoList.length == this.maxCount) { this.VideoOfImagesShow = false; } console.log(this.videoList); } }) }, //预览图片 previewImage: function(e) { console.log(e) uni.previewImage({ current: e, urls: this.imageList }); }, // 删除图片 delect(index) { uni.showModal({ title: '提示', content: '是否要删除该图片', success: res => { if (res.confirm) { this.imageList.splice(index, 1); } if (this.imageList.length+this.videoList.length == this.maxCount) { this.VideoOfImagesShow = false; } else { this.VideoOfImagesShow = true; } } }); }, // 删除视频 delectVideo(index) { uni.showModal({ title: '提示', content: '是否要删除此视频', success: res => { if (res.confirm) { this.videoList.splice(index, 1); } if (this.imageList.length+this.videoList.length == this.maxCount) { this.VideoOfImagesShow = false; } else { this.VideoOfImagesShow = true; } } }); }, } } </script> <style lang="scss"> /* 统一上传后显示的盒子宽高比 */ .box-mode { width: 27vw; height: 27vw; border-radius: 8rpx; overflow: hidden; } .full { width: 100%; height: 100%; } .up-page { display: flex; flex-wrap: wrap; display: flex; width: 100%; .show-box:nth-child(3n){ margin-right: 0; } .show-box { position: relative; margin-bottom:4vw; margin-right: 4vw; @extend .box-mode; .delect-icon { height: 40rpx; width: 40rpx; position: absolute; right: 0rpx; top: 0rpx; z-index: 1000; } } } </style>
// 1.封装上传图片的方法 /** * @description: 图片处理-上传图片 * @param {*} api 请求地址的后缀 url 选择文件后返回的url * @return {*} 格式化后的内容 */ function uploadImage(api, url, callback) { uni.showLoading({ title: '上传中' }); const token = uni.getStorageSync('token'); let header = { 'Authorization': token ? token : '' }; return new Promise((resolve, reject) => { uni.uploadFile({ url: BASE_URL + api, filePath: url, name: 'file', header:{ 'Authorization': token ? token : '' }, success: res => { res = JSON.parse(res.data); console.log('res',res) if (res.code === 200) { uni.hideLoading() uni.showToast({ title: '上传成功', icon: 'none' }); callback(res) // resolve(res.data) } else { uni.hideLoading() uni.showModal({ title: '上传失败', content: res.msg }); } } }); }).catch(e => { reject(e) }) } // 2.页面调用 import { uploadImage } from '@/utils/util'; //上传图片 chooseImages() { uni.chooseImage({ count: this.maxCount, //允许选择的数量 sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有 sourceType: ['album', 'camera'], //从相册选择 success: res => { uploadImage('/common/file/upload', res.tempFilePaths[0], ret => { this.imageList = this.imageList.concat(ret.data); console.log('图片', this.imageList) }); } }) }, //上传视频 chooseVideo(index) { uni.chooseVideo({ maxDuration: 60, //拍摄视频最长拍摄时间,单位秒。最长支持 60 秒 count: this.maxCount, camera: this.cameraList[this.cameraIndex].value, //'front'、'back',默认'back' sourceType: sourceType[this.sourceTypeIndex], success: res => { uploadImage('/common/file/upload', res.tempFilePath, ret => { this.videoList = this.videoList.concat(ret.data); console.log('视频', this.videoList); }); } }) },
39.element中el-cascader级联获取name和id值
// el-select <el-select v-model="nValue" value-key="value" placeholder="请选择" @change="handleChange($event)" clearable> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item"> </el-option> </el-select> options: [{ value: '选项1', label: '黄金糕' }, { value: '选项2', label: '双皮奶' }, { value: '选项3', label: '蚵仔煎' }, { value: '选项4', label: '龙须面' }, { value: '选项5', label: '北京烤鸭' }], handleChange(e){ this.inquire.newValue = e.value || '' this.inquire.newName = e.label || '' } // el-cascader <el-cascader ref="cascaderAddr" v-model="formData.areaId" @change="handleChange" :props="addressProps" :options="addressList" clearable placeholder="请选择地址" /> addressProps: { label: 'areaName', value: 'areaId', children: 'childes', checkStrictly: true, emitPath: false }, handleChange(value) { this.$nextTick(() => { if(this.$refs["cascaderAddr"].presentText && this.$refs["cascaderAddr"].presentText.length > 0){ // 判断在第几层 this.formData.addressHierarchy = (this.$refs["cascaderAddr"].presentText.match(/\//g) || []).length + 1; }else{ this.formData.addressHierarchy = null } }); }
40.uniapp按钮样式调整
<template> <view class="page-wrapper"> <u-navbar title-color="#fff" back-icon-color="#ffffff" :is-fixed="isFixed" :is-back="isBack" :background="background" :back-text-style="{ color: '#fff' }" :title="title" :back-icon-name="backIconName"></u-navbar> <view class="page-body"> <view class="member-list"> <view class="member-card" v-for="(item, index) in source" :key="index"> <view class="member-item">{{item.name}}</view> </view> </view> <view class="add-member"> <view class="addBtn"> 添加成员 </view> </view> </view> </view> </template> <script> export default { data() { return { title: '成员列表', backIconName: 'nav-back', background: { background: 'url("https://chinaja.oss-cn-shenzhen.aliyuncs.com/2023/7/13/0df31754-03ad-4d88-85a0-5584c54fa127.png") no-repeat top / 100% 100%' }, isBack: true, isFixed: true, source: [ { id: 1, name: '张可乐' }, { id: 2, name: '五六七' }, { id: 3, name: '十三' }, { id: 4, name: '五六七' }, { id: 5, name: '五六七' }, { id: 6, name: '五六七' }, { id: 7, name: '五六七' }, { id: 8, name: '五六七' }, { id: 9, name: '五六七' }, { id: 10, name: '五六七' }, { id: 11, name: '五六七' }, { id: 12, name: '五六七' }, { id: 13, name: '五六七' }, { id: 14, name: '五六七' }, { id: 15, name: '五六七' }, ] }; }, onLoad() { }, onShow() { }, methods: { } }; </script> <style lang="less" scoped> .page-body { height: 100%; } .member-list { background: #f5f6f5; padding-top: 2%; padding-bottom: 160rpx; .member-card { width: 92%; height: 80rpx; margin-left: 4%; background: #ffffff; display: flex; align-items: center; padding-left: 6%; margin-top: 2%; border-radius: 12rpx; } } .add-member { position: fixed; bottom: 0; height: 160rpx; width: 100%; background: #f5f6f5; padding-top: 40rpx; .addBtn { width: 92%; height: 80rpx; margin-left: 4%; display: flex; justify-content: center; align-items: center; background: #4e9aef; color: #ffffff; border-radius: 20rpx; } } </style>
41.js获取网址参数
let str = 'http://www.baidu.com/xxx?name=张三&age=18' let a1 = new URLSearchParams(new URL(str).search).get('name') let a2 = new URLSearchParams(new URL(str).search).get('age') console.log('a1',a1); // 输出:张三 console.log('a2',a2); // 输出:18