uniApp项目中自定义上传图片组件和下拉选择组件总结

416 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。 这是为了方便操作上传图片而自定义的组件。也方便以后自己寻找,做了这么一个记录。

一自定义上传主键

vue代码

<template>
	<view>
		 <u-upload :fileList="fileListChy" @afterRead="afterRead" @delete="deletePic" name="Chy" multiple
			:previewFullImage="true" :maxCount="1" :width="chyWidth" height="chyHeight">
			<image :src="chyImageUrl" mode="widthFix" style="{width: `${chyWidth}px`;height: `${chyHeight}px`}">
			</image>
		</u-upload>
	</view>
</template>

<script>
	import config from '@/common/config.js'
	import props from './props.js'
	export default {
		name: 'chy-upload',
		data() {
			return {
			 fileListChy:[]
			}
		},
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
		methods: {
			// 删除图片
			deletePic(event) {
				this[`fileList${event.name}`].splice(event.index, 1)
			},
			async afterRead(event) {
				let that =this;
				//当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
					let lists = [].concat(event.file)
					let fileListLen = this[`fileList${event.name}`].length
					//console.log(event,"event")
					lists.map((item) => {
						this[`fileList${event.name}`].push({
							...item,
							status: 'uploading',
							message: '上传中'
						})
					})
					for (let i = 0; i < lists.length; i++) {
						const result = await this.uploadFilePromise(lists[i].url)
						let item = this[`fileList${event.name}`][fileListLen]
						this[`fileList${event.name}`].splice(fileListLen, 1, Object.assign(item, {
							status: 'success',
							message:  JSON.parse(result).data,
							url: JSON.parse(result).data.fileUrl
						}))
						fileListLen++
					}
					console.log(that.fileListChy,"fileList7")
					that.chyGetImageUrl(that.fileListChy)
			},
			uploadFilePromise(url) {
				let that=this;
				return new Promise((resolve, reject) => {
					let a = uni.uploadFile({
						url: config.baseUrl +'/xxxxx/xxxxxx?Content-Type=multipart/form-data', // 仅为示例,非真实的接口地址
						filePath: url,
						name: 'file',
						formData: that.chyFormData,
						success: (res) => {
							console.log(res,"res")
							setTimeout(() => {
								resolve(res.data)
							}, 1000)
						}
					});
				})
			},
			//获取到上传文件链接
			chyGetImageUrl(dataArr){
				this.$emit("imageClick",dataArr[0].url);
			}
		}
	}
</script>

<style>
</style>

js代码

export default {
    props: {
        // 上传最大数量
        maxCount: {
            type: [Number,String],
            default: 1
        },
		// 提示图片高度
		chyHeight: {
		    type:  [Number,String],
		    default: 150
		},
		// 提示图片宽度
		chyWidth: {
		    type:  [Number,String],
		    default: 250
		},
		//提示图片链接
	    chyImageUrl: {
	      type: String,
	      default: 250
	    },
		//附加信息
		chyFormData:{
			type: Object,
			default: ()=>{	
			}
		}
	        
    }
}

组件使用代码

vue

userInfo是一个对象

userInfo: {
    state:0,
        
},
    formCustomer:{
        keyURL:'',
        tipImageUr:'提示默认图片'    
    }
	<u-form-item label="上传图片" prop="keyURL" borderBottom required="required"
							v-if="item.type==11">
							<block v-if="userInfo.state==0">
								<u--input v-model="formCustomer.keyURL" border="none"
									placeholder="图片地址" v-show="false">
								</u--input>
								<chy-upload maxCount="1" chyHeight="150" chyWidth="330"
									:chyImageUrl="formCustomer.tipImageUr" :chyFormData="userInfo"
									@imageClick="(val)=>{ formCustomer.keyURL=val}">
								</chy-upload>
							</block>
							<block v-else>
								<u--image
									:src="formCustomer.keyURL?formCustomer.keyURL:formCustomer.tipImageUr"
									mode="widthFix" width="330px" height="150px"></u--image>
							</block>
						</u-form-item>

效果图片如下

image.png

二下拉组件

vue代码

<template>
	<view class="ep-picker-box">
		<!-- 蒙版区域 开始 -->
		<view class="ep-mask-box" v-show="show" @click="show=false"></view>
		<!-- 蒙版区域 开始 -->

		<!-- 输入框区域 开始 -->
		<view class="ep-input-box" @click="openOptions" :class="{'disabled':disabled}">
			<view style="display: flex;align-items: center;min-height: 36px;">{{showLabel}}</view>
			<text v-if="!show" class="iconfont icon-xiala"></text>
			<text v-else class="iconfont icon-xialashang"></text>
		</view>
		<!-- 输入框区域 结束 -->

		<!-- 弹出的下拉区域 开始 -->
		<view v-show="show" class="ep-picker-content-wrap">
			<scroll-view class="ep-picker-content" :scroll-y="true">
				<!-- 展示下拉项列表 开始 -->
				<view v-for="item in options" :key="item[value_key]"
					:class="{'disabled':item.disabled,'active':value==item[value_key]}" class="option-item"
					@click="itemClick(item)">{{item[label_key]}}</view>
				<!-- 展示下拉项列表 结束 -->

				<!-- 下拉列表为空 开始 -->
				<view v-if="options.length==0" class="option-no-data">无数据</view>
				<!-- 下拉列表为空 结束 -->
			</scroll-view>
			<text class="triangle"></text>
		</view>
		<!-- 弹出的下拉区域 结束 -->
	</view>
</template>

<script>
	import props from './props.js'
	export default {
		name: 'ep-picker-box',
		
		data() {
			return {
				show: false,
				left: 0,
			}
		},
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
		model:{//https://cn.vuejs.org/v2/guide/components-custom-events.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6%E7%9A%84-v-model
		           prop:'value',
		           event:"valChange"
		       },
		methods: {
			//点击选中选项
			itemClick(item) {
				if (item.disabled) return

				//关闭
				this.show = false
				//修改v-model的值
				this.$emit('valChange', item[this.value_key])
				//将事件通知父组件
				this.$emit('change', item[this.value_key])
			},
			//展开选项
			openOptions() {
				if (!this.disabled) {
					this.show = true
				}
			}
		},
		computed: {
			showLabel() {
				var index = this.options.findIndex(item => {
					return item[this.value_key] == this.value
				})
				if (index != -1) {
					return this.options[index][this.label_key]
				} else if (!this.value) {
					return "请选择"
				} else {
					return this.value
				}
			}
		}

	}
</script>


<style scoped>
	/* 引入字体图标 */
	/*    @import './iconfont.css';
    */
	.ep-picker-box {
		width: 100%;
		box-sizing: border-box;
		position: relative;
		font-size: 14px;
		color: #333;
		/* max-width: 300px; */
	}

	.ep-mask-box {
		position: fixed;
		z-index: 999;
		top: 0;
		right: 0;
		left: 0;
		bottom: 0;
		background: none;
	}

	.ep-input-box {
		border: 1px solid rgb(229, 229, 229);
		border-radius: 4px;
		padding-left: 10px;
		position: relative;
		cursor: pointer;
	}

	/* 整个下拉组件禁用样式 */
	.ep-input-box.disabled {
		cursor: not-allowed;
		background-color: #f5f7fa;
		color: #999;
	}

	/* 展开收起箭头样式 */
	.ep-input-box .iconfont {
		position: absolute;
		top: 50%;
		right: 5px;
		font-size: 20px;
		transform: translateY(-50%);
		color: #B8B8B8;
	}

	/* 下拉容器样式 外层 */
	.ep-picker-content-wrap {
		width: 100%;
		position: absolute;
		top: 45px;
		left: 0;
		z-index: 9999;
		padding-top: 6px;
	}

	/* 下拉容器样式 内层 */
	.ep-picker-content-wrap .ep-picker-content {
		background-color: #fff;
		padding: 3px 0;
		box-shadow: 0 0 20px 5px rgb(0 0 0 / 30%);
		border-radius: 5px;
		max-height: 181px;
	}

	/* 下拉项通用样式 */
	.ep-picker-content-wrap .ep-picker-content .option-item {
		padding: 8px 18px;
		cursor: pointer;
	}

	/* 无下拉项数据时样式 */
	.ep-picker-content-wrap .ep-picker-content .option-no-data {
		padding: 8px 18px;
		cursor: text;
		color: #999;
		text-align: center;
	}

	/* 鼠标移入下拉项样式 */
	.ep-picker-content-wrap .ep-picker-content .option-item:hover {
		background-color: #f5f7fa;
	}

	/* 已选中的下拉项样式 */
	.ep-picker-content-wrap .ep-picker-content .option-item.active {
		color: #007AFF;
	}

	/* 禁用的下拉项样式 */
	.ep-picker-content-wrap .ep-picker-content .option-item.disabled {
		color: #c0c4cc;
	}

	.ep-picker-content-wrap .ep-picker-content .option-item.disabled:hover {
		cursor: not-allowed;
	}

	/* 下拉容器指示箭头样式 */
	.ep-picker-content-wrap .triangle {
		width: 0;
		height: 0;
		border-top: 6px solid rgba(0, 0, 0, 0);
		border-right: 6px solid rgba(0, 0, 0, 0);
		border-bottom: 6px solid #fff;
		border-left: 6px solid rgba(0, 0, 0, 0);
		position: absolute;
		top: -6px;
		left: 50%;
		transform: translateX(-50%);
		box-sizing: content-box;
	}
</style>

js代码

export default { //https://www.cnblogs.com/OrochiZ-/p/15910440.html
	props: {
		value: {
			type: [String, Number],
			default: ""
		},
		options: {
			type: Array,
			default: function() {
				return []
			}
		},
		value_key: {
			type: String,
			default: "value"
		},
		label_key: {
			type: String,
			default: "label"
		},
		disabled: {
			type: Boolean,
			default: false
		}
	}
}

组件使用页面代码

vue 代码

contractTemplateOptions: [
					 	{
					 	eqbTemplateId: "1",
					 	label: "上海"
					 }, {
					 	eqbTemplateId: "2",
					 	label: "深圳"
					 }, {
					 	eqbTemplateId: "3",
					 	label: "广州",
					 	
					 },
				]
			<u-form-item label="合同模板" prop="eqbTemplateId" ref="item1" borderBottom required>
						<ep-picker-box :disabled="signingDisabled" v-model="signingForm.eqbTemplateId"
							style="width:100%" :options="contractTemplateOptions" @change="change">
						</ep-picker-box>
					</u-form-item>

js 代码

	change(val) {
				this.signingForm.eqbTemplateId = val;
			},

效果图

image.png

这些组件还是很好用的。记录一下。