uni-app 17朋友圈开发

Posted 2019ab

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uni-app 17朋友圈开发相关的知识,希望对你有一定的参考价值。

不废话,直接看效果图

下面是实现代码

moments.nvue

<template>
	<view>
		<free-transparent-bar :scrollTop="scrollTop"></free-transparent-bar>
		<view class="position-relative" style="height: 620rpx;">
			<image src="https://douyinzcmcss.oss-cn-shenzhen.aliyuncs.com/shengchengqi/datapic/1.jpg" mode="aspectFill" style="height: 590rpx;" class="bg-secondary w-100"></image>
			<image src="/static/images/demo/demo6.jpg" style="width: 120rpx;height:120rpx;right: 30rpx;" mode="" class="bg-secondary rounded position-absolute bottom-0"></image>
			<text class="text-white font-md position-absolute" style="bottom: 45rpx;right: 160rpx">Summer</text>
		</view>
		
		<!-- 朋友圈列表样式 -->
		<free-moment-list v-for="(item,index) in list" :key='index' :item="item" :index="index" @action="doAction"></free-moment-list>
		
		<!-- 评论框 -->
		<free-popup ref="action" bottom transformOrigin="center bottom">
			<view style="height: 105rpx;" class="bg-light border-top flex align-center">
				<textarea fixed class="bg-white rounded p-2 font-md" style="height: 75rpx;width: 520rpx;" value="" placeholder=""  v-model="content" :focus="true"/>
				<free-icon-button @click="changeFaceModeal"><text class="iconfont font-lg">&#xe605;</text></free-icon-button>
				<free-main-button name="发送" :disabled="content.length===0" @click="send"></free-main-button>
			</view>
			
			<!-- 表情包 -->
			<scroll-view v-if="faceModal" scroll-y="true" style="height: 350rpx;" class="bg-light flex flex-wrap">
				<view class="flex align-center justify-center" hover-class="bg-white" style="width:107rpx;height:107rpx;" v-for="(item,index) in faceList" :key="index" @click="addFace(item)">
					<text>{{item}}</text>
				</view>
			</scroll-view>
		</free-popup>
		
	</view>
</template>

<script>
	import freeTransparentBar from '@/components/free-ui/free-transparent-bar.vue';
	import freeMomentList from '@/components/free-ui/free-moment-list.vue';
	import freePopup from '@/components/free-ui/free-popup.vue';
	import freeIconButton from '@/components/free-ui/free-icon-button.vue';
	import freeMainButton from '@/components/free-ui/free-main-button.vue';
	export default {
		components:{
			freeTransparentBar,
			freeMomentList,
			freePopup,
			freeIconButton,
			freeMainButton
		},
		data() {
			return {
				content:'',
				scrollTop:0,
				faceModal:false,
				faceList:["😀","😁","😂","😃","😄","😅","😆","😉","😊","😋","😎","😍","😘","😗","😙","😚","😇","😐","😑","😶","😏","😣","😥","😮","😯","😪","😫","😴","😌","😛","😜","😝","😒","😓","😔","😕","😲","😷","😖","😞","😟","😤","😢","😭","😦","😧","😨","😬","😰","😱","😳","😵","😡","😠"],
				commentIndex:-1,
				list:[{
					id:2,
					avatar:'/static/images/demo/demo6.jpg',
					username:'昵称',
					context:'靓仔,靓仔',
					image:[],
					video:false,
					create_time:1567481668,
					supports:[{
						id:1,
						username:'昵称',
						avatar:'/static/image/demo/demo6.jpg'
					}],
					comments:[{
						id:1,
						username:'昵称',
						content:'评论内容'
					}]
				},
				{
					id:2,
					avatar:'/static/images/demo/demo6.jpg',
					username:'昵称',
					context:'靓仔,靓仔',
					image:['https://douyinzcmcss.oss-cn-shenzhen.aliyuncs.com/shengchengqi/datapic/1.jpg'],
					video:false,
					create_time:1567481668,
					supports:[],
					comments:[]
				},
				{
					id:2,
					avatar:'/static/images/demo/demo6.jpg',
					username:'昵称',
					context:'靓仔,靓仔',
					image:['https://douyinzcmcss.oss-cn-shenzhen.aliyuncs.com/shengchengqi/datapic/1.jpg','https://douyinzcmcss.oss-cn-shenzhen.aliyuncs.com/shengchengqi/datapic/1.jpg'],
					video:false,
					create_time:1567481668,
					supports:[],
					comments:[]
				},
				{
					id:2,
					avatar:'/static/images/demo/demo6.jpg',
					username:'昵称',
					context:'靓仔,靓仔',
					image:[],
					video:{src:'/static/video/demo.mp4',poster:'https://douyinzcmcss.oss-cn-shenzhen.aliyuncs.com/shengchengqi/datapic/1.jpg'},
					create_time:1567481668,
					supports:[],
					comments:[]
				}],
			}
		},
		onPageScroll(e) {
			this.scrollTop = e.scrollTop;
		},
		methods: {
			// 点击操作菜单
			doAction(e){
				uni.showActionSheet({
					itemList: ['点赞','评论'],
					success: res => {
						if(res.tapIndex === 0){
							// 点赞
							this.doSupport(e)
						}else{
							this.content='';
							this.faceModal=false;
							this.commentIndex = e.index;
							this.$refs.action.show();
							// this.doComment(e)
						}
					}
				});
			},
			// 点赞
			doSupport(e){
				e.item.supports.push({
						id:1,
						username:'昵称',
						avatar:'/static/image/demo/demo6.jpg'
				});
			},
			// 添加表情
			addFace(item){
				this.content += item;
			},
			// 开启关闭表情包面板
			changeFaceModeal(){
				uni.hideKeyboard();
				setTimeout(()=>{
					this.faceModal = !this.faceModal;
				},100);
			},
			// 发送
			send(){
				this.list[this.commentIndex].comments.push({
					id:1,
					username:'昵称',
					content:this.content
				})
				this.$refs.action.hide();
			}
		},
	}
</script>

<style>

</style>

涉及的引入文件

// free-transparent-bar.vue
<template>
	<view>
		<view class="fixed-top" :style="navBarStyle">
			<!-- 状态栏 -->
			<view :style="'height:'+statusBarHeight+'px;'"></view>
			<!-- 导航 -->
			<view class="w-100 flex align-center justify-between" style="height: 90rpx;">
				<!-- 左边 -->
				<view class="flex align-center">
					<!-- 返回按钮 -->
					<view class="flex align-center justify-center"
					hover-class="bg-hover-light" @click="back"
					style="height: 90rpx;width: 90rpx;">
						<text class="iconfont font-md" :style="buttonStyle">&#xe60d;</text>
					</view>
					<!-- 标题 -->
					<text v-if="title" class="font-md ml-3" >{{title}}</text>
				</view>
				<!-- 右边 -->
				<view class="flex align-center">
					<view class="flex align-center justify-center"
					hover-class="bg-hover-light"
					style="height: 90rpx;width: 90rpx;">
						<text class="iconfont font-md" :style="buttonStyle">&#xe682;</text>
					</view>
				</view>
			
				<!--\\ue6e3 \\ue682 -->
			</view>
		</view>

	</view>
</template>

<script>
	export default {
		components: {
		},
		props: {
			title: {
				type: String,
				default: ''
			},
			scrollTop:{
				type:[String,Number],
				default:0
			}
		},
		data() {
			return {
				statusBarHeight: 0,
				navBarHeight: 0,
			}
		},
		mounted() {
			// 获取任务栏高度
			// #ifdef APP-PLUS-NVUE
			this.statusBarHeight = plus.navigator.getStatusbarHeight()
			// #endif
			this.navBarHeight = this.statusBarHeight + uni.upx2px(90)
		},
		computed: {
			// 变化0-1
			changeNumber(){
				let start = uni.upx2px(500);
				let end = uni.upx2px(620);
				let H = end - start;
				let num = 0;
				if(this.scrollTop > start){
					num = (this.scrollTop - start)/H;
				}
				return num > 1 ? 1 : num;
			},
			navBarStyle(){
				return `background-color:rgba(255,255,255,${this.changeNumber});`
			},
			buttonStyle(){
				if(this.changeNumber>0){
					return `color:rgba(0,0,0,${this.changeNumber})`;
				}
				return 'color:#FFFFFF;'
			}
		},
		methods:{
			// 返回
			back(){
				uni.navigateBack({
					delta:1
				})
			}
		}
	}
</script>

<style>

</style>

// free-moment-list.vue
<template>
	<view class="p-3 flex align-start border-bottom border-light-secondary">
		<free-avatar :src='item.avatar' size="80"></free-avatar>
		<view class="pl-2 flex-1 flex flex-column">
			<!-- 昵称 -->
			<text class="font-md text-hover-primary">{{item.username}}</text>
			<!-- 内容 -->
			<text class="font-md text-dark mb-1">{{item.context}}</text>
			<!-- 图片 -->
			<view v-if="item.image.length" class="py-2 flex flex-wrap">
				<block v-for="(image,imageIndex) in item.image" :key='imageIndex'>
					<!-- 单图 -->
					<free-image v-if="item.image.length==1" :src="item.image[imageIndex]" imageClass='rounded' @click="preview(image)"></free-image>
					<free-image v-else :src="item.image[imageIndex]" imageClass='rounded' mode="aspectFill" style="width: 180rpx;height: 180rpx;" class="bg-secondary mr-2 mb-2" @click="preview(image)"></free-image>
				</block>
			</view>
			<!-- 视频 -->
			<view class="py-2" v-if="item.video">
				<video :src="item.video.src" :poster="item.video.poster" controls style="height: 300rpx;width: 500rpx;" loop></video>
			</view>
			<!-- 时间|操作 -->
			<view class="flex align-center justify-between">
				<text class="font-sm text-light-muted">{{item.create_time|formatTime}}</text>
				<view class="rounded p-1 bg-light" @click="$emit('action',{item,index})">
					<text class="text-hover-primary iconfont font">&#xe62a;</text>
				</view>
			</view>
			<!-- 点赞列表,评论列表 -->
			<view class="bg-light mt-2" v-if="item.supports.length || item.comments.length">
				<!-- 点赞 -->
				<view v-if="item.supports.length" class="border-bottom flex align-start p-2">
					<text class="flex-shrink iconfont font text-hover-primary">&#xe637;</text>
					<view class="flex flex-wrap flex-1 ml-1">
						<text v-for="(s,si) in item.supports" :key='si' class="font text-hover-primary ml-1">{{s.username}}</text>
					</view>
				</view>
				<!-- 评论 -->
				<view v-if="item.comments.length" class="border-bottom flex align-start p-2">
					<text class="flex-shrink iconfont font-md text-hover-primary">&#xe64e;</text>
					<view class="flex flex-column flex-wrap flex-1 ml-2">
						<view class="flex" v-for="(c,ci) in item.comments" :key="ci">
							<text class="text-hover-primary font">{{c.username}}:</text>
							<text class="font text-dark flex-1">{{c.content}}</text>
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	import freeAvatar from '@/components/free-ui/free-avatar.vue';
	import freeImage from '@/components/free-ui/free-image.vue';
	import $T from '@/common/free-lib/time.js';
	export default {
		components:{
			freeAvatar,
			freeImage
		},
		filters:{
			formatTime(value){
				return $T.gettime(value);
			}
		},
		props:{
			item:Object,
			index:Number
		},
		methods:{
			// 查看大图
			preview(src){
				uni.previewImage({
					current:src,
					urls:this.item.image
				})
			}
		}
	}
</script>

<style>
</style>

// free-popup.vue
<template>
	<div style="z-index:9999;overflow:hidden;" v-if="status">
		<!-- 蒙版 -->
		<view v-if="mask" class="position-fixed top-0 left-0 right-0 bottom-0" :style="getMaskColor"  @click="hide"></view>
			<!-- 弹出框内容 -->
			<div ref="popup" class="position-fixed free-animated" :class="getBodyClass" :style="getBodyStyle">
		      <slot></slot>	
			</div>
	</div>
</template>

<script>
	// #ifdef APP-PLUS-NVUE
		const animation = weex.requireModule('animation');
	// #endif
	
	export default {
		props: {
			// 是否开启蒙版颜色
			maskColor: {
				type: Boolean,
				default: false
			},
			// 是否开启蒙版
			mask:{
				type:Boolean,
				default:true
			},
			// 是否居中
			center:{
				type:Boolean,
				default:false
			},
			// 是否处于底部
			bottom:{
				type:Boolean,
				default:false
			},
			// 弹出层内容高度
			bodyHeight:{
				type:Number,
				default:0
			},
			// 弹出层内容宽度
			bodyWidth:{
				type:Number,
				default:0
			},
			bodyBgColor:{
				type:String,
				default:'bg-white'
			},
			transformOrigin:{
				type:String,
				default:'left top'
			},
			// tabbar高度
			tabbarHeight:{
				type:Number,
				default:0
			}
		},
		data() {
			return {
				status: false,
				x:-1,
				y:1,
				maxX:0,
				maxY:0
			}
		},
		mounted() {
			try {
			    const res = uni.getSystemInfoSync();
				this.maxX = res.windowWidth - uni.upx2px(this.bodyWidth)
				this.maxY = res.windowHeight - uni.upx2px(this.bodyHeight) - uni.upx2px(this.tabbarHeight)
			} catch (e) {
			    // error
			}
		},
		computed: {
			getMaskColor() {
				let i = this.maskColor ? 0.5 : 0
				return `background-color: rgba(0,0,0,${i});` 
			},
			getBodyClass(){
				if(this.center){
					return 'left-0 right-0 bottom-0 top-0 flex align-center justify-center';
				}
				let bottom = this.bottom ? 'left-0 right-0 bottom-0' : 'rounded border'
				return `${this.bodyBgColor} ${bottom}`;
			},
			getBodyStyle(){
				let left = this.x > -1 ? `left:${this.x}px;` : ''
				let top = this.y > -1 ? `top:${this.y}px;` : ''
				return left + top
			}
		},
		methods:{
			show(x=-1,y=-1){
				if(this.status){
					return;
				}
				this.x = (x > this.maxX) ? this.maxX : x;
				this.y = (y > this.maxY) ? this.maxY : y;
				
				this.status = true
				// #ifdef APP-PLUS-NVUE
				this.$nextTick(()=>{
					animation.transition(this.$refs.popup,{
						styles:{
							transform:'scale(1,1)',
							transformOrigin:this.transformOrigin,
							opacity:1
						},
						duration:100, //ms
						timingFunction:'ease',
					},()=>{
						console.log('动画执行结束');
					})
				})
				// #endif
			},
			hide(){
				this.$emit('hide');
				// #ifdef APP-PLUS-NVUE
				this.$nextTick(()=>{
					animation.transition(this.$refs.popup,{
						styles:{
							transform:'scale(0,0)',
							transformOrigin:this.transformOrigin,
							opacity:0
						},
						duration:100, //ms
						timingFunction:'ease',
					},()=>{
						this.status = false;
					})
				})
				// #endif
			}
		}
	}
</script>

<style scoped>
	.free-animated{
		/* #ifdef APP-PLUS-NVUE */
		/* transform: scale(0,0);
		opacity: 0; */
		/* #endif */
	}
	.z-index{
		/* #ifndef APP-NVUE */
		z-index: 9999;
		/* #endif */
	}
</style>

// free-icon-button.vue
<template>
	<view class="flex align-center justify-center" 
	hover-class="bg-hover-light" @click="$emit('click')"
	style="height: 90rpx;width: 90rpx;">
		<slot></slot>
	</view>
</template>

<script>
	export default {
		props: {
			icon: {
				type: String,
				default: ''
			},
		},
		mounted() {
			// #ifdef APP-PLUS-NVUE
			// 加载公共图标库
			const domModule = weex.requireModule('dom')
			domModule.addRule('fontFace', {
			    'fontFamily': "iconfont",
			    'src': "url('/static/font_1365296_2ijcbdrmsg.ttf')"
			});
			// #endif
		}
	}
</script>

<style>
</style>
// free-main-button.vue
<template>
	<view class="rounded mr-2 px-2 py-1"
	@click="clickEvent"
	:class="disabled ? 'bg-light border' : 'main-bg-color'">
		<text class="font"
		:class="disabled ? 'text-light-muted':'text-white'">{{name}}</text>
	</view>
</template>

<script>
	export default {
		props: {
			name: {
				type: String,
				default: ""
			},
			disabled:{
				type:Boolean,
				default:false
			}
		},
		methods: {
			clickEvent() {
				if(!this.disabled){
					this.$emit('click')
				}
			}
		},
	}
</script>

<style>
</style>

感谢大家观看,我们下期见。

以上是关于uni-app 17朋友圈开发的主要内容,如果未能解决你的问题,请参考以下文章

uni-app 146朋友圈列表api开发

uni-app 144评论朋友圈api开发

uni-app 139发布朋友圈api开发

uni-app 140发布朋友圈api开发

uni-app 142点赞朋友圈api开发

uni-app 147我的朋友圈列表api开发