前言:
常见的一些UI组件库都是只能提前选择发布图片或者发布视频,我觉得在发布前还要选择一下,挺麻烦的。虽然微信朋友圈也是这么做的吧。我希望的是,直接进入发布页,如果没有选择图片或者视频,也可以直接发布文字,选择媒体的话支持拍照、图片、视频三个选项。如果选择了图片,就不能选择视频,如果选择了视频就不能选择图片。且图片最多选择9张,视频最多选择一个。下面将分享实际思路实现以及参考代码(完整代码在本文末尾)
思路:
- 页面放置相机icon,绑定点击事件
- 使用uni.showActionSheet从下弹出选择菜单,模拟微信
- 配置拍照,从相册选择照片,从相册选择视频三个选项
- 编写每个选项具体的操作方法
- 实现最多选择9张照片
- 实现最多选择1个视频
- 实现选择位置功能
一步步介绍思路的话,我觉得文字的话有点冗余,不过我还是尽量把思路分享出来,让大家更好的理解不使用组件自定义的去实现。大概思路如上所诉,接下来拆解思路分析重要方法
每一个步骤的思路都有对应的uni的方法,我先把主要方法介绍一下
大概看看思路得了,要完整的理解看完思路看完整代码
主要步骤实现:
- 从下显示操作菜单
文档链接:https://uniapp.dcloud.net.cn/api/ui/prompt.html#showactionsheet
这里主要实现菜单三个选项。然后后续针对三个选项单独去写具体调用的操作
- 选择媒体
文档链接:https://uniapp.dcloud.net.cn/api/media/image.html#chooseimage
- 控制最多9张图的选择以及最多一个视频的选择
思路:上图中调用选择图片的接口,有一个count参数,用来控制本次选择最多选择几张图片
只需要在每次选择图片的时候用 9 减去 已经存在的图片数量即可。然后选择图片那个相机的
view只需要v-if一下。媒体列表的长度小于9就显示就行了。图片到了9张就消失了。
至于相机的话,看我画框的右边那个 form.video。意思就是如果有视频的话,这玩意也消失了
注意:form.video只是一个判断的变量,临时地址我还是存imageList中的。为了v-for遍历...
具体代码部分展示:
data() {
return {
inputFocus: true,
form: {
imageList: [],
},
}
},
uni.chooseImage({
count: 9 - that.form.imageList.length,
sourceType: ['album'], //从相册选择
)}
- 总结
还有一个重要的事情需要注意,就是如果选择了图片,再次点击相机按钮弹起的选择操作菜单
就没有了“从相册选择视频了”。如果选择了视频的话,相机按钮,也会消失。也就是只能选择一个视频。
选择了9张图那个按钮也会消失。
所以拍照的话,你拍一张就会push一张到imageList中。
到了9张按钮消失。你也没办法弹那个操作菜单了。以上的话基本功能的思想就完成了。
示例图(如果选择了一张图片,再次点击相机按钮,就不会出现选择视频了)
以上示例图主要靠一个三目来解决
let itemL = that.form.imageList.length!=0 ? !that.form.imageList.video ? ['拍照', '从相册选择照片']: '' : ['拍照', '从相册选择照片', '从相册选择视频']
完整代码以及截图:
- 完整样式截图
PS:这个确定发布实在太丑了,写完这篇文章,马上就改。然后下面做几个无分隔选择菜单。
选择一下其他的东西(选择圈子、选择话题等)
template:
<template>
<view class="content">
<view class="container">
<!-- 输入框 -->
<textarea placeholder="想说什么就说什么叭- -" @blur="inputBlur" :focus="inputFocus" :auto-height="true"
:show-confirm-bar="false" maxlength="1500" v-model="form.content" class="post-txt"></textarea>
<!-- 上传图片or视频 -->
<view class="img-list">
<view v-for="(item,index) in form.imageList" :key='index' class="img-list-box">
<image v-if="!form.video" :src="item" class="img-item" @tap="imgTypeSelect(item)"></image>
<video v-else :src="item" @longpress="videoTypeSelect(item)"></video>
</view>
<view v-if="form.imageList.length < 9 && !form.video" class="icon-camera" @tap="selectType">
<uni-icons type="camera-filled" size="27" color=#D3D4D6></uni-icons>
</view>
</view>
<!-- 选择位置 -->
<view @click="chooseLocation" class="choose-location">
<u-icon name="map" size="30rpx"></u-icon>
<text class="txt">{{ form.address || '你在哪里?' }}</text>
</view>
</view>
<!-- 选择板块 -->
<!-- 底部确定按钮 -->
<view @click="clickCreate" class="yue-base-button">
<view>确定发布~</view>
</view>
</view>
</template>
script:
<script>
export default {
data() {
return {
// 默认输入框获得焦点
inputFocus: true,
form: {
content: '',
address: '',
imageList: [],
video: '',
},
}
},
methods: {
// 选择媒体类型
selectType() {
let that = this
let itemL = that.form.imageList.length!=0 ? !that.form.imageList.video ? ['拍照', '从相册选择照片']: '' : ['拍照', '从相册选择照片', '从相册选择视频']
uni.showActionSheet({
itemList: itemL,
success: function(res) {
if (res.tapIndex == 0) {
uni.chooseImage({
sourceType: ['camera'], // 拍照选择
success: function(res) {
that.form.imageList.push(res.tempFilePaths)
}
});
}
if (res.tapIndex == 1) {
uni.chooseImage({
count: 9 - that.form.imageList.length,
sourceType: ['album'], //从相册选择
success: function(res) {
res.tempFilePaths.forEach(path => {
that.form.imageList.push(path);
// 发给oss 待写
})
}
});
}
if (res.tapIndex == 2) {
uni.chooseVideo({
sourceType: ['album'], // 从相册选择视频
success: function(res) {
if (res.size > 20971520) {
uni.showToast({
title: "视频文件过大",
duration: 2000
});
return;
}
that.form.video = true;
that.form.imageList.push(res.tempFilePath)
}
});
}
}
});
},
// 图片状态选择
imgTypeSelect(item) {
let that = this
uni.showActionSheet({
itemList: ['预览', '删除'],
success: function(res) {
if (res.tapIndex == 0) {
uni.previewImage({
current: item,
urls: that.form.imageList
})
}
if (res.tapIndex == 1) {
let index = that.form.imageList.findIndex(url => url === item);
if (index !== -1) {
that.form.imageList.splice(index, 1);
}
}
}
});
},
// 视频状态选择
videoTypeSelect(){
uni.showActionSheet({
itemList: ['删除'],
success: function(res) {
if (res.tapIndex == 0) {
let index = that.form.imageList.findIndex(url => url === item);
if (index !== -1) {
that.form.imageList.splice(index, 1);
}
}
}
});
},
// 文字内容
inputBlur(event) {
this.inputCursor = event.detail.cursor;
this.inputFocus = false;
},
// 位置选择
chooseLocation() {
let that = this;
uni.chooseLocation({
success: function(res) {
that.form.address = res.name;
}
});
},
// 发布
clickCreate() {
console.log(this.form);
if (!this.form.content) {
uni.showToast({
title: "请输入内容噢",
icon: "error"
})
return;
}
this.$request.post("/api/article/save", {
"type": 1,
"content": this.form.content,
}).then((res) => {
if (res.message == '保存成功') {
uni.showToast({
title: '发布成功',
duration: 1500,
mask: true
});
setTimeout(() => {
uni.redirectTo({
url: '/pages/community/community'
});
}, 1500)
}
})
},
}
}
</script>
<style lang="scss" scoped>
.content {
height: 100vh;
background-color: #FFFFFF;
border-radius: 30upx 30upx 0upx 0upx;
}
.container {
padding: 20rpx 40rpx;
overflow: hidden;
}
.post-txt {
width: 100%;
min-height: 300rpx;
line-height: 1rpx;
}
/* 选择位置 */
.choose-location {
display: inline-flex;
align-items: center;
background-color: #eee;
font-size: 28rpx;
border-radius: 100rpx;
padding: 10rpx 20rpx;
margin-left: 5rpx;
line-height: 1;
color: #616161;
.txt {
margin-left: 10rpx;
}
}
.yue-base-button {
position: fixed;
display: flex;
align-items: center;
justify-content: center;
bottom: 0;
width: 100%;
padding: 40rpx 0;
z-index: 3;
}
.yue-base-button view {
width: 560rpx;
text-align: center;
height: 96rpx;
line-height: 96rpx;
border-radius: 96rpx;
font-size: 32rpx;
font-weight: 400;
color: #FFFFFF;
background: #07C062;
}
// 相机icon
.icon-camera {
display: flex;
justify-content: center;
align-items: center;
width: 210rpx;
height: 210rpx;
border-radius: 6rpx;
margin: 5rpx 0rpx 0rpx 5rpx;
background-color: #f4f5f7;
}
// 媒体列表
.img-list {
display: flex;
flex-wrap: wrap;
margin-bottom: 20rpx;
}
.img-list-box {
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.img-item {
width: 210rpx;
height: 210rpx;
margin: 5rpx;
border-radius: 6rpx
}
</style>
以上代码复制过去就能跑。觉得对你思路有帮助的。支持赞一下~