使用uniapp开发社区交友网站的项目教程

uniapp社区交友开发前端模块开发

源码可以提供下载,详情访问末尾码云地址

环境搭建和创建项目

开发环境搭建

  • 使用HubilderX
  • 安装对应插件

创建uniapp项目

  • 创建项目(名称:社区交友)
  • 真机调试或微信开发者工具调试

App.vue引入全局公共样式

引入官方css样式库

  • 新建模板项目hello uniapp

  • 复制模板common下的css

  • 在本项目的app.vue进行引入css文件 @import “./common/uni.css ” (还要引入uni.tff文件,否则报错)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xizHMjdI-1649380676444)(uniapp社区交友开发.assets/image-20220322164136184-16479384973031.png)]

引入自定义图标

  • 阿里巴巴矢量图标库 https://www.iconfont.cn/

  • 下载所选图标至项目打包 得到压缩文件

  • 修改icon.css文件去掉url,引入文件 测试图标使用

    <view>
    		<text class="iconfont icon-smile" style="font-size: 100rpx; color: red;"></text>
    </view>
    

引入css动画库

  • 下载animate.css

  • 引入animate.css

  • 测试css动画库的使用

    <view style="display: flex;justify-content: center;padding: 50rpx;"> 
    			<view class="" hover-class=" animated rubberBand" style="border: 1rpx solid black; padding: 20rpx;">
    				点击效果
    			</view>
    		</view>
    

设置全局属性globalStyle

  • 解析page.json文件 看官方文档

  • 设置导航栏的样式

    "globalStyle": {
    		"navigationBarTextStyle": "black", //导航栏字体颜色
    		"navigationBarTitleText": "社区交友",//导航栏文字
    		"navigationBarBackgroundColor": "#FFF",//背景颜色
    		"backgroundColor": "#FFF"
    	}
    

底部导航开发

  • 设置图标(图片为png,81*81)用矢量图标库下载

  • 配置tabBar前提要配置pages数组页面

    "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
    		{
    			"path": "pages/index/index",
    			"style": {
    			}
    		}
    	    ,{
                "path" : "pages/news/news",
                "style" :                                                                                    
                {
                    "navigationBarTitleText": "",
                    "enablePullDownRefresh": false
                }
                
            }
            ,{
                "path" : "pages/msg/msg",
                "style" :                                                                                    
                {
                    "navigationBarTitleText": "",
                    "enablePullDownRefresh": false
                }
                
            }
            ,{
                "path" : "pages/my/my",
                "style" :                                                                                    
                {
                    "navigationBarTitleText": "",
                    "enablePullDownRefresh": false
                }
                
            }
        ],
    
    
    "tabBar": {
    		"color": "#323232",
    		"selectedColor": "#FC5C82",
    		"backgroundColor": "#FFF",
    		"borderStyle": "black",
    		"list": [
    			{
    				"pagePath": "pages/index/index",
    				"text": "首页",
    				"iconPath": "static/tabbar/index.png",
    				"selectedIconPath": "static/tabbar/indexed.png"
    			},
    			{
    				"pagePath": "pages/news/news",
    				"text": "动态",
    				"iconPath": "static/tabbar/news.png",
    				"selectedIconPath": "static/tabbar/newsed.png"
    			},
    			{
    				"pagePath": "pages/msg/msg",
    				"text": "消息",
    				"iconPath": "static/tabbar/paper.png",
    				"selectedIconPath": "static/tabbar/papered.png"
    			},
    			{
    				"pagePath": "pages/my/my",
    				"text": "我的",
    				"iconPath": "static/tabbar/home.png",
    				"selectedIconPath": "static/tabbar/homeed.png"
    			}
    		]
    	}
    

uni-app和vuejs基础快速上手

view和text组件和动画的使用

  • hover-class的测试使用
  • text的测试使用
  • 两个内置组件的使用可参考官方文档

uniapp的css3选择器

  • 普通的选择器 id就用#class就用.什么都不加默认全部

  • 父级下的子级菜单的选择器

    .box>view:first-of-type{
    	background-color: red;
    }
    .box>view:last-of-type{
    	background-color: pink;
    }
    .box>view:nth-child(2){
    	background-color: yellow;
    }
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SvOmDgZ5-1649380676446)(uniapp社区交友开发.assets/image-20220323110150462-16480045116861.png)]

  • 奇偶选择器

    //奇数选择器
    .box>view:nth-of-type(odd){
    	background-color: red;
    }
    //偶数选择器
    .box>view:nth-of-type(even){
    	background-color: green;
    }
    //偶数选择器
    .box:nth-of-type(even){
    	background-color: green;
    }
    

flex布局快速入手

  • display:flex 外层使用,块内元素挤在一行内
  • justify-content:常用center,水平居中
  • align-items:常用center,垂直居中
  • felx-direction:改变排序方式,从行转换成列
  • felx-shirink:0 不被压缩
  • flex:1占一份 2占两份

数据渲染

  • {{}}获取data中的数据渲染
  • @tap触发点击事件

class和style的绑定

  • 绑定class用冒号:class
  • :class={‘class1’:isActive}
  • s:tyle=" {‘color’: Color,‘font-size’:num+‘px’}"

条件渲染

  • v-if的使用
  • v-show是会渲染只是不显示
  • 一般在template里面用v-if

列表渲染

  • v-for
  • 官方文档建议v-for写在

事件处理器

  • @tap点击事件
  • @tap.stop点里面不会触发外面的事件

监听属性

  • watch

  • 测试

    <template>
    	<view>
    		<view>{{num}}</view>
    		<button @tap="changNum()">按钮</button>
    	</view>
    </template>
    
    <script>
    	export default {
    		data() {
    			return {
    				num:0
    			}
    		},
    		watch:{
    			num(val){
    				console.log(val);
    			}
    		},
    		methods: {
    			changNum(){
    				this.num++;
    			}
    		}
    	}
    </script>
    
    <style>
    button{
    	background: blue;
    	display: flex;
    	justify-content: center;
    	align-items: center;
    	font-size: 15px;
    	color: white;
    }
    </style>
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gyz1MrF9-1649380676447)(uniapp社区交友开发.assets/image-20220323154220758-16480213421241.png)]

计算属性

  • 常用于数据的格式化

  • computed

  • 测试运用

    <template>
    	<view>
    		{{formatWeight}}
    	</view>
    </template>
    
    <script>
    	export default {
    		data() {
    			return {
    				weight:2100
    			}
    		},
    		computed:{
    			formatWeight(){
    				return (this.weight>1000)?this.weight/1000+'kg':this.weight+'g';
    			}
    		}
    	}
    </script>
    
    <style>
    	
    </style>
    
    

首页开发

page.json配置

  • 导航栏配置根据官方文档配置

    {
    			"path": "pages/index/index",
    			"style": {
    				"app-plus": {
    					// 导航栏配置
    					"titleNView":{
    						// 搜索框配置
    						"searchInput":{
    							"align":"center",
    							"backgroundColor":"#F5F4F2",
    							"borderRadius":"4px",
    							"disabled":true,
    							"placeholder":"搜索帖子",
    							"placeholderColor":"#6D6C67"
    						},
    						"buttons":[
    							{
    								"color":"#333333",
    								"colorPressed":"#FD597C",
    								"float":"right",
    								"fontSize":"20px",
    								"fontSrc":"/static/iconfont.ttf",
    								"text":"\ue668"
    							}
    						]
    					}
    				}
    			}
    		}
    
  • 用真机调试成功,微信开发者工具旁边无显示

图文列表样式

  • 封装free.css把常用样式封装 如==flex:display;justify-content:center;algin-items:center、

  • 引入自定义css库

  • 列表开发

    <view style="padding: 20rpx;">
    		<view  class="flex;justify-between;align-center">
    			<!-- 头像,昵称 -->
    			<view class="flex;align-center">
    				<!-- 头像 -->
    				<image src="/static/common//nothing.png" class="mr-1; rounded"  style="width:65rpx;height:65rpx"></image>
    				<view>
    					<view style="font-size: 30rpx;">昵称</view>
    					<view style="color: #9d9589;font-size: 20rpx;">2022-3-15</view>
    				</view>
    			</view >
    			<!-- 按钮 -->
    			<view class="flex;align-center; justify-center" style="background: #FF4A6A; width:90rpx; height:50rpx;
    			color: white;" >
    				关注
    			</view>
    		</view>
    		<!-- 文章内容 -->
    		<view>
    			哈哈哈
    		</view>
    		<!-- 图片 -->
    		<view class="mt-1" >
    			<image src="/static/demo/datapic/45.jpg" style="width: 100%; height: 350rpx;" lazy-load="true"></image>
    		</view>
    		<!-- 按钮 -->
    		<view class="flex" >
    			<view  class="flex;align-center; justify-center flex-1">
    				<view class="iconfont icon-dianzan2 "></view>
    				<view>赞</view>
    			</view>
    			<view  class="flex;align-center; justify-center flex-1">
    				<view class="iconfont icon-cai; mr-2" ></view>
    				<view>踩</view>
    			</view>
    			<view  class="flex;align-center; justify-center flex-1">
    				<view class="iconfont icon-pinglun2; mr-2"  ></view>
    				<view>评论</view>
    			</view>
    			<view  class="flex;align-center; justify-center flex-1">
    				<view class="iconfont icon-zhuanfa1; mr-2" ></view>
    				<view>转发</view>
    			</view>
    		</view>
    	</view>
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-daoAQo1N-1649380676447)(uniapp社区交友开发.assets/image-20220323193232107.png)]

封装列表样式

  • 继续使用free.css封装代码

    <view>
    		<view class="p-2">
    			<view  class="flex;justify-between;align-center">
    				<!-- 头像,昵称 -->
    				<view class="flex;align-center">
    					<!-- 头像 -->
    					<image src="/static/common//nothing.png" class="mr-1; rounded-circle"  style="width:65rpx;height:65rpx"></image>
    					<view>
    						<view class="font" style="line-height: 1.5;">昵称</view>
    						<view style=" ine-height: 1.5;" class="font-small; text-light-muted">2022-3-15</view>
    					</view>
    				</view >
    				<!-- 按钮 -->
    				<view class="flex;align-center; justify-center; rounded; text-white; bg-main" style=" width:90rpx; height:50rpx;" >
    					关注
    				</view>
    			</view>
    			<!-- 文章内容 -->
    			<view class="font-md; my-1">
    				我是标题
    			</view>
    			<!-- 图片 -->
    			<view class="mt-1" >
    				<image src="/static/demo/datapic/45.jpg" class="rounded" style="width: 100%; height: 350rpx;" lazy-load="true"></image>
    			</view>
    			<!-- 按钮 -->
    			<view class="flex" >
    				<view  class="flex;align-center; justify-center flex-1">
    					<view class="iconfont icon-dianzan2 "></view>
    					<view>赞</view>
    				</view>
    				<view  class="flex;align-center; justify-center flex-1">
    					<view class="iconfont icon-cai; mr-2" ></view>
    					<view>踩</view>
    				</view>
    				<view  class="flex;align-center; justify-center flex-1">
    					<view class="iconfont icon-pinglun2; mr-2"  ></view>
    					<view>评论</view>
    				</view>
    				<view  class="flex;align-center; justify-center flex-1">
    					<view class="iconfont icon-zhuanfa1; mr-2" ></view>
    					<view>转发</view>
    				</view>
    			</view>
    		</view>
    	</view>
    
  • 封装本项目公共css(common.css 记得引入)

    .bg-main{
    	background: #FF4A6A;
    }
    
  • 封装成组件动态渲染

    <block v-for="(item,index) in list" :key="index">
    			<commonList :item="item" :index="index" ></commonList>
    		</block>
    
    import commonList from '@/components/common/common-list';
    
    components:{
    			commonList
    		},
    
    <view class="p-2">
    				<view  class="flex;justify-between;align-center">
    					<!-- 头像,昵称 -->
    					<view class="flex;align-center">
    						<!-- 头像 -->
    						<image :src="item.userPic" class="mr-1; rounded-circle"  style="width:65rpx;height:65rpx"></image>
    						<view>
    							<view class="font" style="line-height: 1.5;">{{item.username}}</view>
    							<view style=" ine-height: 1.5;" class="font-small; text-light-muted">{{item.newstime}}</view>
    						</view>
    					</view >
    					<!-- 按钮 -->
    					<view class="flex;align-center; justify-center; rounded; text-white; bg-main" style=" width:90rpx; height:50rpx;" >
    						关注
    					</view>
    				</view>
    				<!-- 文章内容 -->
    				<view class="font-md; my-1">
    					{{item.title}}
    				</view>
    				<!-- 图片 -->
    				<view class="mt-1" >
    					<image :src="item.titlePic" class="rounded" style="width: 100%; height: 350rpx;" lazy-load="true"></image>
    				</view>
    				<!-- 按钮 -->
    				<view class="flex" >
    					<view  class="flex;align-center; justify-center flex-1">
    						<view class="iconfont icon-dianzan2; mr-2"></view>
    						<view>{{item.support.support_count}}</view>
    					</view>
    					<view  class="flex;align-center; justify-center flex-1">
    						<view class="iconfont icon-cai; mr-2" ></view>
    						<view>{{item.support.unsupport_count}}</view>
    					</view>
    					<view  class="flex;align-center; justify-center flex-1">
    						<view class="iconfont icon-pinglun2; mr-2"  ></view>
    						<view>{{item.comment_count}}</view>
    					</view>
    					<view  class="flex;align-center; justify-center flex-1">
    						<view class="iconfont icon-zhuanfa1; mr-2" ></view>
    						<view>{{item.share_num}}</view>
    					</view>
    				</view>
    			</view>
    
    export default{
    		props:{
    			item:Object,
    			key:Number
    		}
    	}
    

全局分割线开发

  • 封装组件divider.vue

    <!-- 分割线样式 -->
    	<view style="height: 15rpx; background-color: #F5F5F4;"></view>
    
  • 引入全局组件(分割线常用)

    import divider from '@/components/common/divider.vue';
    Vue.component('divider',divider);
    
    <block v-for="(item,index) in list" :key="index">
    			<commonList :item="item" :index="index"></commonList>
    			<divider></divider>
    </block>
    

优化列表组件-动画特效

  • 图片显示优化
  • 关注、图标的点击动画特效(jello)
  • 图标主色调变化 加字体颜色
  • 为各元素添加click事件 (头像、关注、标题、图片、点赞、踩)
<template>
	<view>
		<view class="p-2">
			<view class="flex;justify-between;align-center">
				<!-- 头像,昵称 -->
				<view class="flex;align-center">
					<!-- 头像 -->
					<image :src="item.userPic" class="mr-1; rounded-circle" style="width:65rpx;height:65rpx" @click="openSapce()"></image>
					<view>
						<view class="font" style="line-height: 1.5;">{{item.username}}</view>
						<view style=" ine-height: 1.5;" class="font-small; text-light-muted">{{item.newstime}}</view>
					</view>
				</view>
				<!-- 按钮 -->
				<view class="flex;align-center; justify-center; rounded; text-white; bg-main; animated faster "
					style=" width:90rpx; height:50rpx;" hover-class="rubberBand" @click="follow()">
					关注
				</view>
			</view>
			<!-- 文章内容 -->
			<view class="font-md; my-1" @click="openDetail()" >
				{{item.title}}
			</view>
			<!-- 图片 -->
			<view class="mt-1" v-if="item.titlePic" @click="openDetail()">
				<image :src="item.titlePic" class="rounded" style="width: 100%; height: 350rpx;" lazy-load="true">
				</image>
			</view>
			<!-- 按钮 -->
			<view class="flex">
				<view class="flex;align-center; justify-center flex-1 animated faster" hover-class="jello text-main" @click="doSupport('support')">
					<view class="iconfont icon-dianzan2; mr-2;"></view>
					<view>{{item.support.support_count}}</view>
				</view>
				<view class="flex;align-center; justify-center flex-1 animated faster" hover-class="jello text-main" @click="doSupport('unsupport')">
					<view class="iconfont icon-cai; mr-2 "></view>
					<view>{{item.support.unsupport_count}}</view>
				</view>
				<view class="flex;align-center; justify-center flex-1 animated faster" hover-class="jello  text-main" @click="openDetail()">
					<view class="iconfont icon-pinglun2; mr-2"></view>
					<view>{{item.comment_count}}</view>
				</view>
				<view class="flex;align-center; justify-center  flex-1 animated faster" hover-class="jello text-main" @click="openDetail()">
					<view class="iconfont icon-zhuanfa1; mr-2"></view>
					<view>{{item.share_num}}</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		props: {
			item: Object,
			index: Number
		},
		methods:{
			openSapce(){
				console.log("打开个人空间");
			},
			follow(){
				console.log("关注");
			},
			openDetail(){
				console.log("打开详情页");
			},
			doSupport(type){
				console.log(type);
			}
		}
	}
</script>

<style>
</style>

优化列表组件-关注功能

  • 关注按钮的显示
  • 子组件触发父组件方法更新isFollowz
<view class="flex;align-center; justify-center; rounded; text-white; bg-main; animated faster "
					style=" width:90rpx; height:50rpx;" hover-class="rubberBand" @click="follow()" v-if="!item.isFollow">
					关注
				</view>

follow(){
				// 触发父级follow方法
				this.$emit('follow',this.index);
			},

<commonList :item="item" :index="index" @follow="follow(index)"></commonList>

methods: {
			follow(index){
				this.list[index].isFollow=true;
				uni.showToast({
					title:'关注成功'
				})
			}
		}

优化列表组件-顶踩功能

  • 绑定class渲染
  • 方法参数传递
  • 父方法实现
<view class="flex;align-center; justify-center flex-1 animated faster" hover-class="jello text-main" @click="doSupport('support')"
				:class="item.support.type==='support'?'support-active':''">
					<view class="iconfont icon-dianzan2; mr-2;"></view>
					<view>{{item.support.support_count>0?item.support.support_count:'支持'}}</view>
				</view>

doSupport(type){
				this.$emit('doSupport',{
					type:type,
					index:this.index
				})
			}

<commonList :item="item" :index="index" @follow="follow" @doSupport="doSupport"></commonList>

doSupport(e) {
				let obj=this.newList[this.tabIndex].list[e.index]
				console.log(obj);
				if (obj.support.type === '') {
					//无操作
					obj.support[e.type + '_count']++;
				} else if (obj.support.type === 'support' && e.type === 'unsupport') {
					//之前是顶,顶减一,踩加一
					obj.support.support_count--;
					obj.support.unsupport_count++;
				} else if (obj.support.type === 'unsupport' && e.type === 'support') {
					//之前是踩,顶加一,踩减一
					obj.support.support_count++;
					obj.support.unsupport_count--;
				}
				obj.support.type = e.type;
				let msg = e.type === 'support' ? '顶' : '踩';
				uni.showToast({
					title: msg + '成功'
				})
			},

滚动tab导航开发

  • 顶部导航选项卡

    <scroll-view class="scroll-row border-bottom" scroll-x="true" :scroll-into-view="scrollInto" scroll-with-animation="true">
    			<view v-for="(item,index) in tabBars" :key="index" class="scroll-row-item px-3 py-2 font-md " :id="'tab'+index"
    			:class="tabIndex===index?'text-main font-lg font-weight-bold':''" @click="doTab(index)">
    				{{item.name}}
    			</view>
    		</scroll-view>
    
    				tabIndex:0,
    				scrollInto:'',
    				tabBars:[
    					{
    						name:'首页'
    					},
    					{
    						name:'体育'
    					},
    					{
    						name:'军事'
    					},
    					{
    						name:'热点'
    					},
    					{
    						name:'新闻'
    					},
    					{
    						name:'娱乐'
    					},
    					{
    						name:'电竞'
    					},
    					{
    						name:'国际'
    					},
    					{
    						name:'国家'
    					}
    				],
    
    
    doTab(index){
    				this.tabIndex=index;
    				this.scrollInto='tab'+index;
    			}
    
  • 下面容器能做到切换与导航栏一样,容器也能拉取

    <swiper duration=150 @change="onChange" :current="tabIndex" :style="'height:'+scrollH+'px'">
    			<swiper-item v-for="(item,index) in tabBars" :key="index"  >
    				<scroll-view scroll-y="true" :style="'height:'+scrollH+'px'">
    					<view v-for="i in 100">{{i}}</view>
    				</scroll-view>
    			</swiper-item>
    		</swiper>
    
    doTab(index){
    				this.tabIndex=index;
    				this.scrollInto='tab'+index;
    			},
    			onChange(e){
    				this.doTab(e.detail.current);
    			}
    
    onLoad() {
    			const res = uni.getSystemInfoSync();
    			this.scrollH=res.windowHeight-uni.upx2px(101);
    			console.log(this.scrollH);
    		},
    
  • 列表显示

    <swiper duration=150 @change="onChange" :current="tabIndex" :style="'height:'+scrollH+'px'">
    			<swiper-item v-for="(item,index) in newList" :key="index"  >
    				<scroll-view scroll-y="true" :style="'height:'+scrollH+'px'">
    					<block v-for="(item2,index2) in item.list" :key="index">
    						<commonList :item="item2" :index="index2" @follow="follow()" @doSupport="doSupport()"></commonList>
    						<divider></divider>
    					</block>
    				</scroll-view>
    			</swiper-item>
    		</swiper>
    
    getData(){
    				let arr=[];
    				for (var i = 0; i < this.tabBars.length; i++) {
    					arr.push({
    						list: [{
    								userPic: '/static/common//nothing.png',
    								username: '',
    								newstime: '',
    								isFollow: false,
    								title: '我是标题',
    								titlePic: '/static/demo/datapic/45.jpg',
    								support: {
    									type: 'support',
    									support_count: 1,
    									unsupport_count: 2
    								},
    								comment_count: 1,
    								share_num: 0
    							},
    							{
    								userPic: '/static/common//nothing.png',
    								username: '',
    								newstime: '',
    								isFollow: false,
    								title: '我是标题',
    								titlePic: '',
    								support: {
    									type: 'unsupport',
    									support_count: 2,
    									unsupport_count: 2
    								},
    								comment_count: 1,
    								share_num: 1
    							},
    							{
    								userPic: '/static/common//nothing.png',
    								username: '',
    								newstime: '',
    								isFollow: false,
    								title: '我是标题',
    								titlePic: '',
    								support: {
    									type: '',
    									support_count: 2,
    									unsupport_count: 2
    								},
    								comment_count: 1,
    								share_num: 1
    							}
    						]
    						
    					})
    				};
    				this.newList=arr;
    			},
    

上拉加载组件开发

  • 静态的开发

    <scroll-view scroll-y="true" :style="'height:'+scrollH+'px'" @scrolltolower="loadMore(index)">
    					<block v-for="(item2,index2) in item.list" :key="index">
    						<commonList :item="item2" :index="index2" @follow="follow()" @doSupport="doSupport()">
    						</commonList>
    						<divider></divider>
    					</block>
    					<view class="py-2 flex justify-center align-center">
    						<view class="text-light-muted">{{item.loading}}</view>
    					</view>
    				</scroll-view>
    
  • 触底函数的开发

    loadMore(index){
    				let item=this.newList[index];
    				item.loading='加载中.';
    				setTimeout(()=>{
                        //复制文本
    					item.list=[...item.list,...item.list];
    				},2000)
    			}
    

封装上拉加载组件

  • 优化加载判断

    loadMore(index){
    				let item=this.newList[index];
    				if(!item==='上拉加载更多'){
    					return;
    				}
    				item.loading='加载中...';
    				setTimeout(()=>{
    					item.list=[...item.list,...item.list];
    					item.loading='上拉加载更多';
    				},10000)
    			}
    
  • 封装load-more.vue 并引入

    <template>
    	<view class="py-2 flex justify-center align-center">
    		<view class="text-light-muted">{{loading}}</view>
    	</view>
    </template>
    
    <script>
    	export default{
    		props:{
    			loading:String
    		}
    	}
    </script>
    
    import loadMore from '@/components/common/load-more';
    	export default {
    		components: {
    			commonList,
    			loadMore
    		},
    }
    

封装无数据默认组件

  • 无数据环境测试

    const demo=[
    		{
    				userPic: '/static/common//nothing.png',
    				username: '',
    				newstime: '',
    				isFollow: false,
    				title: '我是标题',
    				titlePic: '/static/demo/datapic/45.jpg',
    				support: {
    					type: 'support',
    					support_count: 1,
    					unsupport_count: 2
    				},
    				comment_count: 1,
    				share_num: 0
    			},
    			{
    				userPic: '/static/common//nothing.png',
    				username: '',
    				newstime: '',
    				isFollow: false,
    				title: '我是标题',
    				titlePic: '/static/demo/datapic/45.jpg',
    				support: {
    					type: 'unsupport',
    					support_count: 2,
    					unsupport_count: 2
    				},
    				comment_count: 1,
    				share_num: 1
    			},
    			{
    				userPic: '/static/common//nothing.png',
    				username: '',
    				newstime: '',
    				isFollow: false,
    				title: '我是标题',
    				titlePic: '',
    				support: {
    					type: '',
    					support_count: 2,
    					unsupport_count: 2
    				},
    				comment_count: 1,
    				share_num: 1
    			}
    	]
    
    getData() {
    				let arr = [];
    				for (var i = 0; i < this.tabBars.length; i++) {
    					let obj = {
    						loading:'上拉加载更多',
    						list: []
    					}
    					if(i<2){
    						obj.list=demo;
    					}
    					arr.push(obj)
    				};
    				this.newList = arr;
    			},
    
  • 封装nothing.vue组件 全局引入

    <template v-if="item.list.length>0">
    					<scroll-view scroll-y="true" :style="'height:'+scrollH+'px'" @scrolltolower="loadMore(index)">
    						<block v-for="(item2,index2) in item.list" :key="index">
    							<commonList :item="item2" :index="index2" @follow="follow()" @doSupport="doSupport()">
    							</commonList>
    							<divider></divider>
    						</block>
    						<loadMore :loading="item.loading"></loadMore>
    					</scroll-view>
    				</template>
    				<template v-else>
    					<no-thing></no-thing>
    				</template>
    
    import noThing from '@/components/common/no-thing.vue';
    Vue.component('no-thing',noThing);
    

搜索页开发

  • 创建页面search,配置pages.json

    		{
    			"path": "pages/index/index",
    			"style": {
    				"app-plus": {
    					// 导航栏配置
    					"titleNView":{
    						// 搜索框配置
    						"searchInput":{
    							"align":"center",
    							"backgroundColor":"#F5F4F2",
    							"borderRadius":"4px",
    							"disabled":true,
    							"placeholder":"搜索帖子",
    							"placeholderColor":"#6D6C67"
    						},
    						"buttons":[
    							{
    								"color":"#333333",
    								"colorPressed":"#FD597C",
    								"float":"right",
    								"fontSize":"20px",
    								"fontSrc":"/static/iconfont.ttf",
    								"text":"\ue668"
    							}
    						]
    					}
    				}
    			}
    		}
    	    ,{
                "path" : "pages/news/news",
                "style" :                                                                                    
                {
                    "navigationBarTitleText": "",
                    "enablePullDownRefresh": false
                }
                
            }
            ,{
                "path" : "pages/msg/msg",
                "style" :                                                                                    
                {
                    "navigationBarTitleText": "",
                    "enablePullDownRefresh": false
                }
                
            }
            ,{
                "path" : "pages/my/my",
                "style" :                                                                                    
                {
                    "navigationBarTitleText": "",
                    "enablePullDownRefresh": false
                }
                
            }
            ,{
                "path" : "pages/search/search",
                "style": {
                	"app-plus": {
                		// 导航栏配置
                		"titleNView":{
                			// 搜索框配置
                			"searchInput":{
                				"align":"center",
                				"backgroundColor":"#F5F4F2",
                				"borderRadius":"4px",
                				"placeholder":"搜索帖子",
                				"placeholderColor":"#6D6C67"
                			},
                			"buttons":[
                				{
                					"color":"#333333",
                					"colorPressed":"#FD597C",
                					"float":"right",
                					"fontSize":"14px",
                					"text":"搜索"
                				}
                			]
                		}
                	}
                }
            }
    
  • 监听点击导航栏搜索框事件, 实现跳转,用官方api

    onNavigationBarSearchInputClicked() {
    			uni.navigateTo({
    				url: '../search/search'
    			})
    		},
    
  • 搜索历史开发

    <view>
    		<view class="py-2 font-md px-2">搜索历史</view>
    		<view class="flex flex-wrap">
    			<view class="border rounded font mx-2 my-1 px-2 " v-for="(item,index) in list" :key="index"
    			hover-class="bg-light">
    				{{item}}
    			</view>
    		</view>
    	</view>
    
  • 监听导航输入

    onNavigationBarSearchInputChanged(e) {
    			this.searchText=e.text;
    		}
    
  • 监听导航搜索按钮

    onNavigationBarButtonTap(e) {
    			if(e.index===0){
    				this.searchEvent();
    			}
    		},
    
  • 搜索事件, 收起键盘,处于loading状态, 展示搜索结果,隐藏loading提示框

    searchEvent(){
    				uni.hideKeyboard();
    				uni.showLoading({
    					title:'加载中'
    				})
    				setTimeout(()=>{
    					this.serachList=demo;
    					uni.hideLoading();
    				},3000)
    			}
    
  • 搜索结果列表 引入commonlist,遍历,优化搜索历史与列表存在问题

    <view>
    		<template v-if="this.serachList.length===0">
    			<view class="py-2 font-md px-2">搜索历史</view>
    			<view class="flex flex-wrap">
    				<view class="border rounded font mx-2 my-1 px-2 " v-for="(item,index) in list" :key="index"
    				hover-class="bg-light">
    					{{item}}
    				</view>
    			</view>
    		</template>
    		<template v-else>
    			<block v-for="(item,index) in serachList" :key="index" >
    				<commonList :item="item" :index="index"></commonList>
    			</block>
    		</template>
    	</view>
    
    import commonList from '@/components/common/common-list.vue';
    
    export default {
    		components:{
    			commonList
    		},
    }
    
  • 点击搜索历史的事件

    <view class="flex flex-wrap">
    				<view class="border rounded font mx-2 my-1 px-2 " v-for="(item,index) in list" :key="index"
    				hover-class="bg-light" @click="historyEvent(item)">
    					{{item}}
    				</view>
    			</view>
    
    historyEvent(item){
    				console.log(item);
    				this.searchText=item;
    				this.searchEvent();
    			}
    

发布表单页面开发

自定义导航栏开发

  • 新建发布页面add-input,取消原生导航

    {
                "path" : "pages/add-input/add-input",
                "style" :                                                                                    
                {
                    "app-plus": {
                    	"titleNView": false
                    }
                }
                
            }
    
  • 首页导航按钮跳转页面

    onNavigationBarButtonTap() {
    			uni.navigateTo({
    				url:'../add-input/add-input'
    			})
    		},
    
  • 自定义导航栏,添加uni-nav-bar依赖, 根据官方文档调用

    <uni-nav-bar left-icon="back" statusBar>
    			<view class="flex justify-center align-center w-100">
    				所有人可见<text class="iconfont icon-shezhi ml-1"></text>
    			</view>
    			
    		</uni-nav-bar>
    

textarea组件使用

  • utextarea, 动态绑定

    <textarea v-model="content" placeholder="说一句话吧~" class="px-2 uni-textarea" />
    

底部操作条组件开发

<view style="height: 85rpx" class="fixed-bottom bg-white flex align-center">
			<view class="iconfont icon-caidan footer-btn"></view>
			<view class="iconfont icon-huati footer-btn"></view>
			<view class="iconfont icon-tupian footer-btn"></view>
			
			<view class="bg-main text-white justify-center align-center ml-auto flex mr-2" style="width: 140rpx; height: 60rpx;">发送</view>
		</view>


<style>
.footer-btn{
	width: 86rpx;
	height: 86rpx;
	justify-content: center;
	display: flex;
	align-items: center;
	font-size: 50rpx;
}
</style>

上传多图功能开发

  • upload-image组件开发, 引官方组件,对应引入也需要引入

  • 对官方组件的修改 添加mode压缩,修改内边距, 修改圆角

    <view class="px-2">
    		<view class="uni-uploader">
    			<view class="uni-uploader-head">
    				<view class="uni-uploader-title">点击可预览选好的图片</view>
    				<view class="uni-uploader-info">{{imageList.length}}/9</view>
    			</view>
    			<view class="uni-uploader-body">
    				<view class="uni-uploader__files">
    					<block v-for="(image,index) in imageList" :key="index">
    						<view class="uni-uploader__file">
    							<image class="uni-uploader__img rounded" :src="image" :data-src="image"
    								@tap="previewImage" mode="aspectFill"></image>
    						</view>
    					</block>
    					<view class="uni-uploader__input-box">
    						<view class="uni-uploader__input rounded" @tap="chooseImage"></view>
    					</view>
    				</view>
    			</view>
    		</view>
    	</view>
    
  • 上传图片成功的内容保存 上传图片的回调success方法中

    success: (res) => {
    						this.imageList = this.imageList.concat(res.tempFilePaths);
    						this.$emit('choose',this.imageList);
    					},
    					
    <uploadImage @choose="choose"></uploadImage>
    
    choose(e){
    				console.log(e);
    				this.imageList=e;
    			}
    

删除选中图片功能实现

  • 静态图标的实现

    <block v-for="(image,index) in imageList" :key="index">
    						<view class="uni-uploader__file position-relative">
    							<image class="uni-uploader__img rounded" :src="image" :data-src="image"
    								@tap="previewImage" mode="aspectFill"></image>
    								<view class="bg-dark position-absolute top-0 right-0 rounded"
    								style="padding: 0 15rpx; background-color: rgba(0, 0, 0, 0.5);">
    									<text class="iconfont icon-shanchu text-white"></text>
    								</view>
    						</view>
    					</block>
    
  • 添加删除功能的函数, 通知父组件, 优化父组件方法, 给予交互反馈提示

    <text class="iconfont icon-shanchu text-white"  @click="deleteImage(index)"></text>
    
    deleteImage(index){
    				uni.showModal({
    					title:'提示',
    					content:'是否要删除该图片',
    					confirmText:'删除',
    					cancelText:'不删除',
    					success: (res) => {
    						if(res.confirm){
    							this.imageList.splice(index,1);
    							this.$emit('change',this.imageList);
    						}
    					}
    				})
    				
    			},
    

保存草稿功能开发

  • 添加返回首页方法

    <uni-nav-bar left-icon="back" statusBar @clickLeft="goBack">
    			<view class="flex justify-center align-center w-100 font-weight-bold">
    				所有人可见<text class="iconfont icon-shezhi ml-1"></text>
    			</view>
    		</uni-nav-bar>
    
    goBack(){
    				uni.navigateBack({
    					delta:1
    				})
    			},
    
  • 监听返回, 交互提示反馈 return true即能返回

    onBackPress() {
    			if((this.content!==''||this.imageList.length>0)&&!this.showBack){
    				uni.showModal({
    					content: '是否保存为草稿',
    					showCancel: true,
    					cancelText: '不保存',
    					confirmText: '保存',
    					success: res => {
    						if(res.confirm){
    							console.log('保存');
    						}
    						//手动执行返回
                           // goBack(){
    					// 	uni.navigateBack({
    					// 		delta:1
    					// 	})
    					// },
    						this.goBack();
                            
    					}
    				});
    				this.showBack=true;
    				return true;
    			}
    		},
    
  • 保存的方法

    store(){
    				let obj={
    					content:this.content,
    					imageList:this.imageList
    				};
    				uni.setStorage({
    					key:'add-input',
    					data:JSON.stringify(obj)
    				})
    			}
    
  • 取出的方法 用同步取出

    onLoad() {
    			var res=uni.getStorageSync('add-input');
    			if(res){
    				var obj=JSON.parse(res);
    				// console.log(result);
    				this.content=obj.content;
    				this.imageList=obj.imageList;
    			}
    		},
    
  • 优化图片的草稿功能, 上传图片的组件imageList要用props传值

    <uploadImage :list="imageList" @change="change"></uploadImage>
    
    //组件里面
    
    props: {
    			list: Array
    		},
    
    created(){
    			this.imageList=this.list;
    		},
    
  • 不保存草稿功能的实现, 清楚缓存

    onBackPress() {
    			if((this.content!==''||this.imageList.length>0)&&!this.showBack){
    				uni.showModal({
    					content: '是否保存为草稿',
    					showCancel: true,
    					cancelText: '不保存',
    					confirmText: '保存',
    					success: res => {
    						if(res.confirm){
    							// console.log('保存');
    							this.store();
    						}else{
    							uni.removeStorageSync('add-input');
    						}
    						//手动执行返回
    						this.goBack();
    					}
    				});
    				this.showBack=true;
    				return true;
    			}
    		},
    
  • 下面图标插入图片的方法(优化不需要上传图片时隐藏上传图片组件)

    <view class="iconfont icon-tupian footer-btn" @click="iconClickEvent('uploadImage')"></view>
    
    <uploadImage ref="uploadImage" :show="show"  :list="imageList" @change="change"></uploadImage>
    
    iconClickEvent(e){
    				switch (e){
    					case 'uploadImage': this.$refs.uploadImage.chooseImage();
    						break;
    				}
    			}
    			
    			computed:{
    			show(){
    				return this.imageList.length>0;
    			}
    		},
    		
    		在子组件中加入v-if=“show”
    			
    

动态列表页开发

导航栏tab导航开发

  • 自定义导航栏的静态开发

    <uni-nav-bar statusBar="true" border="false" >
    			<view class="flex align-center justify-center font-weight-bold  w-100">
    				<view class="font-lg text-main mx-1">关注</view>
    				<view class="font-md text-light-muted mx-1">话题</view>
    			</view>
    			<view slot="right" class="iconfont icon-fatie_icon"></view>
    		</uni-nav-bar>
    
  • 取消原生导航栏

    {
    			"path": "pages/news/news",
    			"style": {
    				"app-plus": {
    					"titleNView": false
    				}
    			}
    
    		},
    
  • 导航栏右边图标的单击事件

    <uni-nav-bar statusBar="true" border="false" @clickRight="openAddInput">
    			<view class="flex align-center justify-center font-weight-bold  w-100">
    				<view class="font-lg text-main mx-1">关注</view>
    				<view class="font-md text-light-muted mx-1">话题</view>
    			</view>
    			<view slot="right" class="iconfont icon-fatie_icon"></view>
    		</uni-nav-bar>
    		
    		
    openAddInput(){
    				uni.navigateTo({
    					url: '../add-input/add-input'
    				})
    			}
    
  • tabBar的动态循环渲染

    <uni-nav-bar statusBar="true" border="false" @clickRight="openAddInput">
    			<view class="flex align-center justify-center font-weight-bold  w-100 font-md text-light-muted">
    				<view v-for="(item,index) in tabBars" :key="index"
    				:class="tabIndex===index? 'text-main font-lg':''"
    				@click="changeTab(index)" class="mx-1">
    					{{item.name}}
    				</view>
    			</view>
    			<view slot="right" class="iconfont icon-fatie_icon"></view>
    		</uni-nav-bar>
    
    data() {
    			return {
    				tabIndex:0,
    				tabBars:[
    					{
    						name:'关注'
    					},{
    						name:'话题'
    					}
    				]
    			}
    		},
    
    changeTab(index){
    				this.tabIndex=index;
    			}
    

关注列表页开发

滑动滚动区域计算

  • 引入首页的swipper和scrollview组件, 对应修改即可

    <swiper duration=150 @change="onChange" :current="tabIndex" :style="'height:'+scrollH+'px'">
    			<swiper-item>
    
    				<scroll-view scroll-y="true" :style="'height:'+scrollH+'px'">
    					
    				</scroll-view>
    
    			</swiper-item>
    		</swiper>
    
  • 计算区域高度

    onLoad() {
    			const res = uni.getSystemInfoSync();
    			this.scrollH=res.screenHeight-res.statusBarHeight-44;
    			console.log(this.scrollH);
    		},
    

导航列表联动实现

  • 有两个swipperitem 表示关注和话题

    <swiper duration=150 @change="onChange" :current="tabIndex" :style="'height:'+scrollH+'px'">
    			<swiper-item>
    				<scroll-view scroll-y="true" :style="'height:'+scrollH+'px'">
    					<view v-for=" (item,index) in 100" :key="index">{{item}}</view>
    				</scroll-view>
    			</swiper-item>
    			<swiper-item>
    				<view>话题</view>
    			</swiper-item>
    		</swiper>
    
  • 引入common-list组件

  • 分割线的使用

    <swiper-item>
    				<scroll-view scroll-y="true" :style="'height:'+scrollH+'px'">
    					<block  v-for="(item,index) in list" :key="index" >
    						<commonList :item="item" :index="index"></commonList>
    						<divider></divider>
    					</block>
    				</scroll-view>
    			</swiper-item>
    			<swiper-item>
    				<view>话题</view>
    			</swiper-item>
    
  • 导航与列表的联动实现

    <swiper duration=150 @change="onChangeTab" :current="tabIndex" :style="'height:'+scrollH+'px'">
    			<swiper-item>
    				<scroll-view scroll-y="true" :style="'height:'+scrollH+'px'">
    					<block  v-for="(item,index) in list" :key="index" >
    						<commonList :item="item" :index="index"></commonList>
    						<divider></divider>
    					</block>
    				</scroll-view>
    			</swiper-item>
    			<swiper-item>
    				<view>话题</view>
    			</swiper-item>
    		</swiper>
    
    onChangeTab(e){
    				// console.log(e.detail);
    				this.tabIndex=e.detail.current;
    			}
    

顶踩操作和下拉加载功能 copy首页即可

  • 移植顶踩操作
  • 下拉加载的开发

关注列表页开发

热门分类组件开发

  • 静态页面开发

    <swiper-item>
    				<view class="flex justify-between align-center px-2">
    					<text class="font-md">热门分类</text>
    					<view class="flex align-center font text-secondary">
    						更多<text class="iconfont icon-jinru"></text>
    					</view>
    				</view>
    				<view class="flex align-center border-bottom px-2 py-3">
    					<view class="rounded border bg-light mx-1 px-2">关注</view>
    					<view class="rounded border bg-light mx-1 px-2">关注</view>
    					<view class="rounded border bg-light mx-1 px-2">关注</view>
    					<view class="rounded border bg-light mx-1 px-2">关注</view>
    				</view>
    			</swiper-item>
    
  • 添加点击动画效果

    <view class="rounded border bg-light mx-1 px-2 animated" hover-class="jello">关注</view>
    

封装热门分类组件

  • 热门分类对象数组构建

    hotCate:[{
    					name:'关注'
    				},
    				{
    					name:'推荐'
    				},
    				{
    					name:'体育'
    				},
    				{
    					name:'军事'
    				}
    				]
    
  • 封装组件, 导入组件,遍历输出, 父子传值

  • 留两个接口

    <hotCate :hotCate="hotCate"></hotCate>
    
    <template>
    	<view>
    		<view class="flex justify-between align-center px-2">
    			<text class="font-md">热门分类</text>
    			<view class="flex align-center font text-secondary animated" hover-class="jello" @click="openMore">
    				更多<text class="iconfont icon-jinru"></text>
    			</view>
    		</view>
    		<view class="flex align-center border-bottom px-2 py-3">
    			<view class="rounded border bg-light mx-1 px-2 animated" hover-class="jello"
    			v-for="(item,index) in hotCate" :key="index" @click="openDetail">{{item.name}}</view>
    		</view>
    	</view>
    </template>
    
    <script>
    	export default{
    		props:['hotCate'],
    		methods:{
    			openMore(){
    				console.log("点击更多");
    			},
    			openDetail(){
    				console.log("点击进入详情页");
    			}
    		}
    	}
    </script>
    
    <style>
    </style>
    
    

轮播图和搜索框的开发

  • 静态页面开发

    <view class="p-2">
    			<view class="flex align-center justify-center py-2 rounded bg-light text-secondary">
    				<text class="iconfont icon-sousuo mr-2"></text>搜索话题
    			</view>
    		</view>
    		<swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" class="px-2 pb-2">
    			<swiper-item>
    				<image src="/static/demo/banner3.jpg" class="w-100 rounded" style="height: 300rpx;"></image>
    			</swiper-item>
    		</swiper>
    		<divider></divider>
    

话题列表组件开发

  • 静态页面开发

    <view class="p-2 font-md"> 最近更新</view>
    		<view class="flex align-center p-2">
    			<image src="../../static/demo/topicpic/1.jpeg" style="width: 150rpx; height: 150rpx;"
    			class="rounded mr-2"></image>
    			<view class="flex flex-column ">
    				<text class="font-md text-dark">话题哈哈哈</text>
    				<text class="font text-secondary">话题描述</text>
    				<view class="flex align-center font text-secondary">
    					<text class="mr-2">今日:0</text>
    					<text>关注:0</text>
    				</view>
    			</view>
    		</view>
    

封装话题列表组件

  • 声明topicList

    topicList: [{
    						cover: '/static/demo/topicpic/1.jpeg',
    						title: '话题标题',
    						desc: '话题描述',
    						news_count: '10',
    						today_count: '10'
    					},
    					{
    						cover: '/static/demo/topicpic/1.jpeg',
    						title: '话题标题',
    						desc: '话题描述',
    						news_count: '10',
    						today_count: '10'
    					},
    					{
    						cover: '/static/demo/topicpic/1.jpeg',
    						title: '话题标题',
    						desc: '话题描述',
    						news_count: '10',
    						today_count: '10'
    					},
    					{
    						cover: '/static/demo/topicpic/1.jpeg',
    						title: '话题标题',
    						desc: '话题描述',
    						news_count: '10',
    						today_count: '10'
    					}
    				]
    
  • 封装组件,引入组件

    <block v-for="(item,index) in topicList" :key="index">
    					<topicList :item="item" :index="index"></topicList>
    				</block>
    
    <view class="flex align-center p-2">
    		<image :src="item.cover" style="width: 150rpx; height: 150rpx;"
    		class="rounded mr-2"></image>
    		<view class="flex flex-column ">
    			<text class="font-md text-dark">{{item.title}}</text>
    			<text class="font text-secondary">{{item.desc}}</text>
    			<view class="flex align-center font text-secondary">
    				<text class="mr-2">动态:{{item.news_count}}</text>
    				<text>今日:{{item.today_count}}</text>
    			</view>
    		</view>
    	</view>
    

话题分类页开发

  • 新建页面

    {
                "path" : "pages/topic-nav/topic-nav",
                "style" :                                                                                    
                {
                    "navigationBarTitleText": "话题分类"
                }
                
            }
    
    
  • 导航进入

    openMore(){
    				uni.navigateTo({
    					url:'../topic-nav/topic-nav'
    				})
    			},
    
  • 引入首页,修改topic—nav页面,修改common-list组件, 修改数据

    <template>
    	<view>
    		<scroll-view class="scroll-row border-bottom border-light-secondary" scroll-x="true"
    			:scroll-into-view="scrollInto" scroll-with-animation="true" style="height: 100rpx;">
    			<view v-for="(item,index) in tabBars" :key="index" class="scroll-row-item px-3 py-2 font-md "
    				:id="'tab'+index" :class="tabIndex===index?'text-main font-lg font-weight-bold':''"
    				@click="doTab(index)">
    				{{item.name}}
    			</view>
    		</scroll-view>
    		<swiper duration=150 @change="onChange" :current="tabIndex" :style="'height:'+scrollH+'px'">
    			<swiper-item v-for="(item,index) in newList" :key="index">
    				<template v-if="item.list.length>0">
    					<scroll-view scroll-y="true" :style="'height:'+scrollH+'px'" @scrolltolower="loadMore(index)">
    						<block v-for="(item2,index2) in item.list" :key="index">
    							<!-- <commonList :item="item2" :index="index2" @follow="follow()" @doSupport="doSupport()">
    							</commonList> -->
    							<topicList :item="item2" :index="index2"></topicList>
    
    						</block>
    						<loadMore :loading="item.loading"></loadMore>
    					</scroll-view>
    				</template>
    				<template v-else>
    					<no-thing></no-thing>
    				</template>
    			</swiper-item>
    		</swiper>
    	</view>
    </template>
    
    <script>
    	import topicList from '@/components/news/topic-list';
    	import loadMore from '@/components/common/load-more';
    	const demo = [{
    						cover: '/static/demo/topicpic/1.jpeg',
    						title: '话题标题',
    						desc: '话题描述',
    						news_count: '10',
    						today_count: '10'
    					},
    					{
    						cover: '/static/demo/topicpic/1.jpeg',
    						title: '话题标题',
    						desc: '话题描述',
    						news_count: '10',
    						today_count: '10'
    					},
    					{
    						cover: '/static/demo/topicpic/1.jpeg',
    						title: '话题标题',
    						desc: '话题描述',
    						news_count: '10',
    						today_count: '10'
    					},
    					{
    						cover: '/static/demo/topicpic/1.jpeg',
    						title: '话题标题',
    						desc: '话题描述',
    						news_count: '10',
    						today_count: '10'
    					},
    					{
    						cover: '/static/demo/topicpic/1.jpeg',
    						title: '话题标题',
    						desc: '话题描述',
    						news_count: '10',
    						today_count: '10'
    					},
    					{
    						cover: '/static/demo/topicpic/1.jpeg',
    						title: '话题标题',
    						desc: '话题描述',
    						news_count: '10',
    						today_count: '10'
    					},
    					{
    						cover: '/static/demo/topicpic/1.jpeg',
    						title: '话题标题',
    						desc: '话题描述',
    						news_count: '10',
    						today_count: '10'
    					},
    					{
    						cover: '/static/demo/topicpic/1.jpeg',
    						title: '话题标题',
    						desc: '话题描述',
    						news_count: '10',
    						today_count: '10'
    					}
    				];
    	export default {
    		components: {
    			topicList,
    			loadMore
    		},
    		data() {
    			return {
    				scrollH: 200,
    				tabIndex: 0,
    				scrollInto: '',
    				newList: [],
    				tabBars: [{
    						name: '首页'
    					},
    					{
    						name: '体育'
    					},
    					{
    						name: '军事'
    					},
    					{
    						name: '热点'
    					},
    					{
    						name: '新闻'
    					},
    					{
    						name: '娱乐'
    					},
    					{
    						name: '电竞'
    					},
    					{
    						name: '国际'
    					},
    					{
    						name: '国家'
    					}
    				]
    			}
    		},
    		onNavigationBarSearchInputClicked() {
    			uni.navigateTo({
    				url: '../search/search'
    			})
    		},
    		onLoad() {
    			const res = uni.getSystemInfoSync();
    			this.scrollH = res.windowHeight - uni.upx2px(101);
    			this.getData();
    		},
    		onNavigationBarButtonTap() {
    			uni.navigateTo({
    				url:'../add-input/add-input'
    			})
    		},
    		methods: {
    			getData() {
    				let arr = [];
    				for (var i = 0; i < this.tabBars.length; i++) {
    					let obj = {
    						loading: '上拉加载更多',
    						list: []
    					}
    					if (i < 2) {
    						obj.list = demo;
    					}
    					arr.push(obj)
    				};
    				this.newList = arr;
    			},
    			follow(index) {
    				this.list[index].isFollow = true;
    				uni.showToast({
    					title: '关注成功'
    				})
    			},
    			doSupport(e) {
    				let obj = this.list[e.index];
    				if (obj.support.type === '') {
    					//无操作
    					obj.support[e.type + '_count']++;
    				} else if (obj.support.type === 'support' && e.type === 'unsupport') {
    					//之前是顶,顶减一,踩加一
    					obj.support.support_count--;
    					obj.support.unsupport_count++;
    				} else if (obj.support.type === 'unsupport' && e.type === 'support') {
    					//之前是踩,顶加一,踩减一
    					obj.support.support_count++;
    					obj.support.unsupport_count--;
    				}
    				obj.support.type = e.type;
    				let msg = e.type === 'support' ? '顶' : '踩';
    				uni.showToast({
    					title: msg + '成功'
    				})
    			},
    			doTab(index) {
    				this.tabIndex = index;
    				this.scrollInto = 'tab' + index;
    			},
    			onChange(e) {
    				this.doTab(e.detail.current);
    			},
    			loadMore(index) {
    				let item = this.newList[index];
    				if ((item.loading) !== '上拉加载更多') {
    					return;
    				}
    				item.loading = '加载中...';
    				setTimeout(() => {
    					item.list = [...item.list, ...item.list];
    					item.loading = '上拉加载更多';
    				}, 2000)
    			}
    		}
    	}
    </script>
    
    <style>
    
    </style>
    
    

话题详情页开发

page.json配置

  • 新建topic-detail页面

  • 配置导航栏, 渐变式透明, 图标

    {
                "path" : "pages/topic-detail/topic-detail",
                "style" :                                                                                    
                {
                    "navigationBarTitleText": "",
                    "app-plus": {
                    	"titleNView": {
                    		"type": "transparent",
    						"buttons": [
    							{
    								"type": "menu"
    							}
    						]
                    	}
                    }
                } 
            }
    
  • 导航到话题详情页, 传递json字符串对象, 接受数据转换object

    <view class="flex align-center p-2" @click="openDetail(item)">
        
     openDetail(item){
    				uni.navigateTo({
    					url:'../topic-detail/topic-detail?detail='+JSON.stringify(item)
    				})
    			}
        
        onLoad(e){
    				
    			if(e.detail){
    				var obj=JSON.parse(e.detail);
    				// console.log(obj);
    			}
    			
    		},
    

话题介绍组件开发

  • 图片模糊状态

  • 静态开发

    <view>
    		<view class="position-relative">
    			<image src="/static/demo/topicpic/1.jpeg" mode="aspectFill"
    			style="height: 300rpx;" class="w-100 filter"></image>
    		</view>
    		
    		<view class=" px-2 bg-white position-relative" style="z-index: 10;">
    			<view class="flex align-center">
    				<image src="/static/demo/topicpic/1.jpeg" class="w-100" style="height: 150rpx; width: 150rpx;
    				margin-top: -75rpx;"></image>
    				<text class="font-md">#话题标题#</text>
    			</view>
    			<view class="flex align-center font text-secondary mt-2">
    				<text class="mr-1">动态:0</text>
    				<text>今日:0</text>
    			</view>
    			<view class="font text-secondary">话题描述</view>
    		</view>
    		
    	</view>
    
    <style>
    .filter{
    	filter: blur(10px);
    }
    </style>
    

封装话题介绍组件

  • 新建topic-info组件

  • 动态替换, 数据渲染

    <template>
    	<view>
    		<view class="position-relative">
    			<image :src="info.cover" mode="aspectFill" style="height: 300rpx;" class="w-100 filter">
    			</image>
    		</view>
    		
    		<view class=" px-2 bg-white position-relative pb-1" style="z-index: 10;">
    			<view class="flex align-center">
    				<image :src="info.cover" class="w-100" style="height: 150rpx; width: 150rpx;
    				margin-top: -75rpx;"></image>
    				<text class="font-md">{{info.title}}</text>
    			</view>
    			<view class="flex align-center font text-secondary mt-2">
    				<text class="mr-1">动态:{{info.news_count}}</text>
    				<text>今日:{{info.today_count}}</text>
    			</view>
    			<view class="font text-secondary">{{info.desc}}</view>
    		</view>
    	</view>
    </template>
    
    <script>
    	export default {
    		props:['info']
    	}
    </script>
    
    <style>
    </style>
    
    
    <topicInfo :info="info"></topicInfo>
    		<divider></divider>
    

精华帖子列表组件开发

<view class="flex p-2 border-bottom">
			<text class="iconfont icon-xihuan text-main"></text>
			<text class="font text-darker text-ellipsis"> 
				【新人必读】uni-app实战项目第四季社区交友开发
			</text>
		</view>
		<view class="flex p-2 border-bottom">
			<text class="iconfont icon-xihuan text-main"></text>
			<text class="font text-darker text-ellipsis"> 
				【新人必读】uni-app实战项目第四季社区交友开发
			</text>
		</view>

tab选项卡组件开发

  • 优化精华帖子列表开发, 用循环

    <block v-for="(item,index) in hotList" :key="index">
    			<view class="flex p-2 border-bottom">
    				<text class="iconfont icon-xihuan text-main"></text>
    				<text class="font text-darker text-ellipsis">
    					{{item.title}}
    				</text>
    			</view>
    		</block>
    
    hotList: [{
    						title: '【新人必读】uni-app实战项目第四季社区交友开发'
    					},
    					{
    						title: '【新人必读】Hillky社区规范'
    					}
    				]
    
  • tab选项开发

    <view class="flex align-center py-2">
    			<text class="flex-1 flex align-center justify-center font-weight-bold font-lg text-main">默认</text>
    			<text class="flex-1 flex align-center justify-center font-weight-bold font-md text-dark">最新</text>
    		</view>
    
  • 列表开发, 引入公共列表, 声明两个数组list1,2

    <block v-for="(item,index) in list1" :key="index">
    			<commonList :item="item" :index="index"></commonList>
    		</block>
    
  • tab切换实现

    <view class="flex align-center py-2" >
    			<text class="flex-1 flex align-center justify-center"
    			v-for="(item,index) in tabBar" :key="index"
    			:class="tabIndex===index?'font-lg text-main font-weight-bold':'font-md text-dark'"
    			@click="changeTab(index)">{{item.name}}</text>
    		</view>
    
    tabIndex: 0,
    				tabBar:[
    					{
    						name:'默认'
    					},
    					{
    						name:'最新'
    					}
    				]
    

利用计算属性实现列表切换

  • 用计算属性切换数组

    computed: {
    			listData() {
    				if (this.tabIndex === 0) {
    					return this.list1;
    				}
    				if (this.tabIndex === 1) {
    					return this.list2;
    				}
    			}
    		},
    
  • 遍历列表要分割线

  • 判断数组长度, 用nothing组件

    <template v-if="listData.length>0">
    			<block v-for="(item,index) in listData" :key="index">
    				<commonList :item="item" :index="index"></commonList>
    				<divider></divider>
    			</block>
    		</template>
    		<template v-else>
    			<no-thing></no-thing>
    		</template>
    

话题详情上拉加载实现

  • 触底事件

    onReachBottom() {
    			this.loadMore();
    		},
    
  • 引入上拉加载组件

    	import loadMore from '@/components/common/load-more';
    
    <loadMore :loading="loadText"></loadMore>
    
  • loadText计算属性区分是哪个列表的上拉加载

    loadText1:'上拉加载更多',
    loadText2:'上拉加载更多'
    
    loadText(){
    				if(this.tabIndex===0){
    					return this.loadText1
    				}else{
    					return this.loadText2
    				}
    			}
    
  • 上拉加载更多事件

    loadMore(){
    				let index =this.tabIndex
    				if(this['loadText'+(index+1)]!=='上拉加载更多'){
    					return;
    				}
    				this['loadText'+(index+1)]='加载中...'
    				setTimeout(()=>{
    					this['loadText'+(index+1)]='上拉加载更多';
    					this['list'+(index+1)]=[...this['list'+(index+1)],...this['list'+(index+1)]];
    				},2000)
    			}
    

消息列表页面开发

page.json配置

  • 配置顶部导航栏, 配置左右图标

     {
    			"path": "pages/msg/msg",
    			"style": {
    				"navigationBarTitleText": "消息列表",
    				"app-plus": {
    					"titleNView": {
    						"buttons": [
    							{
    								"color": "#333333",
    								"colorPressed": "#FD597C",
    								"float": "left",
    								"fontSize": "20px",
    								"fontSrc": "/static/iconfont.ttf",
    								"text": "\ue611"
    							},
    							{
    								"color": "#333333",
    								"colorPressed": "#FD597C",
    								"float": "right",
    								"fontSize": "20px",
    								"fontSrc": "/static/iconfont.ttf",
    								"text": "\ue649"
    							}
    						]
    					}
    				}
    			}
    
    

消息列表组件开发

  • 静态开发

  • 引入数字脚标组件

    <view>
    		<view class="flex align-center justify-center p-2 border-bottom border-light-secondary">
    			<image src="../../static/default.jpg" style="height: 80rpx; width: 80rpx;" class="rounded-circle mr-2"></image>
    			<view class="flex-column flex flex-1">
    				<view class="flex align-center justify-between">
    					<text class="font-md text-dark">昵称</text>
    					<text class="font-sm text-secondary">17:00</text>
    				</view>
    				<view class="py-1 flex align-center justify-between">
    					<view class=" font-sm text-secondary">内容</view>
    					<uni-badge text="1" type="error"></uni-badge>
    				</view>
    			</view>
    		</view>
    	</view>
    

封装消息列表组件

  • 优化内容, 添加对应css和最大宽度

    <view class="pt-1 flex align-center justify-between">
    					<view class=" font-sm text-secondary text-ellipsis" style="max-width: 500rpx;">内容内容内容内容内容内容内容内容内容内容内容内容内容</view>
    					<uni-badge text="1" type="error"></uni-badge>
    				</view>
    
  • 封装数据,封装组件, 时间使用在线时间戳

  • 引入time.js, 使用对应库,使用过滤器

    import $T from '@/common/time.js'
    
    filters:{
    			formatTime(value){
    				return $T.gettime(value);
    			}
    		},
    
  • 组件分离

    <block v-for="(item,index) in list" :key="index">
    			<msgList :item="item" :index="index"></msgList>
    		</block>
    
    <template>
    	<view class="flex align-center justify-center p-2 border-bottom border-light-secondary">
    		<image :src="item.avatar" style="height: 80rpx; width: 80rpx;" class="rounded-circle mr-2"></image>
    		<view class="flex-column flex flex-1">
    			<view class="flex align-center justify-between">
    				<text class="font-md text-dark">{{item.username}}</text>
    				<text class="font-sm text-secondary">{{item.update_time | formatTime}}</text>
    			</view>
    			<view class="pt-1 flex align-center justify-between">
    				<view class=" font-sm text-secondary text-ellipsis" style="max-width: 500rpx;">{{item.data}}</view>
    				<uni-badge :text="item.noread" type="error"></uni-badge>
    			</view>
    		</view>
    	</view>
    </template>
    
    <script>
    	import $T from '@/common/time.js'
    	export default {
    		props:{
    			item:Object,
    			index:Number
    		},
    		filters: {
    			formatTime(value){
    				// console.log(value);
    				return $T.gettime(value);
    			}
    		}
    	}
    </script>
    
    <style>
    </style>
    
    

下拉刷新功能实现

  • page.json配置

    "enablePullDownRefresh": true,
    
  • 监听下拉刷新, 写入方法

    onPullDownRefresh() {
    			this.refresh();
    		},
                
    refresh(){
    				setTimeout(()=>{
    					this.list=demo;
    					uni.stopPullDownRefresh();
    				},2000);
    			}
    
  • 引入nothing组件, v-if判断

    <template>
    	<view>
    		<template v-if="this.list.length>0">
    			<block v-for="(item,index) in list" :key="index">
    				<msgList :item="item" :index="index"></msgList>
    			</block>
    		</template>
    		<template v-else>
    			<no-thing></no-thing>
    		</template>
    		
    		
    	</view>
    </template>
    
    <script>
    	
    	const demo=[{
    					avatar:'../../static/default.jpg',
    					username:'昵称',
    					update_time:1648458088,
    					data:'内容内容内容内容内容内容内容内容内容内容内容内容内容',
    					noread:20
    				},
    				{
    					avatar:'../../static/default.jpg',
    					username:'昵称',
    					update_time:1648458088,
    					data:'内容内容内容内容内容内容内容内容内容内容内容内容内容',
    					noread:20
    				},
    				{
    					avatar:'../../static/default.jpg',
    					username:'昵称',
    					update_time:1648458088,
    					data:'内容内容内容内容内容内容内容内容内容内容内容内容内容',
    					noread:20
    				},
    				{
    					avatar:'../../static/default.jpg',
    					username:'昵称',
    					update_time:1648458088,
    					data:'内容内容内容内容内容内容内容内容内容内容内容内容内容',
    					noread:20
    				}];
    	import msgList from '@/components/msg/msg-list';
    	
    	export default {
    		components:{
    			msgList
    		},
    		data() {
    			return {
    				list:[]
    			}
    		},
    		onLoad() {
    			this.list=demo;
    			console.log(this.list);
    		},
    		onPullDownRefresh() {
    			this.refresh();
    		},
    		methods: {
    			refresh(){
    				setTimeout(()=>{
    					this.list=[...this.list,...this.list];
    					uni.stopPullDownRefresh();
    				},2000);
    			}
    		}
    	}
    </script>
    
    <style>
    
    </style>
    
    
    

下拉弹出层组件使用

  • 使用uni-poup组件,

  • 监听原生导航栏按钮事件,弹出弹出层

    <uni-popup ref="popup" type="top" background-color="#fff">123</uni-popup>
    
    onNavigationBarButtonTap(e) {
    			switch (e.index){
    				case 0:
    					break;
    				case 1:
    					this.$refs.popup.open();
    					break;
    				
    			}
    		},
    

下拉弹出选项完善

  • 静态开发

  • 添加点击事件

    <uni-popup ref="popup" type="top" background-color="#fff">
    			<view class="flex justify-center align-center font-md border-bottom py-2" hover-class="bg-light"
    			@click="popupEvent('findFriend')">
    				<text class="iconfont icon-sousuo mr-2" ></text>搜索好友
    			</view>
    			<view class="flex justify-center align-center font-md py-2" hover-class="bg-light"
    				@click="popupEvent('deleteList')">
    				<text class="iconfont icon-shanchu mr-2"></text>删除列表
    			</view>
    		</uni-popup>
    
    
    popupEvent(event){
    				switch (event){
    					case 'findFriend':
    					{
    						console.log('findFriend');
    						this.$refs.popup.close();
    						break;
    					}
    					case 'deleteList':
    					{
    						console.log('deleteList');
    						this.$refs.popup.close();
    						break;
    					}
    				}
    			}
    
    

我的好友列表页开发

page.json配置

  • 新建user-list, 导航进入该页面

    onNavigationBarButtonTap(e) {
    			switch (e.index){
    				case 0:
    					uni.navigateTo({
    						url:'../user-list/user-list'
    					})
    					break;
    				case 1:
    					this.$refs.popup.open();
    					break;
    				
    			}
    		},
    
  • 配置page.json

    {
    			"path": "pages/user-list/user-list",
    			"style": {
    				"navigationBarTitleText": "",
    				"app-plus": {
    					"animationType": "slide-in-left",
    					"titleNView": {
    						"autoBackButton": true,
    						"searchInput": {
    							"align": "center",
    							"backgroundColor": "#F5F4F2",
    							"borderRadius": "4px",
    							"disabled": true,
    							"placeholder": "搜索用户",
    							"placeholderColor": "#6D6C67"
    						},
    						"buttons": [{
    							"color": "#333333",
    							"colorPressed": "#FD597C",
    							"float": "right",
    							"fontSize": "14px",
    							"text": "取消"
    						}]
    					}
    				}
    			}
    
  • 监听点击输入框事件, 监听取消按钮事件

    onNavigationBarSearchInputClicked() {
    			// console.log('跳转');
    			uni.navigateTo({
    				url:'../search/search'
    			})
    		},
    		onNavigationBarButtonTap() {
    			uni.navigateBack({
    				delta: 1
    			})
    		},
    

tab导航组件再次优化

  • 引入tabBar导航

  • 条件渲染数字

    <view class="flex align-center py-2">
    			<text class="flex-1 flex align-center justify-center" v-for="(item,index) in tabBar" :key="index"
    				:class="tabIndex===index?'font-lg text-main font-weight-bold':'font-md text-dark'"
    				@click="changeTab(index)">{{item.name}} <text v-if="item.num>0" class="ml-1">{{item.num}}</text> </text>
    		</view>
    
    
    

好友列表组件开发

  • 引入首页的scrollview, 下拉, 对应修改和引入

  • 列表样式静态开发

    <swiper duration=150 @change="onChange" :current="tabIndex" :style="'height:'+scrollH+'px'">
    			<swiper-item v-for="(item,index) in newList" :key="index">
    				<template v-if="item.list.length>0">
    					<scroll-view scroll-y="true" :style="'height:'+scrollH+'px'" @scrolltolower="loadMore(index)">
    						<block v-for="(item2,index2) in item.list" :key="index2">
    							<view class="flex align-center p-2 border-bottom border-light-secondary">
    								<image src="../../static/default.jpg" class="rounded-circle mr-2" style="width: 100rpx; height: 100rpx;"></image>
    								<view class="flex flex-column flex-1">
    									<text class="font-md text-dark">昵称</text>
    									<text class="font-sm mt-1">性别</text>
    								</view>
    								<view class="uni-icon uni-icon-checkbox-filled text-light-muted "></view>
    							</view>
    						</block>
    						<loadMore :loading="item.loading"></loadMore>
    					</scroll-view>
    				</template>
    				<template v-else>
    					<no-thing></no-thing>
    				</template>
    			</swiper-item>
    		</swiper>
    
    getData() {
    				let arr = [];
    				for (var i = 0; i < this.tabBars.length; i++) {
    					let obj = {
    						loading: '上拉加载更多',
    						list: []
    					}
    					if (i < 2) {
    						obj.list = [1,2,3,4];
    					}
    					arr.push(obj)
    				};
    				this.newList = arr;
    			},
    			changeTab(index){
    				this.tabIndex=index;
    			},
    			onChange(e){
    				this.changeTab(e.detail.current);
    			},
    			loadMore(index) {
    				let item = this.newList[index];
    				if ((item.loading) !== '上拉加载更多') {
    					return;
    				}
    				item.loading = '加载中...';
    				setTimeout(() => {
    					item.list = [...item.list, ...item.list];
    					item.loading = '上拉加载更多';
    				}, 2000)
    			}
    

强化badge组件开发

  • 使用uni-badge, 插入图标, 优化性别显示

    <view>
    										<text class="iconfont icon-nv text-secondary"style="font-size: 18rpx;"></text>
    										<uni-badge type="error" text="24">
    										</uni-badge>
    									</view>
    

封装好友列表组件

  • 测试demo数据

    const demo=[{
    		avatar:'../../static/default.jpg',
    		username:'昵称',
    		sex:1,
    		age:24,
    		isFollow:false
    	},
    	{
    		avatar:'../../static/default.jpg',
    		username:'昵称',
    		sex:2,
    		age:24,
    		isFollow:true
    	}
    	];
    
  • 数据渲染,动态绑定性别class, 点击灰色

  • 封装组件, 引入组件

    <template>
    	<view>
    		<view class="flex align-center p-2 border-bottom border-light-secondary " hover-class="bg-light">
    			<image :src="item.avatar" class="rounded-circle mr-2" style="width: 100rpx; height: 100rpx;"></image>
    			<view class="flex flex-column flex-1">
    				<text class="font-md text-dark">{{item.username}}</text>
    				<view v-if="item.sex>0">
    					<text class="iconfont text-secondary" :class="item.sex===1?'icon-nv':'icon-nan'"   style="font-size: 18rpx;"></text>
    					<uni-badge :type="item.sex===1?'error':'primary'" :text="item.age">
    					</uni-badge>
    				</view>
    				
    			</view>
    			<view class="uni-icon uni-icon-checkbox-filled  " :class="item.isFollow?'text-light-muted':'text-main'"></view>
    		</view>
    	</view>
    </template>
    
    <script>
    	export default {
    		name:"user-list",
    		props:{
    			item:Object,
    			index:Number
    		},
    		data() {
    			
    			return {
    				
    			};
    		}
    	}
    </script>
    
    <style>
    
    </style>
    
    
    import userList from '@/components/user-list/user-list.vue';
    
    <userList :item="item2" :index="index2"></userList>
    

优化我的好友列表页面

  • 优化scrollH问题,引入首页方法

    onLoad() {
    			this.getData();
    			const res = uni.getSystemInfoSync();
    			this.scrollH = res.windowHeight - uni.upx2px(101);
    			// console.log(this.scrollH);
    		},
    
  • 隐藏上拉加载组件

    	<loadMore :loading="item.loading" v-if="item.list.length>10"></loadMore>
    

聊天界面开发

page.json配置

  • 新建页面user-chat, 导航进入

  • 配置导航栏

    {
                "path" : "pages/user-chat/user-chat",
                "style" :{
                    "app-plus": {
                    	"titleNView": {
                    		"buttons": [
                    			{
                    				"color": "#333333",
                    				"colorPressed": "#FD597C",
                    				"float": "right",
                    				"fontSize": "20px",
                    				"fontSrc": "/static/iconfont.ttf",
                    				"text": "\ue628"
                    			}
                    		]
                    	}
                    }
                }
        
        
    

聊天输入框组件开发

  • 底部操作条开发

    <view class="flex fixed-bottom align-center bg-white border-top" style="height: 100rpx;">
    			<view class="flex-1">
    				<input type="text" placeholder="请文明发言" class="rounded ml-2 bg-light p-1" />
    			</view>
    			<view class="iconfont icon-fabu flex align-center justify-center font-lg animated" style="width: 100rpx;"
    				hover-class="jello text-main"></view>
    
    		</view>
    

聊天列表组件开发

  • scrollH获取

    <scroll-view :style="'height: '+this.scrollH+'px;'" scroll-y="true">
    			<view v-for="i in 100" :key="i">{{i}}</view>
    		</scroll-view>
    
    onLoad() {
    			const res = uni.getSystemInfoSync();
    			this.scrollH = res.windowHeight - uni.upx2px(101);
    			
    		},
    
  • 聊天列表组件开发

  • 右边气泡的开发

    		<scroll-view :style="'height: '+this.scrollH+'px;'" scroll-y="true">
    			<view class="flex align-start px-2 my-2">
    				<image src="../../static/default.jpg" class="rounded-circle"
    				style="height: 100rpx; width: 100rpx;"></image>
    				<view class="bg-light mx-2 p-2 rounded mt-1" style="max-width: 400rpx;  min-width: 100rpx;">
    					你好啊
    				</view>
    			</view>
    			
    			<view class="flex align-start px-2 my-2" style="flex-direction: row-reverse;">
    				<image src="../../static/default.jpg" class="rounded-circle"
    				style="height: 100rpx; width: 100rpx;"></image>
    				<view class="bg-light mx-2 p-2 rounded mt-1" style="max-width: 400rpx; min-width: 100rpx;">
    					你好啊
    				</view>
    			</view>
    			
    		</scroll-view>
    

封装聊天列表组件完善时间显示

  • 新建user-chat-list, 封装数据

  • 计算属性, 是否本人

    isShelf(){
    				return this.item.userId===1
    			},
    
  • 时间显示开发

    <view class="my-2 flex align-center justify-center text-secondary font-sm">
    			{{shortTime}}
    		</view>
    
  • 引入time.js, 优化时间显示, 用计算属性

    shortTime(){
    				return $T.getChatTime(this.item.create_time,this.preTime);
    			}
    
    <userChatList :item="item" :index="index" :preTime=" index>0 ? list[index-1].create_time : 0"></userChatList>
    

完善聊天页功能

  • 输入框绑定内容, 绑定发送事件, 发送功能实现

    sendMessage(){
    				let obj={
    					userId:1,
    					avatar: '../../static/default.jpg',
    					data: this.content,
    					type: 'text',
    					create_time: (new Date()).getTime()
    				};
    				if(obj.data===''){
    					uni.showToast({
    						title:"请输入内容"
    					});
    					return;
    				}
    				this.list.push(obj);
    				this.content=''
    			}
    
  • 优化功能, 最小宽度去掉, 键盘推页面false, 清空输入框, 丢弃scrollH

    <input type="text" placeholder="请文明发言" class="rounded ml-2 bg-light p-1" v-model="content" adjust-position="false" />
    
    <scroll-view style="position: absolute; left: 0 ; top: 0; right: 0; bottom: 100rpx;" scroll-y="true">
    
  • 滚动到底部实现

    <scroll-view style="position: absolute; left: 0 ; top: 0; right: 0; bottom: 100rpx;" scroll-y="true"
    		:scroll-into-view="scrollInto" scroll-with-animation>
    			<block v-for="(item,index) in list" :key="index">
    				<userChatList :id="'chat'+index" :item="item" :index="index" :preTime=" index>0 ? list[index-1].create_time : 0"></userChatList>
    			</block>
    			
    
    		</scroll-view>
    
    pageToBottom(){
    				let lastIndex=this.list.length-1;
    				if(lastIndex < 0){
    					return
    				}
    				this.scrollInto='chat'+lastIndex;
    				console.log(this.scrollInto);
    			}
                                      
     onReady() {
    			this.pageToBottom();
    		},
    

搜索列表页开发

搜索列表功能完善

  • 添加搜索标识

    onNavigationBarSearchInputClicked() {
    			uni.navigateTo({
    				url: '../search/search?type=post'
    			})
    		},
    
  • 获取类型, 修改搜索占位, 添加如果说是app端

    if (e.type) {
    				this.type = e.type;
    			}
    			let pageTitle='';
    			switch (this.type) {
    				case 'post':
    						pageTitle='搜索帖子'
    					break;
    				case 'topic':
    						pageTitle='搜索话题'
    					break;
    				case 'friend':
    						pageTitle='搜索好友'
    					break;
    			}
    			console.log(this.type);
    			// #ifdef APP-PLUS
    			let currentWebview=this.$scope.$getAppWebview();
    			let tn=currentWebview.getStyle().titleNView;
    			tn.searchInput.placeholder=pageTitle;
    			console.log(tn);
    			currentWebview.setStyle({
    				titleNView:tn
    			})
    			// #e
    
  • 搜索结果完善优化, 根据不同搜索,组件,数据都要不同

    searchEvent() {
    				uni.hideKeyboard();
    				uni.showLoading({
    					title: '加载中'
    				})
    				setTimeout(() => {
    					switch (this.type) {
    						case 'post':
    							this.serachList = demo1;
    							break;
    						case 'topic':
    							this.serachList = demo2;
    							break;
    						case 'friend':
    							this.serachList = demo3;
    							break;
    					}
    					uni.hideLoading();
    				}, 3000)
    			},
    
    <block v-for="(item,index) in serachList" :key="index">
    				<template v-if="type==='post'">
    					<commonList :item="item" :index="index"></commonList>
    				</template>
    				<template v-if="type==='topic'">
    					<topicList :item="item" :index="index"></topicList>
    				</template>
    				<template v-if="type==='friend'">
    					<userList :item="item" :index="index"></userList>
    				</template>
    			</block>
    

文章详情页开发

page.json配置

  • 新建页面,detail, 导航入口

    ,{
                "path" : "pages/detail/detail",
                "style" :                                                                                    
                {
                    "app-plus": {
                    	"titleNView": {
                    		"buttons": [
                    			{
                    				"float": "right",
    								"type": "menu"
                    			}
                    		]
                    	}
                    }
                }
                
            }
    
  • 把对象作为参数传过去,初始化

    openDetail(){
    				console.log("打开详情页");
    				uni.navigateTo({
    					url:'../../pages/detail/detail?detail='+JSON.stringify(this.item)
    				})
    			},
    
    onLoad(e){
    			if(e.detail){
    				this.__init(JSON.parse(e.detail));
    			}
    		},
    		methods: {
    			__init(data){
    				uni.setNavigationBarTitle({
    					title:data.title
    				})
    			}
    		}
    

强化公共列表组件功能

  • 修改公共列表组件, 添加isDetail, prop, 评论和分享功能

    props: {
    			item: Object,
    			index: {
    				type: Number,
    				default: -1
    			},
    			isDetail: {
    				type: Boolean,
    				default: false
    			}
    		},
    		
    doComment(){
    				if(!this.isDetail){
    					return this.openDetail();
    				}
    				this.$emit('doComment');
    			},
    			doShare(){
    				if(!this.isDetail){
    					return this.openDetail();
    				}
    				this.$emit('doShare');
    			}
    
    
    
    <commonList :item="this.item" :isDetail="true" @doComment="doComment" @doShare="doShare">
    			帖子详请
    		</commonList>
    		
    

完善详情页关注顶踩功能

  • 关注事件, 修改index默认值

    follow() {
    				this.info.isFollow = true;
    			}
    
    index: {
    				type: Number,
    				default: -1
    			}
    
  • 顶踩方法改写

    doSupport(e) {
    				let obj = this.info
    				if (obj.support.type === e.type) {
    					uni.showToast({
    						title: '你已经操作过了'
    					})
    					return;
    				}
    				if (obj.support.type === '') {
    					//无操作
    					obj.support[e.type + '_count']++;
    				} else if (obj.support.type === 'support' && e.type === 'unsupport') {
    					//之前是顶,顶减一,踩加一
    					obj.support.support_count--;
    					obj.support.unsupport_count++;
    				} else if (obj.support.type === 'unsupport' && e.type === 'support') {
    					//之前是踩,顶加一,踩减一
    					obj.support.support_count++;
    					obj.support.unsupport_count--;
    				}
    				obj.support.type = e.type;
    				let msg = e.type === 'support' ? '顶' : '踩';
    				uni.showToast({
    					title: msg + '成功'
    				})
    			}
    
  • 增加content,image

    content:"Hillky正在开发ing.....",
    					images:[
    						{
    							url:"https://tupian.qqw21.com/article/UploadPic/2020-5/20205622141239876.jpg"
    						},
    						{
    							url:"https://tse1-mm.cn.bing.net/th/id/R-C.df1d553893d9b7888c725b8dbcbcf439?rik=hpbIzO6xZ3Qchw&riu=http%3a%2f%2fwww.chabeichong.com%2fimages%2f2016%2f11%2f12-04122113.jpg&ehk=%2fe971CgX%2bMeAgZuGCVac3td74wDOd1%2bWzz0q4IsP1Lc%3d&risl=&pid=ImgRaw&r=0&sres=1&sresct=1"
    						}
    					]
    
  • 增加图片预览功能

    <image v-for="(item,index) in info.images" :src="item.url" class="w-100" mode="widthFix" @click="preview(index)"></image>
    
    preview(index){
    				// console.log(this.imageList);
    				uni.previewImage({
    					urls:this.imageList,
    					current:index
    				})
    			}
    
    computed:{
    			imageList(){
    				return this.info.images.map(item=>item.url);
    			}
    		},
    

评论输入框组件封装

  • 先对聊天室底部操作条的封装,测试是否成功

    <template>
    	<view class="flex fixed-bottom align-center bg-white border-top" style="height: 100rpx;">
    		<view class="flex-1">
    			<input type="text" placeholder="请文明发言" class="rounded ml-2 bg-light p-1" v-model="content"
    				adjust-position="false" />
    		</view>
    		<view class="iconfont icon-fabu flex align-center justify-center font-lg animated" style="width: 100rpx;"
    			hover-class="jello text-main" @click="sendMessage"></view>
    	</view>
    </template>
    
    <script>
    	export default {
    		data(){
    			return{
    				content:''
    			}
    		},
    		methods:{
    			sendMessage(){
    				if (this.content === '') {
    					uni.showToast({
    						title: "请输入内容",
    						icon:"none"
    					});
    					return;
    				}
    				this.$emit('submit',this.content);
    				this.content = '';
    				
    			}
    		}
    	}
    </script>
    
    <style>
    </style>
    
    
    <bottomBtn @submit="submit"></bottomBtn>
    
    submit(content) {
    				let obj = {
    					userId: 1,
    					avatar: '../../static/default.jpg',
    					data: content,
    					type: 'text',
    					create_time: (new Date()).getTime()
    				};
    				this.list.push(obj);
    				this.pageToBottom();
    			},
    
  • 再到detail页面使用该组件,需要占位

列表评论组件开发

  • 使用官方评论界面,进行静态开发

    <view class="px-2">
    			<!-- 评论区 start -->
    			<view class="uni-comment">
    				<view class="uni-comment-list">
    					<view class="uni-comment-face" style="margin-top: 15rpx;">
    						<image src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/images/uni@2x.png" mode="widthFix">
    						</image>
    					</view>
    					<view class="uni-comment-body">
    						<view class="uni-comment-top">
    							<text>网友</text>
    						</view>
    						<view class="uni-comment-date">
    							<text>08/10 08:12</text>
    						</view>
    						<view class="uni-comment-content">很酷的HBuilderX和uni-app,开发一次既能生成小程序,又能生成App</view>
    					</view>
    				</view>
    			</view>
    		</view>
    

分享功能组件开发

  • 弹出层,底部弹出, 监听导航栏按钮触发, 层级关系的修改-z-index

    <uni-popup ref="popup" type="bottom" background-color="#fff">
    			<view style="height: 300rpx;">
    				123
    			</view>
    		</uni-popup>
    
    onNavigationBarButtonTap() {
    			this.$refs.popup.open();
    		},
    
    uni-popup {
    		position: fixed;
    		/* #ifndef APP-NVUE */
    		z-index: 9999;
    
  • 监听返回事件,隐藏弹出层

    onBackPress() {
    			this.$refs.popup.close();
    		},
    
  • 静态开发

    <view class="font-md border-bottom border-light-secondary text-center py-2">分享到</view>
    				<view class="flex align-center ">
    					<view class="flex flex-1 flex-column justify-center align-center py-2">
    						<view class="iconfont icon-QQ rounded-circle bg-primary text-white flex align-center justify-center font-lg" style="width: 100rpx; height: 100rpx;"></view>
    						<view class="font mt-1 text-light-muted">QQ好友</view>
    					</view>
    					...
    				</view>
    				<view class="font-md border-top border-light-secondary text-center py-2">取消</view>
    
  • 遍历图标

    <block v-for="(item,index) in btnList" :key="index">
    					<view class="flex flex-1 flex-column justify-center align-center py-2">
    						<view
    							class="iconfont  rounded-circle bg-primary text-white flex align-center justify-center font-lg"
    							:class="item.icon+' '+item.color "
    							style="width: 100rpx; height: 100rpx;"></view>
    						<view class="font mt-1 text-light-muted">{{item.name}}</view>
    					</view>
    				</block>
    
  • 封装组件 more-share.vue

    <template>
    	<view>
    		<uni-popup ref="popup" type="bottom" background-color="#fff">
    			<view class="font-md border-bottom border-light-secondary text-center py-2">分享到</view>
    			<view class="flex align-center ">
    				<block v-for="(item,index) in btnList" :key="index">
    					<view class="flex flex-1 flex-column justify-center align-center py-2">
    						<view
    							class="iconfont  rounded-circle bg-primary text-white flex align-center justify-center font-lg"
    							:class="item.icon+' '+item.color " style="width: 100rpx; height: 100rpx;"></view>
    						<view class="font mt-1 text-light-muted">{{item.name}}</view>
    					</view>
    				</block>
    			</view>
    			<view class="font-md border-top border-light-secondary text-center py-2">取消</view>
    		</uni-popup>
    	</view>
    </template>
    
    <script>
    	export default {
    		data(){
    			return{
    				btnList: [{
    						"icon": 'icon-QQ',
    						"color": 'bg-primary',
    						"name": 'QQ好友'
    					},
    					{
    						"icon": 'icon-QQ',
    						"color": 'bg-primary',
    						"name": 'QQ好友'
    					},
    					{
    						"icon": 'icon-QQ',
    						"color": 'bg-primary',
    						"name": 'QQ好友'
    					},
    					{
    						"icon": 'icon-QQ',
    						"color": 'bg-primary',
    						"name": 'QQ好友'
    					}
    				],
    			}
    		},
    		methods:{
    			open(){
    				this.$refs.popup.open();
    			},
    			close(){
    				this.$refs.popup.close();
    			}
    		}
    	}
    </script>
    
    <style>
    </style>
    
    
    	<moreShare ref="share"></moreShare>
    	
    	onNavigationBarButtonTap() {
    			this.$refs.share.open();
    		},
    		onBackPress() {
    			this.$refs.share.close();
    		},
    
  • 用官方组件分享动态渲染数据, 子组件用created()

    created(){
    			uni.getProvider({
    				service: 'share',
    				success: (e) => {
    					console.log(e);
    					let data = []
    					for (let i = 0; i < e.provider.length; i++) {
    						switch (e.provider[i]) {
    							case 'weixin':
    								data.push({
    									name: '微信好友',
    									id: 'weixin',
    									icon:'icon-weixin',
    									color:'bg-success',
    									sort:0
    								})
    								data.push({
    									name: '朋友圈',
    									id: 'weixin',
    									icon:'icon-huati',
    									color:'bg-dark',
    									type:'WXSenceTimeline',
    									sort:1
    								})
    								break;
    							case 'sinaweibo':
    								data.push({
    									name: '新浪微博',
    									icon:'icon-xinlangweibo',
    									color:'bg-danger',
    									id: 'sinaweibo',
    									sort:2
    								})
    								break;
    							case 'qq':
    								data.push({
    									name: 'QQ好友',
    									id: 'qq',
    									icon:'icon-QQ',
    									color:'bg-primary',
    									sort:3
    								})
    								break;
    							default:
    								break;
    						}
    					}
    					this.providerList = data.sort((x,y) => {
    						return x.sort - y.sort
    					});
    				},
    				fail: (e) => {
    					console.log('获取分享通道失败', e);
    					uni.showModal({
    						content:'获取分享通道失败',
    						showCancel:false
    					})
    				}
    			});
    		},
    
  • 分享方法

    async share(e) {
    				console.log('分享通道:'+ e.id +'; 分享类型:' + this.shareType);
    				
    				if(!this.shareText && (this.shareType === 1 || this.shareType === 0)){
    					uni.showModal({
    						content:'分享内容不能为空',
    						showCancel:false
    					})
    					return;
    				}
    				
    				if(!this.image && (this.shareType === 2 || this.shareType === 0)){
    					uni.showModal({
    						content:'分享图片不能为空',
    						showCancel:false
    					})
    					return;
    				}
    				
    				let shareOPtions = {
    					provider: e.id,
    					scene: e.type && e.type === 'WXSenceTimeline' ? 'WXSenceTimeline' : 'WXSceneSession', //WXSceneSession”分享到聊天界面,“WXSenceTimeline”分享到朋友圈,“WXSceneFavorite”分享到微信收藏     
    					type: this.shareType,
    					success: (e) => {
    						console.log('success', e);
    						uni.showModal({
    							content: '已分享',
    							showCancel:false
    						})
    					},
    					fail: (e) => {
    						console.log('fail', e)
    						uni.showModal({
    							content: e.errMsg,
    							showCancel:false
    						})
    					},
    					complete:function(){
    						console.log('分享操作结束!')
    					}
    				}
    				
    				switch (this.shareType){
    					case 0:
    						shareOPtions.summary = this.shareText;
    						shareOPtions.imageUrl = this.image;
    						shareOPtions.title = '欢迎体验uniapp';
    						shareOPtions.href = 'https://uniapp.dcloud.io';
    						break;
    					case 1:
    						shareOPtions.summary = this.shareText;
    						break;
    					case 2:
    						shareOPtions.imageUrl = this.image;
    						break;
    					case 5:
    						shareOPtions.imageUrl = this.image ? this.image : 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/b6304f00-5168-11eb-bd01-97bc1429a9ff.png'
    						shareOPtions.title = '欢迎体验uniapp';
    						shareOPtions.miniProgram = {
    							id:'gh_33446d7f7a26',
    							path:'/pages/tabBar/component/component',
    							webUrl:'https://uniapp.dcloud.io',
    							type:0
    						};
    						break;
    					default:
    						break;
    				}
    				
    				if(shareOPtions.type === 0 && plus.os.name === 'iOS'){//如果是图文分享,且是ios平台,则压缩图片 
    					shareOPtions.imageUrl = await this.compress();
    				}
    				if(shareOPtions.type === 1 && shareOPtions.provider === 'qq'){//如果是分享文字到qq,则必须加上href和title
    					shareOPtions.href = 'https://uniapp.dcloud.io';
    					shareOPtions.title = '欢迎体验uniapp';
    				}
    				uni.share(shareOPtions);
    			},
    

个人中心页面开发

page.json配置

  • 配置page.json

    {
    			"path": "pages/my/my",
    			"style": {
    				"navigationBarTitleText": "我的",
    				"app-plus": {
    					"titleNView": {
    						"buttons": [
    							{
    								"type": "menu"
    							}
    						]
    					}
    				}
    			}
    
    		},
    

个人中心ui构建

  • 静态开发第一个view

    <view class="flex align-center p-2">
    			<image src="../../static/default.jpg" style="width: 100rpx; height: 100rpx;" class="rounded-circle"></image>
    			<view class="flex flex-column flex-1 px-2">
    				<text class="font-lg font-weight-bold text-dark ">昵称</text>
    				<text class="font text-muted mt-1"> 总帖子10 今日发帖0</text>
    			</view>
    			<view class="iconfont icon-jinru"></view>
    		</view>
    
  • 第二个view开发,使用遍历方式

    <view class="flex align-center px-3 py-2">
    			<view class="flex-1 flex-column flex align-center justify-center" v-for="(item,index) in this.itemList " :key="index">
    				<text class="font-lg text-dark">{{item.num}}</text>
    				<text class="text-muted fony">{{item.name}}</text>
    			</view>
    		</view>
    
  • 第三个view, 广告位的开发

    <view class="px-3 py-2">
    			<image src="/static/demo/banner1.jpg" style="height: 300rpx; width: 100%;" mode="aspectFill" class="rounded"></image>
    		</view>
    
  • 引入uni-list-item

    <uni-list-item title="浏览历史" :showExtraIcon="true" :extra-icon="extraIcon1" link :border="false"></uni-list-item>
    		<uni-list-item title="社区认证" :showExtraIcon="true" :extra-icon="extraIcon2" link :border="false">
    		</uni-list-item>
    		<uni-list-item title="审核帖子" :show-extra-icon="true" link :border="false">
    			<text slot="icon" class="iconfont icon-keyboard font-lg"></text>
    		</uni-list-item>
    
    import uniListItem from '@/components/uni-list-item/uni-list-item.vue';
    
    extraIcon1: {
    					type: 'eye',
    					color: '#000000',
    					size: 20
    				},
    				extraIcon2: {
    					type: 'vip',
    					color: '#000000',
    					size: 20
    				},
    

设置页面开发

  • 新建页面,导航进入

  • 退出登录静态开发

    <template>
    	<view>
    		<uni-list-item title="账号与安全" link :border="false" ></uni-list-item>
    		<uni-list-item title="资料编辑" link :border="false" ></uni-list-item>
    		<uni-list-item title="清楚缓存" link :border="false"></uni-list-item>
    		<uni-list-item title="意见反馈" link :border="false"></uni-list-item>
    		<uni-list-item title="关于社区" link :border="false"></uni-list-item>
    		
    		<view class="py-2 px-3">
    			<button class="bg-main text-white" style="border-radius: 50rpx;">退出登录</button>
    		</view>
    	</view>
    </template>
    
    <script>
    	import uniListItem from '@/components/uni-list-item/uni-list-item.vue';
    	export default {
    		components:{
    			uniListItem
    		},
    		data() {
    			return {
    				
    			}
    		},
    		methods: {
    			
    		}
    	}
    </script>
    
    <style>
    
    </style>
    
    

修改密码页面开发

修改密码UI界面开发

  • 新建页面,导航进入

    <uni-list-item title="账号与安全" link :border="false" @click="open"></uni-list-item>
    
    uni.navigateTo({
    					url:'../userPassword/userPassword'
    				})
    
  • 静态页面开发

    <view class="px-1">
    		<input class="uni-input" value=""  type="text" placeholder="输入旧密码"/>
    		<input class="uni-input" value=""  type="text" placeholder="输入新密码"/>
    		<input class="uni-input" value=""  type="text" placeholder="输入确认密码"/>
    		<view class="py-2 px-3">
    			<button class="bg-main text-white" style="border-radius: 50rpx;">设置</button>
    		</view>
    	</view>
    

表单验证功能实现

  • 输入框绑定vue, disabled属性绑定

    computed:{
    			disable(){
    				return this.oldPassword===''||this.newPassword===''||this.renewPassword==='';
    			}
    		},
    
    <button class="bg-main text-white" style="border-radius: 50rpx;" :disabled="disable">设置</button>
    
  • 验证功能实现

    check(){
    				if(this.newPassword!==this.renewPassword){
    					uni.showToast({
    						title:'两次输入密码不一致',
    						icon:"none"
    					})
    					return false;
    				}
    				return true;
    			},
    			submit(){
    				if(this.check()){
    					console.log('提交成功');
    				}
    			}
    

修改邮箱页面开发

修改邮箱页UI界面开发

  • 新建页面, 配置page.json

    ,{
                "path" : "pages/userEmail/userEmail",
                "style" :                                                                                    
                {
                    "navigationBarTitleText": "设置邮箱"
                }
                
            }
    
  • 拼接字符串, 配置导航,引号不一样用1左边的那个,${}拼接

    open(path){
    				uni.navigateTo({
    					url:`../${path}/${path}`,
    					fail(e) {
    						console.log(e);
    					}
    				})
    				
    			}
    
  • 静态页面开发,与修改密码差不多的功能,禁用

    <template>
    	<view>
    		<input type="text" class="uni-input" placeholder="请输入邮箱" v-model="email"/>
    		<input type="text" class="uni-input" placeholder="请输入密码" v-model="password"/>
    		<button class="bg-main text-white mt-1" style="border-radius: 50rpx;" :disabled="disable">绑定邮箱</button>
    	</view>
    </template>
    
    <script>
    	export default {
    		data() {
    			return {
    				email:'',
    				password:''
    			}
    		},
    		computed:{
    			disable(){
    				return this.email===''||this.password===''
    			}
    		},
    		methods: {
    			
    		}
    	}
    </script>
    
    <style>
    
    </style>
    
    

表单验证功能实现

  • 利用正则表达式完成邮箱功能验证js常用正则表达式

    methods: {
    			check(){
    				var ePattern = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
    				if(!ePattern.test(this.email)){
    					uni.showToast({
    						title:'邮箱格式不正确',
    						icon:"none"
    					})
    					return false;
    				}
    				return true;
    			},
    			submit(){
    				if(this.check()){
    					console.log("提交成功");
    				}
    				return;
    			}
    		}
    

编辑资料页面开发

编辑资料UI界面实现

  • 新建页面,配置page.json,配置导航

    ,{
                "path" : "pages/userInfo/userInfo",
                "style" :                                                                                    
                {
                    "navigationBarTitleText": "资料编辑"
                }
                
            }
    
  • 使用uni-list-item实现静态页面,使用插槽修改

    <template>
    	<view>
    		<uni-list-item title="头像" :border="false" >
    			<view slot="right" class="flex">
    				<image class="rounded" style="width: 100rpx; height: 100rpx;" src="../../static/default.jpg"></image>
    				<text class="flex align-center iconfont icon-bianji1 ml-2" ></text>
    			</view>
    		</uni-list-item>
    		<uni-list-item title="昵称" :border="false">
    			<view slot="right" class="flex ">
    				哈哈
    				<text class="flex align-center iconfont icon-bianji1 ml-2 " ></text>
    			</view>
    		</uni-list-item>
    		<uni-list-item title="性别" :border="false">
    			<view slot="right" class="flex ">
    				未知
    				<text class="flex align-center iconfont icon-bianji1 ml-2 " ></text>
    			</view>
    		</uni-list-item>
    		<uni-list-item title="生日" :border="false">
    			<view slot="right" class="flex ">
    				2021-4-1
    				<text class="flex align-center iconfont icon-bianji1 ml-2 " ></text>
    			</view>
    		</uni-list-item>
    		<uni-list-item title="情感" :border="false">
    			<view slot="right" class="flex ">
    				已婚
    				<text class="flex align-center iconfont icon-bianji1 ml-2 " ></text>
    			</view>
    		</uni-list-item>
    		<uni-list-item title="职业" :border="false">
    			<view slot="right" class="flex align-center">
    				程序员
    				<text class="flex align-center iconfont icon-bianji1 ml-2 " ></text>
    			</view>
    		</uni-list-item>
    		<uni-list-item title="家乡" :border="false">
    			<view slot="right" class="flex ">
    				广东广州
    				<text class="flex align-center iconfont icon-bianji1 ml-2 " ></text>
    			</view>
    		</uni-list-item>
    		
    		<view class="py-2 px-3">
    			<button class="bg-main text-white" style="border-radius: 50rpx;">完成</button>
    		</view>
    	</view>
    </template>
    
    <script>
    	import uniListItem from '@/components/uni-list-item/uni-list-item.vue';
    	export default {
    		components:{
    			uniListItem
    		},
    		data() {
    			return {
    				
    			}
    		},
    		methods: {
    			
    		}
    	}
    </script>
    
    <style>
    
    </style>
    
    

修改头像功能

  • 添加点击事件, 动态绑定userPIc

    <uni-list-item title="头像" :border="false">
    			<view slot="right" class="flex">
    				<image class="rounded" style="width: 100rpx; height: 100rpx;" :src="userPic"></image>
    				<text class="flex align-center iconfont icon-bianji1 ml-2"  @click="changePic" ></text>
    			</view>
    		</uni-list-item>
    
  • uni.chooseImage的使用, 修改头像功能实现

    changePic(){
    				uni.chooseImage({
    					count:1,
    					sizeType:["compressed"],
    					sourceType:["album","camera"],
    					success:(e)=>{
    						this.userPic=e.tempFilePaths[0];
    					}
    				})
    			}
    

showActionSheet接口使用

  • 修改昵称,用输入框

    <input v-model="nickname" class="text-right"/>
    
  • 修改性别, 使用showActionSheet,使用计算属性渲染

    <uni-list-item title="性别" :border="false">
    			<view slot="right" class="flex ">
    				{{sexText}}
    				<text class="flex align-center iconfont icon-bianji1 ml-2 " @click="changeSex"></text>
    			</view>
    		</uni-list-item>
    
    	const sexArray=["保密","男","女"];
    
    sex:0,
    
    sexText(){
    				return sexArray[this.sex];
    			},
    
    changeSex(){
    				uni.showActionSheet({
    					itemList:sexArray,
    					success:(e)=>{
    						// this.sex=sexArray[e.tapIndex];
    						this.sex=e.tapIndex;
    					}
    				})
    			},
    
  • 修改情感, 使用一样的方法

  • 修改职业, 使用一样的方法

    changeJob(){
    				uni.showActionSheet({
    					itemList:jobArray,
    					success:(e)=>{
    						this.job=jobArray[e.tapIndex];
    					}
    				})
    			}
    

修改生日功能实现

  • 使用picker,完成该功能

    <picker mode="date" :value="birthday" @change="onDateChange">
    			<uni-list-item title="生日" :border="false">
    				<view slot="right" class="flex ">
    					{{birthday}}
    					<text class="flex align-center iconfont icon-bianji1 ml-2 "></text>
    				</view>
    			</uni-list-item>
    		</picker>
    
    onDateChange(e){
    				this.birthday=e.detail.value;
    			}
    

三级城市联动多列选择器选择城市

  • 使用官方组件mpvueCityPicker

    <uni-list-item title="家乡" :border="false">
    			<view slot="right" class="flex ">
    				{{pickerText}}
    				<text class="flex align-center iconfont icon-bianji1 ml-2 " @click="showCityPicker"></text>
    			</view>
    		</uni-list-item>
    
    
     <mpvue-city-picker :themeColor="themeColor" ref="mpvueCityPicker" :pickerValueDefault="cityPickerValueDefault"
    		          @onConfirm="onConfirm"></mpvue-city-picker>
    
    import mpvueCityPicker from '@/components/mpvue-citypicker/mpvueCityPicker.vue'
    
    mpvueCityPicker
    
    				themeColor:'#007AFF',
    				cityPickerValueDefault:[0, 0, 1],
    				pickerText:'广东广州'
    
    onBackPress() {
    		          if (this.$refs.mpvueCityPicker.showPicker) {
    		            this.$refs.mpvueCityPicker.pickerCancel();
    		            return true;
    		          }
    		        },
    		onUnload() {
    		            if (this.$refs.mpvueCityPicker.showPicker) {
    		                this.$refs.mpvueCityPicker.pickerCancel()
    		            }
    		        },
    
    onConfirm(e){
    				this.pickerText = e.label;
    			},
    			showCityPicker(){
    				this.$refs.mpvueCityPicker.show()
    			}
    

帮助反馈页面开发

帮助反馈UI界面实现

  • 新建页面,配置page.json

  • 使用组件uni-collapse

    <view>
    		<uni-collapse accordion>
    			<uni-collapse-item title="默认开启" >
    				<text>折叠内容</text>
    			</uni-collapse-item>
    			<uni-collapse-item title="默认开启" >
    				<text>折叠内容</text>
    			</uni-collapse-item>
    		</uni-collapse>
    		<view class="py-2 px-3">
    			<button class="bg-main text-white" style="border-radius: 50rpx;">意见反馈</button>
    		</view>
    	</view>
    

关于页面开发

关于页面UI界面

  • 新建页面,配置page.json

  • 静态页面开发

    <view>
    		<view class="flex align-center justify-center flex-column pt-4 pb-3">
    			<image src="../../static/common/nothing.png" style="width: 300rpx; height: 300rpx;" class="rounded-circle"></image>
    			<text class="font text-muted mt-2">version 1.0.1</text>
    		</view>
    		<uni-list-item title="新版本检测" :border="false" link></uni-list-item>
    		<uni-list-item title="社区用户协议" :border="false" link></uni-list-item>
    	</view>
    

登录页开发

page.json配置

  • 新建页面,取消原生导航,导航进入

    ,{
                "path" : "pages/login/login",
                "style" :                                                                                    
                {
                    "navigationBarTitleText": "",
    				"app-plus": {
    					"titleNView": false
    				}
                }
                
            }
    
    <navigator url="../login/login">
    			<view class="flex align-center p-2" hover-class="bg-light">
    				<image src="../../static/default.jpg" style="width: 100rpx; height: 100rpx;" class="rounded-circle">
    				</image>
    				<view class="flex flex-column flex-1 px-2">
    					<text class="font-lg font-weight-bold text-dark ">昵称</text>
    					<text class="font text-muted mt-1"> 总帖子10 今日发帖0</text>
    				</view>
    				<view class="iconfont icon-jinru"></view>
    			</view>
    		</navigator>
    
  • x的样式开发

    <view class="flex iconfont icon-guanbi algin-center justify-center font-lg " style="width: 100rpx; height: 100rpx;
    		position: fixed; left: 0;"
    		:style="'top:'+statusBarHeight+'px;'" hover-class="bg-light" @click="back"></view>
    
    			var res=uni.getSystemInfoSync();
    			this.statusBarHeight=res.statusBarHeight;
    
    back(){
    				uni.navigateBack({
    					delta:1
    				})
    			}
    

登录页UI界面构建

  • 对之前的开发进行修改,引用一个view代替状态栏即可

    <template>
        <view>
            <view class="status_bar">
                <!-- 这里是状态栏 -->
            </view>
            <view> 状态栏下的文字 </view>
        </view>
    </template>    
    <style>
        .status_bar {
            height: var(--status-bar-height);
            width: 100%;
        }
    </style>
    
  • 静态页面开发

    <view class="flex iconfont icon-guanbi algin-center justify-center font-lg " style="width: 100rpx; height: 100rpx;
    		position: fixed; left: 0;" hover-class="bg-light" @click="back">
    		</view>
    
    		<view class="flex algin-center justify-center " style="margin-top: 300rpx;">
    			<text class="text-secondary " style="font-size: 60rpx;">账号密码登录</text>
    		</view>
    
    		<view class="flex  algin-center border-bottom py-3 px-2 " style="margin-top: 100rpx;">
    			<input type="text" placeholder="昵称/手机号/邮箱" class="" />
    		</view>
    		<view class="flex  algin-center border-bottom">
    			<input type="text" placeholder="请输入密码" class="py-3 px-2  flex-1" />
    			<text style="width: 150rpx;" class="text-muted py-3">忘记密码</text>
    		</view>
    
    		<view class="py-2 px-3 " style="margin-top: 100rpx;">
    			<button class="bg-main text-white" style="border-radius: 50rpx;">登录</button>
    		</view>
    
    		<view class="mt-5 flex algin-center justify-center">
    			<view class="text-primary pr-2">验证码登录</view>
    			<view class="text-secondary">|</view>
    			<view class="text-primary pl-2">登录遇到问题</view>
    		</view>
    		
    		<view class="flex algin-center justify-center mt-5">
    			<view style="width: 100rpx; border-bottom: solid #ddd ;" class="mb-2" ></view>
    			<view class="text-muted mx-2">社交账号登录</view>
    			<view style="width: 100rpx; border-bottom: solid #ddd ; "class="mb-2" ></view>
    		</view>
    

登录类型切换效果实现

  • 静态开发图标列表

    <view class="flex align-center px-5 py-3" style="padding-left: 100rpx; padding-right: 100rpx;">
    
    			<view class="flex-1 flex align-center justify-center">
    
    				<view
    					class="iconfont icon-QQ font-lg bg-primary  text-white flex align-center justify-center rounded-circle "
    					style="width: 100rpx;height: 100rpx;">
    				</view>
    
    			</view>
    			<view class="flex-1 flex align-center justify-center ">
    
    				<view
    					class="iconfont icon-QQ font-lg bg-primary  text-white flex align-center justify-center rounded-circle"
    					style="width: 100rpx;height: 100rpx;">
    				</view>
    
    			</view>
    			<view class="flex-1 flex align-center justify-center ">
    
    				<view
    					class="iconfont icon-QQ font-lg bg-primary  text-white flex align-center justify-center rounded-circle"
    					style="width: 100rpx;height: 100rpx;">
    				</view>
    
    			</view>
    
    		</view>
    
    		<view class="flex algin-center justify-center px-5 text-muted">
    			注册即代表同意<text class="text-primary">《xxx社区协议》</text>
    		</view>
    
  • 切换验证码的静态显示

    <view class="flex algin-center justify-center " style="margin-top: 300rpx;">
    			<text class="text-secondary " style="font-size: 60rpx;">
    				{{status?'账号密码登录':'验证码登录'}}</text>
    		</view>
    
    		<template v-if="status">
    			<view class="flex  algin-center border-bottom py-3 px-2 " style="margin-top: 100rpx;">
    				<input type="text" placeholder="昵称/手机号/邮箱" class="" />
    			</view>
    			<view class="flex  algin-center border-bottom">
    				<input type="text" placeholder="请输入密码" class="py-3 px-2  flex-1" />
    				<text style="width: 150rpx;" class="text-muted py-3">忘记密码</text>
    			</view>
    			
    		</template>
    		
    		<template v-else>
    			<view class="flex  algin-center border-bottom py-3 px-2 " style="margin-top: 100rpx;">
    				<text class="text-dark mr-2">+86</text>
    				<input type="text" placeholder="手机号" class="" />
    			</view>
    			<view class="flex  algin-center border-bottom px-2">
    				<input type="text" placeholder="请输入验证码" class="py-3 px-2  flex-1" />
    				<text style="width: 200rpx;" class="text-white bg-main py-3 flex justify-center">获取验证码</text>
    			</view>
    		</template>
    
    changeStatus(){
    				this.status=!this.status
    			}
    

表单基础功能实现

  • 输入框绑定内容,计算属性disable要对于账号密码与手机验证码都ok

    <input type="text" placeholder="昵称/手机号/邮箱" v-model="username" class="" />
    
    disabled(){
    				if((this.username===''||this.password==='')&&(this.phone===''||this.code==='')){
    					return true;
    				}
    				return false;
    			}
    
    <button class="bg-main text-white" style="border-radius: 50rpx;" :disabled="disabled">登录</button>
    
  • 切换登录方式要初始化表单

    initForm(){
    				this.username='';
    				this.password='';
    				this.phone='';
    				this.code='';
    			},
    			changeStatus(){
    				this.initForm();
    				this.status=!this.status
    			}
    
  • 获取验证码的功能, 倒计时的功能

    getCode(){
    				if(this.codeTime>0){
    					return;
    				}
    				this.codeTime=60;
    				let  timer=setInterval(()=>{
    					if(this.codeTime>=1){
    						this.codeTime--;
    					}else{
    						this.codeTime=0;
    						clearInterval(timer);
    					}
    				},1000)
    			}
    
    <text style="width: 200rpx;" class="text-white  py-3 flex justify-center" @click="getCode"
    				:class="codeTime>0?'bg-main-disable':'bg-main'">
    				{{codeTime>0?this.codeTime+'s':'获取验证码'}}</text>
    
  • 验证手机号规则编写,用正则表达式验证, 提交方法绑定

    getCode() {
    				if (this.codeTime > 0) {
    					return;
    				}
    				if(!this.validate()){
    					return;
    				}
    				this.codeTime = 60;
    				let timer = setInterval(() => {
    					if (this.codeTime >= 1) {
    						this.codeTime--;
    					} else {
    						this.codeTime = 0;
    						clearInterval(timer);
    					}
    				}, 1000)
    			},
    			validate() {
    				var mPattern = /^1[34578]\d{9}$/;
    				var flag = mPattern.test(this.phone)
    				// console.log(flag);
    				if (!flag) {
    					uni.showToast({
    						title: '手机格式不正确',
    						icon: "none"
    					})
    					return false;
    				}
    				return true;
    			},
    			submit() {
    				if(!this.validate()){
    					return;
    				}
    				console.log('验证成功');
    				this.validate();
    			}
    

第三方登录组件功能实现

  • 新建other-login组件,实现第三方登录

    <template>
    	<view class="flex align-center px-5 py-3" style="padding-left: 100rpx; padding-right: 100rpx;">
    	
    		<view class="flex-1 flex align-center justify-center" v-for="(item,index) in this.resultList" :key
    		="index">
    	
    			<view :class="item.icon+' '+item.bgColor"
    				class="iconfont  font-lg   text-white flex align-center justify-center rounded-circle "
    				style="width: 100rpx;height: 100rpx;">
    			</view>
    	
    		</view>
    		
    	
    	</view>
    </template>
    
    <script>
    	export default{
    		data(){
    			return {
    				providerList: [],
    				resultList:[]
    			}
    		},
    		mounted() {
    			uni.getProvider({
    				service: 'oauth',
    				success: (result) => {
    					this.providerList = result.provider.map((value) => {
    						let providerName = '';
    						let icon='';
    						let bgColor='';
    						switch (value) {
    							case 'weixin':
    								providerName = '微信登录'
    								icon='icon-weixin';
    								bgColor='bg-success';
    								break;
    							case 'qq':
    								providerName = 'QQ登录';
    								icon='icon-QQ';
    								bgColor='bg-primary';
    								break;
    							case 'sinaweibo':
    								providerName = '新浪微博登录'
    								icon='icon-xinlangweibo';
    								bgColor='bg-danger';
    								break;
    							default:
    								break;
    		
    						}
    						return {
    							name: providerName,
    							id: value,
    							icon:icon,
    							bgColor:bgColor
    						}
    					});
    					console.log(this.providerList);
    					for(var i=0;i<this.providerList.length;i++){
    						if(this.providerList[i].id==='weixin'||this.providerList[i].id==='qq'||
    						this.providerList[i].id==='sinaweibo'){
    							this.resultList.push(this.providerList[i]);
    						}
    					}
    					console.log(this.resultList);
    				},
    				fail: (error) => {
    					console.log('获取登录通道失败', error);
    				}
    			});
    		}
    	}
    </script>
    
    <style>
    </style>
    
    

个人空间开发

page.json配置

  • 新建页面, 配置导航栏按钮,导航进入

     ,{
                "path" : "pages/user-space/user-space",
                "style" :                                                                                    
                {
                    "navigationBarTitleText": "",
    				"app-plus": {
    					"titleNView": {
    						"titleText": "个人空间",
    						"buttons": [
    							{
    								"type": "menu"
    							}
    						]
    					}
    				}
                }
                
            }
    
    openSapce() {
    				uni.navigateTo({
    					url:'../../pages/user-space/user-space'
    				})
    			},
    

个人空间头部开发

  • 静态开发

    <view class="flex align-center justify-center p-3 border-bottom border-light-secondary">
    			<image src="../../static/default.jpg" class="rounded " style="width: 180rpx; height: 180rpx;"></image>
    			<view class="flex flex-column flex-1 align-center justify-center " >
    				<view class="flex align-center justify-center " style="width: 400rpx;">
    					<view class=" flex-1 flex  align-center justify-center flex-column ">
    						<text class="font-lg font-weight-bold">1</text>
    						<text class="font text-muted">粉丝</text>
    					</view>
    					<view class=" flex flex-1 align-center justify-center flex-column">
    						<text class="font-lg font-weight-bold">1</text>
    						<text class="font text-muted">粉丝</text>
    					</view>
    					<view class=" flex flex-1 align-center justify-center flex-column">
    						<text class="font-lg font-weight-bold">1</text>
    						<text class="font text-muted">粉丝</text>
    					</view>
    				</view>
    				<view class="flex align-center justify-center pt-2">
    					<button class="bg-main text-white" style="width: 400rpx;">关注</button>
    				</view>
    			</view>
    		</view>
    

个人空间UI界面实现

  • 借用好友列表的tabBar

    <view class="flex align-center py-4" style="height: 100rox;">
    			<text class="flex-1 flex align-center justify-center" v-for="(item,index) in tabBars" :key="index"
    				:class="tabIndex===index?'font-lg text-main font-weight-bold':'font-md text-dark'"
    				@click="changeTab(index)">{{item.name}}</text>
    		</view>
    
    data() {
    			return {
    				tabIndex:0,
    				tabBars: [{
    						name: '主页',
    
    					},
    					{
    						name: '帖子',
    
    					},
    					{
    						name: '动态',
    
    					}
    				]
    			}
    		},
    
    changeTab(index){
    				this.tabIndex=index;
    			}
    
  • 主页的实现

    <template v-if="tabIndex===0">
    			<view class="px-3 border-bottom py-2">
    				<view class="font-md">账号信息</view>
    				<view class="font">账号年龄:12个月</view>
    				<view class="font">账号id:1</view>
    			</view>
    			<view class="px-3 border-bottom py-2">
    				<view class="font-md">个人信息</view>
    				<view class="font">星座:天蝎座</view>
    				<view class="font">职业:IT</view>
    				<view class="font">故乡:中国</view>
    				<view class="font">情感:未婚</view>
    			</view>
    		</template>
    		<template v-else>
    			<text>帖子/动态</text>
    		</template>
    
  • 帖子动态的实现, 引入commonlist组件,loadMore组件,引入方法,添加动画效果

    <view class="animated fast fadeIn">
    				<block v-for="(item,index) in list" :key="index">
    					<commonList :item="item" :index="index" @follow="follow" @doSupport="doSupport">
    					</commonList>
    					<divider></divider>
    				</block>
    				<loadMore :loading="loading"></loadMore>
    			</view>
    
    			follow(index) {
    				let obj=this.tabBars[this.tabIndex].list[index];
    				obj.isFollow=true;
    				uni.showToast({
    					title: '关注成功'
    				})
    			},
    			doSupport(e) {
    				let obj=this.tabBars[this.tabIndex].list[e.index]
    				console.log(obj);
    				if (obj.support.type === '') {
    					//无操作
    					obj.support[e.type + '_count']++;
    				} else if (obj.support.type === 'support' && e.type === 'unsupport') {
    					//之前是顶,顶减一,踩加一
    					obj.support.support_count--;
    					obj.support.unsupport_count++;
    				} else if (obj.support.type === 'unsupport' && e.type === 'support') {
    					//之前是踩,顶加一,踩减一
    					obj.support.support_count++;
    					obj.support.unsupport_count--;
    				}
    				obj.support.type = e.type;
    				let msg = e.type === 'support' ? '顶' : '踩';
    				uni.showToast({
    					title: msg + '成功'
    				})
    			},
    

个人空间操作菜单

  • 使用弹出层,进行修改即可

    <uni-popup ref="popup" type="top" background-color="#fff">
    			<view class="flex justify-center align-center font-md border-bottom py-2" hover-class="bg-light"
    			@click="popupEvent('findFriend')">
    				<text class="iconfont icon-sousuo mr-2" ></text>加入黑名单
    			</view>
    			<view class="flex justify-center align-center font-md py-2" hover-class="bg-light"
    				@click="popupEvent('deleteList')">
    				<text class="iconfont icon-shanchu mr-2"></text>聊天
    			</view>
    		</uni-popup>
    
    onNavigationBarButtonTap() {
    			this.$refs.popup.open();
    		},
    

全局功能开发

清楚缓存的功能

  • 添加点击事件,清除缓存的方法

==文档只有一些功能缺失,但源码已经完善所有功能,详情请点击码云地址下载源码学习 https://gitee.com/HelLichu/friend ==

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
你好!如果你想使用uniapp开发app,我可以为你提供一些相关信息。Uniapp是一个基于Vue.js的开发框架,它可以将代码编译为多个平台(包括iOS、Android、H5等)。通过使用uniapp,你只需要编写一次代码,就可以在不同平台上运行。 为了开始使用uniapp开发app,你需要安装uni-app的开发环境。首先,确保你已经安装了Node.js和Vue CLI(如果你之前没有安装过)。然后,你可以通过以下命令安装uni-app: ``` npm install -g @vue/cli vue create -p dcloudio/uni-preset-vue my-project cd my-project npm run dev ``` 上述命令中,我们首先全局安装Vue CLI,然后使用uni-preset-vue创建一个新的uni-app项目,并进入项目目录。最后,通过运行npm run dev命令,你就可以在本地启动一个开发服务器,并在浏览器中预览你的app。 在开始开发之前,你需要熟悉Vue.js的基本知识。如果你已经熟悉Vue.js,那么使用uniapp开发app会更加容易上手。 在uniapp中,你可以使用Vue的语法编写页面和组件。此外,uniapp还提供了一些平台特定的API和组件,以实现更深入的原生功能。 一旦你完成了app的开发,你可以使用uniapp提供的命令来构建app。具体的构建命令将根据你要构建的平台而有所不同。例如,如果你要构建iOS应用,你可以运行以下命令: ``` npm run build:ios ``` 这是一个简单的介绍,希望能帮助到你开始使用uniapp开发app。如果你有进一步的问题,请随时提问!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值