u-picker 封装
u-radio 分装
u-select 分装
正在加载中 分装
u-picker 封装
uniapp分装 uview1.0x 中的 u-checkbox
<!-- 日期选择器 专注于时间和地区的选择-->
<!-- 只支持 年月日时分秒 按顺序排列 -->
<!-- 不回显原因:在页面的data中 写上你绑定的对应的属性~~~~~否则监听不到回显~~~~~ -->
<!-- 不回显原因:修改页面 不能直接 this.form = data[0],这样监听响应失效~~~~~ -->
<template>
<view style="width: 100%">
<u-input :disabled="disabled" :input-align="align" :placeholder="`请选择 ${placeholder}`" v-model="valueLable" type="select" :select-open="show" @click="disabled? '' : show = true" :border="border" />
<u-picker :mode="mode" v-model="show" :params="params" @cancel="cancel" @confirm="confirm" :safe-area-inset-bottom="safebottom" />
</view>
</template>
<script>
export default {
name: "fs-picker",
props: {
placeholder: { type: String, default: '' }, // 提示
mode: { type: String, default: 'time' }, // 模式 time、region 时间、地区
valueformat: { type: String, default: 'yyyy-MM-dd HH:mm:ss' }, //选中的值,value
labelformat: { type: String, default: 'yyyy-MM-dd' },
border: { type: Boolean, required: false }, // 是否显示边框
value: { type: String, default: '' },
align: { type: String, default: 'right' },
safebottom: { type: Boolean, default: true }, //底部安全区域
disabled:{type:Boolean, default: false},// 禁用全部
},
data() {
return {
show: false, //控制显隐
valueLable: '', //当前展示的值
currentValue: '',//当前展示的 key
valueLabelArr: [],//当前拆分的 值 [yyyy,MM,dd,HH,mm,ss]
valueArr: [],//当前拆分的 值 [2002,01,03,24,59,59]
params: { year: false, month: false, day: false, hour: false, minute: false, second: false, }, //时间模式
obj: { 'yyyy': 'year', 'MM': 'month', 'dd': 'day', 'HH': 'hour', 'mm': 'minute', 'ss': 'second' },
};
},
mounted() {
// 2021-11-18 00:00:00
//初始化 下拉框选项
this.valueLabelArr = this.paramsFormat(this.valueformat) //[yyyy,dd,zz,hh,ss,hh]
let obj = {}
this.valueLabelArr.forEach(item => { obj[this.obj[item]] = true })
this.params = obj
},
watch: {
// 监听 value
value: {
handler(newValue, oldValue) {
console.log('-fs-picker--','新:',newValue, '旧:',typeof oldValue,oldValue)
if(!newValue) return
this.currentValue = newValue
this.initData(newValue)
},
immediate: true
}
},
methods: {
//初始化数据
initData(newValue) {
//初始化显示的值
let valueLable = this.labelformat //yyyy-MM-dd
//拆分 value
this.valueArr = this.paramsFormat(newValue) //【2022,】
this.valueLabelArr = this.paramsFormat(this.valueformat) //[yyyy,dd,zz,hh,ss,hh]
console.log(this.valueArr,this.valueLabelArr,'this.valueArr')
this.valueLabelArr.forEach((item, index) => {
if (valueLable.indexOf(item) != -1) {//yyyy年MM月dd日
let reg = new RegExp(item, "i")
valueLable = valueLable.replace(reg, this.valueArr[index] || '00')
console.log(valueLable,'valueLabel')
}
})
console.log(valueLable,'this.valuelabel')
this.valueLable = valueLable
},
//成功选中
confirm(e) {
let NYR = [] //年月日
let SFM = [] //时分秒
this.valueLabelArr = this.paramsFormat(this.valueformat)
this.valueLabelArr.forEach((item, index) => {
if (item == 'yyyy' || item == 'MM' || item == 'dd') { NYR.push(e[this.obj[item]]) }
if (item == 'HH' || item == 'mm' || item == 'ss') { SFM.push(e[this.obj[item]]) }
})
let NYRstr = ''
let SFMstr = ''
if (NYR.length) { NYRstr = NYR.join('-') }
if (SFM.length) { SFMstr = SFM.join(':') }
let value = ''
if (NYRstr && SFMstr) {
value = NYRstr + ' ' + SFMstr
} else if (NYRstr && !SFMstr) {
value = NYRstr
} else if (!NYRstr && SFMstr) {
value = SFMstr
}
this.$emit('input', value)
this.$emit('returnData', { value, oldValue: this.valueLable })
console.log('开放方法:returnData:', { value, oldValue: this.valueLable, })
},
//取消 选择
cancel(e) {},
//解析日期格式
paramsFormat(date) { //yyyy-dd-zz hh:ss:bb
let arrFormat = []
if (date.indexOf(' ') > 0 && date.indexOf(' ') < date.length - 1) {//有 时 / 时分 / 时分秒
let arr = date.split(' ') // ['yyyy-dd-zz', 'hh']| ['yyyy-dd-zz', 'hh:ss'] |['yyyy-dd-zz', 'hh:ss:bb']
arrFormat = [...arr[0].split('-'), ...arr[1].split(':')] //[yyyy,MM,dd,zz,hh,ss,hh]
} else {
arrFormat = date.split('-') //[yyyy,MM,dd]
}
return arrFormat
}
}
}
</script>
<style lang="scss" scoped>
</style>
使用
<fs-picker v-model="form.JSSJ" placeholder="结束时间" labelformat="yyyy-MM-dd HH:mm:ss"></fs-picker>
u-radio 分装
<!-- 单选组件分装 -->
<template>
<view>
<u-radio-group :disabled="disabled" @change="radioGroupChange" :wrap="wrap" v-model="selectValue">
<u-radio @change="radioChange" v-model="item.checked" v-for="(item, index) in list" :key="index" :name="item[valuename] || item.value"> {{ item[labelname] || item.label}}</u-radio>
</u-radio-group>
</view>
</template>
<script>
export default {
name:"fs-checkbox",
props: {
value: {type:String, default:''},//值 '1'
labelname: {type:String,default:'dictValue'}, // 默认 label tag
valuename: {type: String, default: 'dictKey'}, // 默认 value tag
list: {type: Array, default() {return []}},//字典 [{dictKey:1,dictValue:'男'}] 默认
wrap: {type:Boolean, default: false},//是否独占一行
disabled:{type:Boolean, default: false},// 禁用全部
},
mounted() {
//当 值为空时触发
// if(!this.value && (this.value !== 0 || this.value !== '0')) {
// this.selectValue = this.value
// }
},
watch:{
value:{
handler(newValue,oldValue) {
if(newValue || newValue === 0 || newValue === '0') {
this.selectValue = newValue
}else {
this.selectValue = ''
}
},
deep:true,
immediate: true
}
},
data() {
return {selectValue: ''};
},
methods:{
//radioChange
radioChange(e) {},
//获取选中的数据 数组格式
radioGroupChange(e) {
// console.log(e,'eeeee')
let returnData = e || ''
this.$emit('input',returnData)
this.$emit('returnData',returnData)
console.log('开放方法: returnData')
}
}
}
</script>
<style lang="scss">
</style>
使用
<fs-radio v-model="recordForm.DWLX" :list="[{dictValue: '是',dictKey: '0'},{dictValue: '否',dictKey: '1'}]"></fs-radio>
u-select 分装
<!-- 点击弹窗下拉选择 可 单/多 列-->
<template>
<view style="width: 100%">
<u-input :input-align="inputaling" :placeholder="`请选择 ${placeholder}`" v-model="valueLable" type="select" :select-open="show" @click="show = true" :border="border"/>
<u-select v-model="show" :mode="mode" :list="list" @confirm="confirm" :value-name="valuename" :label-name="labelname" :safe-area-inset-bottom="true"></u-select>
</view>
</template>
<script>
export default {
name:"fs-select",
props:{
placeholder: {type:String,default:''}, // 提示
labelname: {type:String,default:'dictValue'}, // 默认 label tag
valuename: {type: String, default: 'dictKey'}, // 默认 value tag
mode: {type: String, default: 'single-column'}, // 模式
list: {type: Array, default(){return []}}, //下拉列表数据
value: {type:[String, Number],required:true},//选中的值,value
border: {type: Boolean,required:false},// 是否显示边框
inputaling: {type:String,default:'right'},
},
data() {
return {
show: false,//控制显隐
valueLable: ''//展示的值
};
},
watch:{
//监听 value
value(newValue, oldValue) {
this.list.forEach((item,index) => {
if(newValue == item[this.valuename]) {
this.valueLable = item[this.labelname]
}
})
},
//监听 value
list:{
handler(newValue, oldValue) {
newValue.forEach((item,index) => {
if(this.value == item[this.valuename]) {
this.valueLable = item[this.labelname]
}
})
},
deep: true
}
},
methods:{
//成功选中
confirm(e) {
console.log(e,'e--')
this.valueLable = e[0].label
this.$emit('input',e[0].value)
this.$emit('change',e)
// console.log(this.$emit('change'))
}
}
}
</script>
<style lang="scss">
</style>
使用
<fs-select :list="[{dictKey: 1,dictValue: '男'}, {dictKey: 2,dictValue: '女'}]" v-model="form.SEX" ></fs-select>
正在加载中 分装
<!-- 加载数据 loading弹窗 -->
<template>
<u-mask :show="show" @click="$emit('update:show', false)">
<view class="load_more_m">
<u-loading mode="circle" color="#169ef9" />
<view class="word">正在加载中...</view>
</view>
</u-mask>
</template>
<script>
export default {
name:"loading-mask",
data() {return {};},
props:{show:Boolean},
methods:{}
}
</script>
<style lang="scss" scoped>
.load_more_m {
margin: 33vh auto auto;
width: 300rpx;
height: 200rpx;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
border-radius: 20rpx;
flex-direction: column;
.word {
margin-top: 24rpx;
letter-spacing: 0.1em;
}
}
</style>
使用
<loading-mask :show.sync="showMask"></loading-mask>
u-popup 分装
<template>
<view style="color: #000000;">
<view style="position: relative;" @click="openClick">
<slot name="btn">
<!-- <view class="fs_button">测试</view> -->
</slot>
</view>
<u-popup v-model="showPopup" mode="bottom" :mask-close-able="maskclose" :height="height" :border-radius="borderradius" :safe-area-inset-bottom="true" :closeable="closeable">
<view class="popup_title">{{title}}</view>
<scroll-view :scroll-top="scrollTop" scroll-y="true" @scrolltoupper="upper" @scrolltolower="lower" :class="toggleClass" >
<slot>
<view style="height: 100%" v-if="height">
<u-empty text="暂无数据" mode="list"></u-empty>
</view>
</slot>
</scroll-view>
<view class="mask_footer" v-if="(confirmbtn || cancalbtn) && footBtn">
<slot name="footer">
<u-button type="primary" style="width:320rpx" @click="confirmClick" v-if="confirmbtn">{{confirmtext}}</u-button>
<u-button type="info" style="width:320rpx" @click="cancalClick" v-if="cancalbtn">取 消</u-button>
</slot>
</view>
</u-popup>
</view>
</template>
<script>
export default {
name: "popup",
props: {
height: { type: String, default: '90%' },
borderradius: { type: String, default: '20' },
title: { type: String, default: '' },
maskclose: {type:Boolean, default: false},//点击 mask 关闭
closeable: {type:Boolean, default: false},//关闭按钮
confirmbtn: {type:Boolean, default: true},
cancalbtn: {type:Boolean, default: true},
confirmtext: { type: String, default: '确 认' },
footBtn: {type:Boolean, default: true},//底部按钮事件
visible: {type:Boolean, default: false},//没有 按钮插槽 控制显隐的属性
},
data() {
return {
showPopup: false, //切换弹窗
scrollTop: 0,//滚动
};
},
watch:{
visible(newValue,oldValue) {
this.showPopup = newValue
}
},
computed:{
toggleClass() {
if(this.footBtn) {//都在
return 'popup_all'
}else if(!this.footBtn){ //头在 脚不在
return 'popup_header'
}
}
},
methods: {
//点击确认事件
confirmClick() {
console.log('confirmClick','点击确认')
this.$emit('confirmClick',this.done)
// this.showPopup = false
},
//
done() {
this.showPopup = false
this.$emit('update:visible', false);
},
//点击取消事件
cancalClick() {
this.showPopup = false
console.log('cancalClick','点击取消')
this.$emit('cancalClick')
this.$emit('update:visible', false);
},
//点击打开弹窗
openClick() {
console.log(1111)
this.showPopup = true
this.$emit('changeClick')
console.log('点击按钮可触发:changeClick 事件,在 fs-popup 组件上绑定')
},
//滚动到顶部触发的事件
upper() {
console.log('滚动到顶部触发的事件 @scrolltoupper')
this.$emit('scrolltoupper')
},
//滚动到底部触发的事件
lower() {
console.log('滚动到底部触发的事件 @scrolltolower')
this.$emit('scrolltolower')
},
}
}
</script>
<style lang="scss" scoped>
.popup_title{
text-align: center;
font-size: 36rpx;
font-weight: 500;
line-height: 70rpx;
height: 70rpx;
border-bottom: 2rpx solid #888;
}
// 关闭按钮样式
/deep/.u-close.u-close--top-right{
top: 0rpx !important;
}
.mask_footer{
height: 50px;
padding: 0 30rpx;
display: flex;
justify-content: space-around;
align-items: center;
border-top: 2rpx solid #888;
}
// 切换滚动组件高度问题
.popup_all{height: calc(100% - 43px - 45px);}
.popup_header{height: calc(100% - 45px);}
.popup_no{height: calc(98%);}
// 自定义按钮
.fs_button {
color: #ffffff;
border-color: #2979ff;
background-color: #2979ff;
display: inline-flex;
width: auto;
font-size: 22rpx;
padding-top: 1px;
height: 50rpx;
line-height: 50rpx;
padding: 0 20rpx;
border-radius: 5px;
}
</style>
使用
<fs-popup title="市场准入检查情况" :visible.sync="sczrshow" @confirmClick="sczradd" @cancalClick="sczrqx" :height="zobj.SCZRJCQKDX==1? '90%': '60%'">
<u-cell-group :border="false">
<u-cell-item :arrow="false" hover-class="none" bg-color="white">
<u-form-item label-width="1px">
<fs-radio v-model="zobj.SCZRJCQKDX" @returnData="bhgqk" :list="[{dictValue: '未发现不合格现象',dictKey: '0'},{dictValue: '不合格',dictKey: '1'}]"></fs-radio>
</u-form-item>
<view v-if="zobj.SCZRJCQKDX==1">
<!-- <fs-checkbox v-model="recordForm.CSLX" :list="typeBoxList" valuename="name" labelname="label"></fs-checkbox> -->
<u-checkbox-group wrap @change='sczrbhg'>
<u-checkbox v-model="item.checked" v-for="(item, index) in SCZRJCQK" :key="index" :name="item.name">
{{item.name}}
</u-checkbox>
</u-checkbox-group>
</view>
<u-form-item label="不合格情况" :label-style='{fontSize:"20px"}' label-position='top'>
<u-input v-model="zobj.SCZRJCQK" type="textarea" maxlength="2222" border
:height="100" :auto-height="true" />
</u-form-item>
</u-cell-item>
</u-cell-group>
</fs-popup>
checkbox 封装
<!-- 多选组件分装 -->
<template>
<view>
<u-checkbox-group :disabled="disabled" @change="handleChangeCheckbox" :wrap="wrap">
<u-checkbox @change="checkboxChange" v-model="item.checked" v-for="(item, index) in formatList" :key="index" :name="item[valuename] || item.value" v-show="!item.hidden"> {{ item[labelname] || item.label}}</u-checkbox>
</u-checkbox-group>
</view>
</template>
<script>
export default {
name:"fs-checkbox",
props: {
value: {type:String, default:''},//值 '1,2,3,4,5'
keyname: {type: String, default:''}, //key 名字
labelname: {type:String,default:'dictValue'}, // 默认 label tag
valuename: {type: String, default: 'dictKey'}, // 默认 value tag
list: {type: Array, default() {return []}},//字典 [{dictKey:1,dictValue:'男'}] 默认
wrap: {type:Boolean, default: false},//是否独占一行
disabled:{type:Boolean, default: false},// 禁用全部
},
mounted() {
this.formatData()
// console.log(this.list,'this.list')
},
watch:{
list(newvalue, oldValue) {
this.formatData()
},
value(newValue, oldValue) {
console.log(newValue,'1111111111111111111111111111111111111111')
this.formatData()
}
},
data() {
return {
formatList:[],//重新赋值,解决奇葩bug
};
},
methods:{
//格式化数据
formatData() {
//当 值为空时触发
if(!this.value && (this.value !== 0 || this.value !== '0')) {
this.list.forEach(item => {item.checked = false})
this.formatList = this.list
}else{
let arr = []
if(this.value === 0 || this.value === '0' || this.value != '') {//不为空
if(this.value.indexOf(',') != -1) {//选多个
arr = this.value.split(',')
}else { //选一个
arr = [this.value]
}
//赋值 checked true false
this.list.forEach(item => {this.$set(item,'checked', false)})
arr.forEach(item1 => {this.list.forEach(item2 => { console.log(item1 == item2[this.valuename]); if(item1 == item2[this.valuename]) {item2.checked = true;}})})
this.formatList = this.list
}
}
},
//checkboxChange
checkboxChange(e) {console.log(e,'eee')},
//获取选中的数据 数组格式
handleChangeCheckbox(e) {
console.log(e,'e')
let returnData =(e || []).join(",")
console.log(returnData,'选中的')
this.$emit('input',returnData)
this.$emit('returnData',{value: returnData,prop: this.keyname || ''})
console.log('开放方法: returnData')
}
}
}
</script>
<style lang="scss">
</style>
使用
<fs-checkbox v-model="form.hzlx" :list="[{name: "铁道",value: "12"},{name: "船舶",value: "13"},{name: "民航",checked: false,value: "14"}," valuename="value" labelname="name"></fs-checkbox>
下拉加载更多数据 fs-load-more
示例
组件
<!-- 下拉加载更多数据状态 -->
<template>
<view v-if="page.total > page.pageSize" class="load_more" style="padding: 32rpx; background-color: #FFFFFF;">
<u-loadmore :status="status" color=" #169ef9" />
</view>
</template>
<script>
/**
* param {String} status // 加载前值为loadmore,加载中为loading,没有数据为nomore
* page {Object} status // 页码-数据小于每页显示条数时不显示组件
*/
export default {
props: {
status: { type: String, default: 'loadmore' },
page: { type: Object,default() {return {currentPage: 1, pageSize: 10, total: 0}} }
},
}
</script>
<style lang="scss" scoped>
.load_more {
padding: 40rpx 0 160rpx;
color: #169ef9;
}
</style>
使用
#模板
<fs-load-more :page="page" :status="status"></fs-load-more>
#状态
status: "loadmore"
page: { pageSize: 10, currentPage: 1, total: 0 }
#调接口
if (this.status == 'nomore') return;
try{
this.status = 'loading'
const data = await post(this.page.currentPage, this.page.pageSize, {});
this.page.total = data.total;
if (this.page.currentPage == 1) {
this.data = data.records
} else {
this.data.push(...data.records)
if (this.data.length < this.page.total) {
this.status = 'loadmore'
} else {
this.status = 'nomore'
}
}
}catch(e){}
fs-load-page
组件
<!-- 加载状态:首次进入页面显示数据加载中,没有数据显示暂无数据 -->
<template>
<view>
<view v-if="(page.current == 1 || page.currentPage == 1 ) && firstLoading" class="empty_wrap" :style="{top: top + 'rpx'}">
<view class="container">
<view class="box">
<view class="atom"></view>
<view class="atom"></view>
<view class="atom"></view>
<div class="dot"></div>
</view>
</view>
</view>
<view v-if="page.total == 0 && !firstLoading && isList" class="empty_wrap" :style="{top: top + 'rpx'}">
<view class="data_empty">
<image src="@/static/img/fs-empty-data.png"></image>
<view class="tip_title"> 暂无数据 </view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
loading: { type: Boolean, default: true },
isList: { type: Boolean, default: true },
firstFlag: { type: Boolean, default: false },
top: { type: String | Number, default: 0 },
page: { type: Object, default () { return { currentPage: 1, pageSize: 10, total: 0 } } }
},
watch: {
loading: {
handler(newValue, oldValue) {
if (newValue == true && this.firstFlag) { this.firstLoading = true }
if (newValue == false) { this.firstLoading = false; }
console.log(newValue, this.firstLoading, 'this.firstLoading')
},
deep: true,
immediate: true
},
},
data() {
return {
firstLoading: true,
};
}
}
</script>
<style lang="scss" scoped>
.empty_wrap {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 999;
background: white;
display: flex;
align-items: center;
justify-content: center;
.data_empty {
flex-direction: column;
.tip_title {
text-align: center;
}
}
}
.container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.box {
position: relative;
width: 120rpx;
height: 120rpx;
}
.dot {
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #0396FF;
animation: dotbreath 2s linear infinite;
}
.atom {
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
border-left-width: 6rpx;
border-top-width: 6rpx;
border-left-color: #0396FF;
border-left-style: solid;
border-top-style: solid;
border-top-color: transparent;
}
.atom:nth-of-type(1) {
left: 0%;
top: 0%;
animation: atom1 1s linear infinite;
}
.atom:nth-of-type(2) {
right: 0%;
top: 0%;
animation: atom2 1s linear infinite;
}
.atom:nth-of-type(3) {
right: 0%;
bottom: 0%;
animation: atom3 1s linear infinite;
}
@keyframes dotbreath {
0% {
opacity: 1;
}
50% {
opacity: 0.5;
}
100% {
opacity: 1;
}
}
@keyframes atom1 {
0% {
transform: rotateZ(120deg) rotateX(66deg) rotateZ(0deg);
}
100% {
transform: rotateZ(120deg) rotateX(66deg) rotateZ(360deg);
}
}
@keyframes atom2 {
0% {
transform: rotateZ(240deg) rotateX(66deg) rotateZ(0deg);
}
100% {
transform: rotateZ(240deg) rotateX(66deg) rotateZ(360deg);
}
}
@keyframes atom3 {
0% {
transform: rotateZ(360deg) rotateX(66deg) rotateZ(0deg);
}
100% {
transform: rotateZ(360deg) rotateX(66deg) rotateZ(360deg);
}
}
</style>
使用
<!-- 首次加载 -->
<fs-load-page :page="page" :loading="loading" :firstFlag="firstFlag"></fs-load-page>