备份
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

浙公网安备 33010602011771号