# 发贴评论功能
# 创建分包
在uniapp中添加分包,减少主包体积,提升页面加载的性能:
- 新增页面,
/subcom-pkg/post/post
加入基本的vue页面的结构
- 配置
pages.json
pages.json
中配置分包:
"subPackages": [
{
"root": "subcom-pkg",
"pages": [
...
{
"path": "post/post",
"style": {
"navigationBarTitleText": "发贴"
}
}
]
}
]
# 表单校验
使用uview中的form (opens new window)表单组件:
<template>
<view class="container">
<u-form :model="form" ref="uForm" label-width="0">
<u-form-item prop="title">
<u-input v-model="form.title" placeholder="请输入帖子标题" clearable></u-input>
</u-form-item>
<u-form-item prop="content">
<u-input v-model="form.content" placeholder="请输入帖子内容" type="textarea"></u-input>
</u-form-item>
<view class="upload-img">
<view class="prev">设置封面图片:</view>
<!-- 上传图片 -->
</view>
<u-form-item :label-position="labelPosition" label="发贴类型" label-width="140" prop="catalog">
<u-input class="right-text" type="select" :select-open="show1" v-model="form.catalog" placeholder="请选择发贴类型" @click="show1=true"></u-input>
<u-select v-model="show1" :list="list" @confirm="confirmType"></u-select>
</u-form-item>
<!-- </view> -->
<u-form-item label="奖励积分" label-width="140" prop="fav">
<u-input class="right-text" type="select" :select-open="show" v-model="form.fav" placeholder="请选择奖励积分" @click="show=true"></u-input>
<u-select v-model="show" :list="tempFavs" @confirm="confirmFav"></u-select>
</u-form-item>
</u-form>
<view class="btn">
<u-button size="default" type="primary" hover-class="none">发布</u-button>
</view>
</view>
</template>
加入表单校验:
- 配置
u-form
中的model
属性,ref
用于校验整个表单; - 配置
u-form-item
中的prop
属性,配置对应的rules规则 - 在script的
onReady
回调中配置this.$refs.uForm.setRules(this.rules)
<script>
export default {
components: {},
data: () => ({
show: false,
show1: false,
form: {
title: '',
content: '',
catalog: '',
fav: '',
snapshot: ''
},
rules: {
title: [
{
required: true,
message: '请输入标题',
// 可以单个或者同时写两个触发验证方式
trigger: ['blur']
}
],
content: [
{
required: true,
message: '请输入文章内容',
trigger: 'blur'
}
],
catalog: [
{
required: true,
message: '请选择发贴类型',
// 触发器可以同时用blur和change
trigger: ['change', 'blur']
}
],
fav: [
{
required: true,
message: '请选择积分',
trigger: ['change', 'blur']
}
]
},
list: [
{
value: '',
label: '请选择'
},
{
value: 'ask',
label: '提问'
},
{
value: 'share',
label: '分享'
},
{
value: 'discuss',
label: '讨论'
},
{
value: 'advise',
label: '建议'
}
],
listIndex: 0,
tempFavs: [
{
label: '请选择',
value: ''
},
{
label: '20',
value: 20
},
{
label: '30',
value: 30
},
{
label: '50',
value: 50
},
{
label: '100',
value: 100
}
],
favIndex: 0,
fileList: [],
disabledButton: true
}),
methods: {
confirmType (e) {
const index = this.list.findIndex(item => item.value === e[0].value)
this.listIndex = index
this.form.catalog = e[0].label
},
confirmFav (e) {
const index = this.tempFavs.findIndex(item => item.value === e[0].value)
this.favIndex = index
this.form.fav = e[0].label
},
addPost () {
this.$refs.uForm.validate(async valid => {
if (valid) {
// to do
} else {
console.log('验证失败')
}
})
}
},
onReady () {
this.$refs.uForm.setRules(this.rules)
}
}
</script>
# 图片上传
# 上传接口
上传formdata类型的数据,需要使用uni.uploadFile API,封装成一个promise谅,在complete中加入callback,方便后续的处理:
// 图片上传接口
const uploadImg = (params, callback) => {
return new Promise((resolve, reject) => {
uni.uploadFile({
url: baseUrl + '/content/upload', // 仅为示例,非真实的接口地址
filePath: params,
name: 'file',
header: {
'Content-Type': 'multipart/form-data',
authorization: 'Bearer ' + store.state.token
},
formData: {
// 'user': 'test'
},
success: (uploadFileRes) => {
resolve(uploadFileRes)
},
fail: (err) => {
reject(err)
},
complete: (res) => {
callback && callback(res)
}
})
})
}
// 发贴接口
const addPost = (data) => axios.post('/content/wxAdd', data)
# 页面结构
可以使用u-upload (opens new window)组件来轻松实现图片上传:
<template>
<view class="container">
<u-form :model="form" ref="uForm" label-width="0">
<u-form-item prop="title">
<u-input v-model="form.title" placeholder="请输入帖子标题" clearable></u-input>
</u-form-item>
<u-form-item prop="content">
<u-input v-model="form.content" placeholder="请输入帖子内容" type="textarea"></u-input>
</u-form-item>
<view class="upload-img">
<view class="prev">设置封面图片:</view>
<u-upload ref="uUpload" :file-list="fileList" action="#" :auto-upload="false" @on-list-change="uploadImg" multiple :max-size="5 * 1024 * 1024" max-count="1" />
</view>
<u-form-item :label-position="labelPosition" label="发贴类型" label-width="140" prop="catalog">
<u-input class="right-text" type="select" :select-open="show1" v-model="form.catalog" placeholder="请选择发贴类型" @click="show1=true"></u-input>
<u-select v-model="show1" :list="list" @confirm="confirmType"></u-select>
</u-form-item>
<!-- </view> -->
<u-form-item label="奖励积分" label-width="140" prop="fav">
<u-input class="right-text" type="select" :select-open="show" v-model="form.fav" placeholder="请选择奖励积分" @click="show=true"></u-input>
<u-select v-model="show" :list="tempFavs" @confirm="confirmFav"></u-select>
</u-form-item>
</u-form>
<view class="btn">
<u-button size="default" type="primary" @click="addPost" hover-class="none">发布</u-button>
</view>
</view>
</template>
<script>
import { authNav } from '@/common/checkAuth'
export default {
data: () => ({
// ...
fileList: [],
}),
methods: {
// ....
async uploadImg (lists, name) {
if (lists.length > 0) {
const res = await this.$u.api.uploadImg(lists[0].url)
if (res.statusCode === 401) {
await authNav('登录已失效,图片上传失败,请登录后重传!')
this.$refs.uUpload.clear()
}
if (res.statusCode === 200) {
const { data } = res
const { code, msg, data: url } = JSON.parse(data)
if (code === 200) {
this.form.snapshot = url
}
uni.showToast({
icon: 'none',
title: msg,
duration: 2000
})
}
}
},
// ...
},
}
</script>
# 完成效果
<template>
<view class="container">
<u-form :model="form" ref="uForm" label-width="0">
<u-form-item prop="title">
<u-input v-model="form.title" placeholder="请输入帖子标题" clearable></u-input>
</u-form-item>
<u-form-item prop="content">
<u-input v-model="form.content" placeholder="请输入帖子内容" type="textarea"></u-input>
</u-form-item>
<view class="upload-img">
<view class="prev">设置封面图片:</view>
<u-upload ref="uUpload" :file-list="fileList" action="#" :auto-upload="false" @on-list-change="uploadImg" multiple :max-size="5 * 1024 * 1024" max-count="1" />
</view>
<u-form-item :label-position="labelPosition" label="发贴类型" label-width="140" prop="catalog">
<u-input class="right-text" type="select" :select-open="show1" v-model="form.catalog" placeholder="请选择发贴类型" @click="show1=true"></u-input>
<u-select v-model="show1" :list="list" @confirm="confirmType"></u-select>
</u-form-item>
<!-- </view> -->
<u-form-item label="奖励积分" label-width="140" prop="fav">
<u-input class="right-text" type="select" :select-open="show" v-model="form.fav" placeholder="请选择奖励积分" @click="show=true"></u-input>
<u-select v-model="show" :list="tempFavs" @confirm="confirmFav"></u-select>
</u-form-item>
</u-form>
<view class="btn">
<u-button size="default" type="primary" @click="addPost" hover-class="none">发布</u-button>
</view>
</view>
</template>
<script>
import { mapMutations } from 'vuex'
import { authNav } from '@/common/checkAuth'
export default {
components: {},
data: () => ({
show: false,
show1: false,
form: {
title: '',
content: '',
catalog: '',
fav: '',
snapshot: ''
},
rules: {
title: [
{
required: true,
message: '请输入标题',
// 可以单个或者同时写两个触发验证方式
trigger: ['blur']
}
],
content: [
{
required: true,
message: '请输入文章内容',
trigger: 'blur'
}
],
catalog: [
{
required: true,
message: '请选择发贴类型',
// 触发器可以同时用blur和change
trigger: ['change', 'blur']
}
],
fav: [
{
required: true,
message: '请选择积分',
trigger: ['change', 'blur']
}
]
},
list: [
{
value: '',
label: '请选择'
},
{
value: 'ask',
label: '提问'
},
{
value: 'share',
label: '分享'
},
{
value: 'discuss',
label: '讨论'
},
{
value: 'advise',
label: '建议'
}
],
listIndex: 0,
tempFavs: [
{
label: '请选择',
value: ''
},
{
label: '20',
value: 20
},
{
label: '30',
value: 30
},
{
label: '50',
value: 50
},
{
label: '100',
value: 100
}
],
favIndex: 0,
fileList: [],
disabledButton: true
}),
computed: {
},
methods: {
...mapMutations(['setPage']),
confirmType (e) {
const index = this.list.findIndex(item => item.value === e[0].value)
this.listIndex = index
this.form.catalog = e[0].label
},
confirmFav (e) {
const index = this.tempFavs.findIndex(item => item.value === e[0].value)
this.favIndex = index
this.form.fav = e[0].label
},
async uploadImg (lists, name) {
if (lists.length > 0) {
const res = await this.$u.api.uploadImg(lists[0].url)
if (res.statusCode === 401) {
await authNav('登录已失效,图片上传失败,请登录后重传!')
this.$refs.uUpload.clear()
}
if (res.statusCode === 200) {
const { data } = res
const { code, msg, data: url } = JSON.parse(data)
if (code === 200) {
this.form.snapshot = url
}
uni.showToast({
icon: 'none',
title: msg,
duration: 2000
})
}
}
},
addPost () {
this.$refs.uForm.validate(async valid => {
if (valid) {
const data = {
...this.form,
catalog: this.list[this.listIndex].value,
fav: this.tempFavs[this.favIndex].value
}
const { code, msg, data: res } = await this.$u.api.addPost(data)
// console.log('🚀 ~ file: post.vue ~ line 157 ~ addPost ~ res', res)
if (code === 200 && res._id) {
uni.showToast({
icon: 'none',
title: msg,
duration: 2000
})
uni.navigateBack()
} else {
// 内容审核提示
if (code === 500 && /内容安全/.test(msg)) {
uni.showModal({
title: '注意文明用语',
content: '发布内容没有通过内容审核,请检查后重新提效',
showCancel: false,
success: function (res) {
console.log(res)
}
})
return
}
uni.showToast({
icon: 'none',
title: msg,
duration: 2000
})
}
} else {
console.log('验证失败')
}
})
}
},
onReady () {
this.$refs.uForm.setRules(this.rules)
}
}
</script>
<style lang="scss" scoped>
.container {
padding: 32rpx;
}
::v-deep .edit-post {
position: relative;
textarea {
max-height: 400rpx;
}
.u-clear-icon {
position: absolute;
right: 10rpx;
bottom: 30rpx;
}
}
.btn {
margin-top: 60rpx;
}
::v-deep .right-text {
.u-input__input {
text-align: end;
padding-right: 15rpx;
}
}
.prev {
padding: 15rpx 0 30rpx;
}
</style>
完成效果:
