小程序(创客+)一点一点搬家(解读)

一些以后可能用到的资源

  • 小程序图标资源:https://www.easyicon.net/iconsearch/app%E5%9B%BE%E6%A0%87/?s=addtime_DESC
  • 坐标拾取:http://api.map.baidu.com/lbsapi/getpoint/index.html
  • 微信小程序案例最全整理:https://www.jianshu.com/p/4a6cac171de0

进销存:https://blog.csdn.net/luoxuanewei/article/details/88345388

1. 小程序样例学习

目标是分析这个小程序的实现的细节,进而熟悉如何使用组件、样式、布局。

小程序是从这里下载到的:http://www.see-source.com/weixinwidget/detail.html?wid=56

后面会照抄一下代码,并且对抄过来的代码进行分析。里面关于样式的,尽量是在当前页面的wxss里面来实现,并且增加一些注释说明便于理解。

在已经完成了所有的页面转移(抄袭)之后,发现这个小程序的页面基本上是常规组件的使用,类似swiper、navigator、wx.xxx、tabBar这些,其他是通过view+css来渲染完成。

里面有些功能比较好用,比如:

  • “服务(首页)index”的排版

  • “会议室列表conference”里面的面板筛选

  • “活动activity”里面的scroll-view

  • “众创空间space”里面的tag高亮

  • “众创空间 -> 入住申请apply”比较全的表单

  • “园区问问question”上传图片
    代码已经上传到github:https://github.com/kelvinliu11/chuangke-

2. 服务(首页)index

2.1. 概要图(首页)

这个图看起来比较典型,导航+轮播图+图标菜单+tabBar

2.2. 首页关键功能

2.2.1. navigator

看起来navigator只是设置了背景色和文字“创客+”,在app.json中设置全局样式

  "window":{
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#f7982a",
    "navigationBarTitleText": "创客+",
    "navigationBarTextStyle":"white"
  },

navigationBarBackgroundColor背景色

navigationBarTextStyle字体颜色

2.2.2. tabBar

tabBar看起来是通过3个图片+text来实现的。(图片全部从原项目中拷贝过来)

"tabBar": {
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "服务",
        "iconPath": "images/xihuan.png",
        "selectedIconPath": "images/xihuanfill.png"
      },
      {
        "pagePath": "pages/activity/activity",
        "text": "活动",
        "iconPath": "images/biaoxing.png",
        "selectedIconPath": "images/biaoxingfill.png"
      },
      {
        "pagePath": "pages/my/my",
        "text": "我发起的",
        "iconPath": "images/yonghu.png",
        "selectedIconPath": "images/yonghufill.png"
      }
    ],
    "color": "#333",
    "selectedColor": "#f7982a",
    "backgroundColor": "#f6f6f6",
    "borderStyle": "white"
  },

“selectedColor”: "#f7982a"要设置为黄色,不然默认是绿色,不协调

“backgroundColor”: “#f6f6f6”, tabBar的背景色,不设置的话是白色底

“borderStyle”: "white"默认不设置的话会有一条黑线,在tabBar上方

2.2.3. swiper

<view class="container">
  <swiper indicator-dots="{{true}}"
    autoplay="{{true}}" interval="{{4000}}" duration="{{1000}}">
    <block wx:for="{{imgUrls}}" wx:key="*this">
      <swiper-item>
        <image src="{{item}}" mode="aspectFill" class="slide-image"/>
      </swiper-item>
    </block>
  </swiper>
	<view class="index-menu">
		<navigator class="index-menu-item" wx:for="{{indexmenu}}" wx:key="{{item.url}}" url="../{{item.url}}/{{item.url}}">
			<image src="{{item.icon}}"></image>
			<text>{{item.text}}</text>
		</navigator>
	</view>
</view>

分析swiper参数:

indicator-dots是否显示面板指示点。在滑块视图上的点。轮播图。

autoplay自动切换

interval自动切换时间间隔

duration滑动动画时长

block wx:for,block的作用就是把这些swiper-item放在一起,没有实际的意义。官网的解释:

<block/> 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。

  • 这个时候,发现swiper里的图片不是在swiper控件上铺满的

在swiper组件上加上class=“index-banner”,并且在wxss上加上以下的样式

.index-banner{
	width: 100%;
	height: 474rpx;
}
.index-banner .slide-image{
	width: 100%;
}

index-banner控制宽度和高度

index-banner .slide-image控制里面图片的宽度

mode="aspectFill"控制,aspectFill缩放模式,保持纵横比缩放图片,只保证图片的短边能完全显示出来。也就是说,图片通常只在水平或垂直方向是完整的,另一个方向将会发生截取。

2.2.4. 正文中的几个快速链接navigator

wxml

<view class="index-menu">
		<navigator class="index-menu-item" wx:for="{{indexmenu}}" wx:key="{{item.url}}" url="../{{item.url}}/{{item.url}}">
			<image src="{{item.icon}}"></image>
			<text>{{item.text}}</text>
		</navigator>
	</view>

wxss

.index-menu {
  width: 100%;
  display: -webkit-flex;
  display: -webkit-box;
  display: flex;
  -webkit-flex-wrap: wrap;
  flex-wrap: wrap;
  background: #fff;
}

.index-menu-item {
  -webkit-flex: 0 0 25%;
  -webkit-box-flex: 0;
  flex: 0 0 25%;
  max-width: 25%;
  text-align: center;
  margin-top: 10rpx;
  padding: 20rpx 20rpx;
  box-sizing: border-box;
  margin-bottom: -1rpx;
}

.index-menu-item image {
  width: 110rpx;
  height: 110rpx;
}

.index-menu-item text {
  display: block;
  font-size: 30rpx;
  line-height: 1.4;
  white-space: nowrap;
}

到此,可以展示出快捷导航按钮,但是快捷导航按钮点击后无法跳转,需要增加下面的方法

changeRoute:function(url){
    wx.navigateTo({
      url: `../${url}/${url}`
    })
  },

但是还是跳转不起来,是因为没有在app.json配置跳转后的页面,比如pages里面加上"pages/space/space",就可以跳转了

还有一些小的改进,比如轮播图和快速导航按钮需要从后台接口抓取,这样就比较灵活,那么只需要在index.js改造一下获取数据的方式即可:

定义fetchData方法:

fetchData:function(){
    this.setData({
      indexmenu:[
        {
          'icon':'./../../images/icon_01.png',
          'text':'众创空间',
          'url':'space'
        },
        {
          'icon':'./../../images/icon_03.png',
          'text':'服务集市',
          'url':'service'
        },
        {
          'icon':'./../../images/icon_05.png',
          'text':'会议室预定',
          'url':'conference'
        },
        {
          'icon':'./../../images/icon_07.png',
          'text':'云资源申请',
          'url':'resource'
        },
        {
          'icon':'./../../images/icon_09.png',
          'text':'园区问问',
          'url':'question'
        },
        {
          'icon':'./../../images/icon_11.png',
          'text':'物业服务',
          'url':'property'
        },
        {
          'icon':'./../../images/icon_13.png',
          'text':'入驻申请',
          'url':'apply'
        }
      ],
      imgUrls: [
        '../../images/banner_02.jpg',
        '../../images/banner_02.jpg',
        '../../images/banner_02.jpg',
      ]
    })
  },

在页面加载onLoad的时候调用:

onLoad: function (options) {
    this.fetchData();
  },

3. 活动(tabBar中间)activity

3.1. 概要图

3.2. 活动页面关键功能

3.2.1. 排序

先创建排序的view:

<view class="container">
	<view class="filter-flex">
		<view class="filter-tab sort-tab">
			<text bindtap="setSortBy" data-sortindex="{{index}}" data-sortid="{{item.id}}" class="{{sortindex==index?'active':''}}" wx:for="{{sort}}" wx:key="{{item.id}}">{{item.title}}</text>
		</view>
	</view>
</view>

给加上样式:

.filter-tab{
	display: flex;
	width: 100%;
	line-height: 80rpx;
	border-bottom: 1rpx solid #ddd;
	position: relative;
	z-index: 2;
	background: #fff;
}
.filter-tab text{
	flex: 1;
	text-align: center;
}
.filter-tab text:after{
	content: '';
	display: inline-block;
	vertical-align: 4rpx;
	width: 0;
	height: 0;
	border-left: 12rpx solid transparent;
	border-right: 12rpx solid transparent;
	border-top: 12rpx solid #bbb;
	margin-left: 8rpx;
}
.filter-tab text.active{
	color: #f7982a;
}
.filter-tab:not(.sort-tab) text.active:after{
	border-top: 0;
	border-bottom: 12rpx solid #f7982a;
}
.filter-tab.sort-tab text.active:after{
	border-top: 12rpx solid #f7982a;
}

加上js方法,用来在点击排序的时候调用:

setSortBy:function(e){ //选择排序方式
    const d= this.data;
    const dataset = e.currentTarget.dataset;
    this.setData({
      sortindex:dataset.sortindex,
      sortid:dataset.sortid
    })
    console.log('排序方式id:'+this.data.sortid);
  },

里面的元素在data里设置初始化数据:

    sortindex:0,  //排序索引
    sortid:null,  //排序id

到此,页面样式和点击之后的高亮效果就完成了,并且点击的时候可以知道是按照什么排序的。

3.2.2. 滚动列表scroll-view

先把页面上的元素写上,暂时不考虑样式情况

<scroll-view class="container-body" scroll-y="true" scroll-top="{{scrolltop}}" bindscroll="scrollHandle" lower-threshold="50" bindscrolltolower="scrollLoading">
		<view class="conference-list">
			<navigator class="conference-item" wx:for="{{activitylist}}" wx:key="{{item.id}}" url="../activitydetail/activitydetail?id={{item.id}}">
				<view class="conference-item-img">
					<image src="{{item.imgurl}}" mode="aspectFill"></image>
					<text class="hover{{index}}" data-status="{{item.status}}">{{item.status}}</text>
				</view>
				<view class="conference-item-text">
					<view class="conference-item-title">{{item.name}}</view>
					<view class="conference-item-info activity-item-info">
						<text class="icon-time">{{item.time}}</text>
						<text class="icon-xinxi">{{item.coments}}</text>
					</view>
					<view class="conference-item-info">
						<text class="icon-zuobiao">{{item.address}}</text>
					</view>
				</view>
			</navigator>
		</view>
	</scroll-view>
  • scroll-y允许纵向滚动

  • scroll-top设置竖向滚动条位置

  • bindscroll滚动时触发,event.detail = {scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY}

  • lower-threshold距底部/右边多远时,触发 scrolltolower 事件

  • bindscrolltolower滚动到底部/右边时触发

问题1:分别在js中加上scrollHandle、scrollLoading,发现并没有出现更多的数据,需要调试一下看看。试验了一下,scroll-view如果没有设置height,那么bindscroll、bindscrolltolower事件都不会触发,但是如果手动给scroll-view设置高度,那么就要考虑适配。在原来的案例中,是没有设置高度的,这个需要考虑一下。

为了解决这个问题,网上有关于scroll-view高度计算的:https://www.cnblogs.com/dayin1/p/13188267.html

经过尝试,发现在app.wxss里有关于Page的样式如下,加上之后,不用设置scroll-view高度,也可触发事件:

page{
	height: 100%;
	color: #333;
  	display: flex;
  	flex-direction: column;
 	font-family:;
 	font: normal 30rpx/1.68 -apple-system-font, 'Helvetica Neue', Helvetica, 'Microsoft YaHei', sans-serif;
}

在这里发现了一个问题,原先顶部的排序功能,在滑动的时候会被隐藏起来,这个跟要求不符。看一下如何实现排序的顶部功能固定。—可能是眼睛花了,现在不能复现,考虑可能是加了page样式,这一块会被固定。经过验证,事实的确如此。这一块要加强flex布局部分的学习。

在增加一些关于图片底部的样式排版,就可以实现效果,主要还是flex布局的内容。

问题2:原来代码有个bug,就是在wxss里面设置图片是有问题的,图片无法加载,报错“wxss 中的本地资源图片无法通过 WXSS 获取”

将图片user_bg.jpg 转换为base64,地址https://www.sojson.com/image2base64.html(此地址访问不存在,请用这个试试http://tool.chinaz.com/tools/imgtobase,都不行的话,网上自行搜索 图片转Base64,多尝试,一定会行的),在这里把要使用的图片转换一把,然后将得到的字符放到background-image属性值中,类似于这样:background-image: url(“data:image/jpg;base64,/9j/4QMZR…”);

问题3: wx:key="{{item.id}}" does not look like a valid key name (did you mean wx:key=“id” ?)

怀疑是新更新的内容?还没有尝试使用,只是在网上翻了些文章,后面再详细看:https://developers.weixin.qq.com/community/develop/doc/000600fb83c158c1e26999fa951400

至此,“活动”页就全部实现了,包含顶部的排序、scroll-view部分、回到顶部、到底部再次加载数据功能。

4. 活动详情页 activitydetail

4.1. 概要图

4.2. 活动详情页关键功能点

4.2.1. 轮播图,带图上index

这些基本都是常规组件,以view为基础,加上样式即可,没有特殊的地方

wxml

<view class="container">
	<view class="container-body space-content">
		<view class="space-top">
			<view class="space-banner" bindtap="imgPreview">
				<swiper autoplay="{{true}}" interval="{{4000}}" duration="{{1000}}" bindchange="setCurrent">
					<block wx:for="{{spaceimgs}}" wx:key="*this">
						<swiper-item>
							<image src="{{item}}" mode="aspectFill" class="slide-image" />
						</swiper-item>
					</block>
				</swiper>
				<view class="number-banner">
					<text>{{currentIndex>9?currentIndex:'0'+currentIndex}}</text>
					<text>/{{spaceimgs.length>9?spaceimgs.length:'0'+spaceimgs.length}}</text>
				</view>
				<view class="space-info">
					<view class="space-title">{{activitydata.name}}</view>
					<view class="space-list">
						<view class="space-item">
							<text class="text-left">活动时间:</text>
							<text class="text-right">{{activitydata.date}}</text>
						</view>
						<view class="space-item">
							<text class="text-left">活动地点:</text>
							<text class="text-right">{{activitydata.address}}</text>
						</view>
						<view class="space-item">
							<text class="text-left">报名情况:</text>
							<text class="text-right">已报名<text class="text-orange">{{activitydata.hasentered}}</text>人/限额<text class="text-orange">{{activitydata.total}}</text></text>
						</view>
						<view class="space-item">
							<text class="text-left">主办方:</text>
							<text class="text-right">{{activitydata.hoster}}</text>
						</view>
					</view>
				</view>
			</view>
		</view>
		<view class="space-block">
	  	<view class="space-block-title">活动介绍</view>
	  	<view class="space-block-content">
	  		<view class="space-passage">平台工作室配置办公桌、椅、文件柜等办公家具,提供空调、网络配套到位,入驻机构可以实现“拎包试制”的便捷创业梦想。平台设立了集商务洽谈、产品展示、沙龙论坛等多功能为一体的商务中心,以及会议室,供学习交流,参观访问。</view>
	  		<view class="space-passage">特色描述:长三角创业汇免费办理公司注册、创业辅导、财务记账、税务咨询、创业孵化、创新大赛、创业营活动、项目转化、创新基金申报、交流合作、市场调研、宣传推广、会务会展、评估认证、法律援助、资金扶持等,为青年创业者提供信息、渠道、场地、资金等支持和服务。</view>
	  		<view class="space-passage">地点描述:交通便利,可乘坐公交或地铁,及多处基础设施建设,银行、医院、餐饮、超市等。</view>
	  	</view>
  	</view>
  	<view class="space-block">
	  	<view class="space-block-title">评论</view>
	  	<view class="space-block-content"></view>
  	</view>
	</view>

	<view class="container-footer">
		<text class="apply-btn">我要报名</text>
	</view>
</view>

样式wxss,已经加好了注释

/* swiper轮播图样式 */
.space-banner{
	position: relative;
}

.space-top,.space-block{
	padding: 20rpx;
	background: #fff;
	margin-bottom: 20rpx;
	border-bottom: 1rpx solid #ddd;
}

.space-banner swiper{
	width: 100%;
	height: 360rpx;
}

.space-banner .slide-image{
	width: 100%;
	height: 360rpx;
}


/* 这里是在swiper上显示数字的样式 */
.number-banner{
	position: absolute;
	right: 40rpx;
	margin-top: -80rpx;
	padding: 0 16rpx;
	background: rgba(0,0,0,.3);
	border-radius: 6rpx;
	color: #fff;
	font-size: 36rpx;
}
.number-banner text:last-child{
	color: rgba(255,255,255,.6);
	font-size: 30rpx;
}

/* 下面是swiper下面的活动概述部分 */
.space-title{
	font-size: 44rpx;
	line-height: 2;
}

.space-item{
	display: flex;
	font-size: 32rpx;
	color: #555;
	padding: 16rpx 0;
	border-bottom: 1rpx solid #eee;
}

/* 下面是活动介绍样式 */
.space-block{
	border-top: 1rpx solid #ddd;
}
.space-block-title{
	font-size: 40rpx;
}
/* 在“活动介绍”前面加一个竖亮黄条 */
.space-block-title:before{
	content: '';
	display: inline-block;
	vertical-align: -6rpx;
	width: 6rpx;
	height: 40rpx;
	background: #f7982a;
	margin-right: 8rpx;
}
/* 活动介绍里面的文字样式 */
.space-passage{
	font-size: 30rpx;
	text-indent: 2em;
	margin-top: 20rpx;
}

/* 我要报名  按钮样式 */
.container-footer text.apply-btn{
	background: #f7982a;
	color: #fff;
	flex: 1.5;
}
.container-footer text{
	flex: 1;
	display: block;
	text-align: center;
	height: 88rpx;
	line-height: 88rpx;
	font-size: 34rpx;
	border-left: 1rpx solid #ddd;
}

js部分,基本都是抄的,没有特殊的地方

// pages/activitydetail/activitydetail.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    spaceimgs:[],
    currentIndex:1,
  },

  // 点击图片预览
  imgPreview: function(){ //图片预览
    const imgs = this.data.spaceimgs;
    wx.previewImage({
      current: imgs[this.data.currentIndex-1], // 当前显示图片的http链接
      urls: imgs // 需要预览的图片http链接列表
    })
  },

  setCurrent: function(e){
    this.setData({
      currentIndex:e.detail.current+1
    })
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.setData({
      activitydata:{
        "name": "云栖技术分享日(云栖TechDay0)",
        "date": "2016/06/08 14:00",
        "hasentered":60,
        "total":200,
        "address":'上海市松江区莘砖公路518号双子楼1楼',
        "hoster": "上海爱普科技有限公司"
      },
      spaceimgs:["http://139.196.218.128/SjPark/UserFile/Files/Thumbnail/46932530-4bc8-48dc-bf10-1e5e39d254b8_750x470.png","http://139.196.218.128/SjPark/UserFile/Files/Thumbnail/73efa039-6c54-43c6-8ad9-70f831723e2e_750x470.png","http://139.196.218.128/SjPark/UserFile/Files/Thumbnail/eb8bbf4d-e236-4c92-900c-67d8b941b02a_750x470.png"]
    })
    wx.setNavigationBarTitle({
      title: this.data.activitydata.name
    })
  }
})

5. 众创空间space

5.1. 概要图

5.2. 关键功能点

通过概要图,大概可以看到里面包含:swiper、概要描述、基本介绍和底部功能入口,看起来是常规功能。

其中有个,就是点击文字后,调起地图组件,在地图上显示对应的位置。入口在space.js里面的getAddress方法。

wxml排版:

<view class="container">
	<view class="container-body space-content">
		<view class="space-top">
			<view class="space-banner" bindtap="imgPreview">
				<swiper autoplay="{{true}}" interval="{{4000}}" duration="{{1000}}" bindchange="setCurrent">
					<block wx:for="{{spaceimgs}}" wx:key="*this">
						<swiper-item>
							<image src="{{item}}" mode="aspectFill" class="slide-image" />
						</swiper-item>
					</block>
				</swiper>
				<view class="number-banner">
					<text>{{currentIndex>9?currentIndex:'0'+currentIndex}}</text>
					<text>/{{spaceimgs.length>9?spaceimgs.length:'0'+spaceimgs.length}}</text>
				</view>
			</view>
			<view class="space-info">
				<view class="space-title">{{spacedata.ParkName}}</view>
				<view class="space-tags">
					<text wx:for="{{spacedata.TagIDs}}" wx:key="*this">{{item}}</text>
				</view>
				<view class="space-list">
					<view class="space-item">
						<text class="text-left">收费标准:</text>
						<text class="text-right">
  	  				<text class="text-orange">{{spacedata.FeeScale}}</text>{{spacedata.FeeScaleRoomUnit}}
						</text>
					</view>
					<view class="space-item">
						<text class="text-left">可租面积:</text>
						<text class="text-right">{{spacedata.FeeScaleRoomUnitValue}}㎡</text>
					</view>
					<view class="space-item">
						<text class="text-left">地理位置:</text>
						<text class="text-right" data-address="{{spacedata.Address}}" data-latitude="{{spacedata.latitude}}" data-longitude="{{spacedata.longitude}}" bindtap="getAddress">{{spacedata.Address}}</text>
					</view>
				</view>
			</view>
		</view>
    <view class="space-block">
	  	<view class="space-block-title">基本介绍</view>
	  	<view class="space-block-content">
	  		<view class="space-list">
	  			<view class="space-item">
	  				<text class="text-left">总建筑面积:</text>
	  				<text class="text-right">{{spacedata.TotalBulidingArea}}㎡</text>
	  			</view>
	  			<view class="space-item">
	  				<text class="text-left">得房率:</text>
	  				<text class="text-right">{{spacedata.RoomRate}}%</text>
	  			</view>
	  			<view class="space-item">
	  				<text class="text-left">总工位:</text>
	  				<text class="text-right">{{spacedata.TotalWorkstation}}个</text>
	  			</view>
	  			<view class="space-item">
	  				<text class="text-left">总的独立办公室:</text>
	  				<text class="text-right">{{spacedata.TotalRoom}}个</text>
	  			</view>
	  		</view>
	  		<view class="space-passage">{{spacedata.Summary}}</view>
	  	</view>
	  </view>
    <view class="space-block">
	  	<view class="space-block-title">优惠政策</view>
	  	<view class="space-block-content">
	  		<view class="space-passage">{{spacedata.Policy}}</view>
	  	</view>
  	</view>
	</view>

  <view class="container-footer">
		<text>联系责任人</text>
		<text bindtap="reserveHandle">预约看房</text>
		<text class="apply-btn" bindtap="goApply">入驻申请</text>
	</view>
</view>

wxss样式,里面加了备注,把公共的也放在里面的,这样会比较清晰一点:

/* swiper轮播图样式 */
.space-banner{
	position: relative;
}

.space-top,.space-block{
	padding: 20rpx;
	background: #fff;
	margin-bottom: 20rpx;
	border-bottom: 1rpx solid #ddd;
}

.space-banner swiper{
	width: 100%;
	height: 360rpx;
}

.space-banner .slide-image{
	width: 100%;
	height: 360rpx;
}


/* 这里是在swiper上显示数字的样式 */
.number-banner{
	position: absolute;
	right: 40rpx;
	margin-top: -80rpx;
	padding: 0 16rpx;
	background: rgba(0,0,0,.3);
	border-radius: 6rpx;
	color: #fff;
	font-size: 36rpx;
}
.number-banner text:last-child{
	color: rgba(255,255,255,.6);
	font-size: 30rpx;
}

/* 睿鼓众创,文字样式 */
.space-title{
	font-size: 44rpx;
	line-height: 2;
}

/* 几个高亮方块的样式 */
.space-tags{
	margin-bottom: 10rpx;
}
.space-tags text{
	padding: 6rpx 16rpx;
	border: 1rpx solid #f7982a;
	line-height: 1;
	color: #f7982a;
	font-size: 28rpx;
	border-radius: 4rpx;
	margin-right: 10rpx;
	margin-bottom: 10rpx;
	white-space: nowrap;
}

/* 收费标准、可租面积、地理位置样式 */
.space-item{
	display: flex;
	font-size: 32rpx;
	color: #555;
	padding: 16rpx 0;
	border-bottom: 1rpx solid #eee;
}
.space-item .text-left{
	white-space: nowrap;
}
.space-item .text-orange{
	font-size: 40rpx;
	color: #f7982a;
	line-height: 1;
}
.space-item .text-right{
	color: #777;
}

/* 基本介绍样式 */
.space-block-title{
	font-size: 40rpx;
}
.space-block-title:before{
	content: '';
	display: inline-block;
	vertical-align: -6rpx;
	width: 6rpx;
	height: 40rpx;
	background: #f7982a;
	margin-right: 8rpx;
}

/* 建筑面试等元素,一行两个 */
.space-block-content .space-list .space-item{
	width: 50%;
	float: left;
}

/* 基本介绍里的内容 */
.space-passage{
	font-size: 30rpx;
	text-indent: 2em;
	margin-top: 20rpx;
}

/* 底部功能点,这个样式可以放入app.wxss */
.container-footer{
	width: 100%;
	display: flex;
	height: 88rpx;
	border-top: 1rpx solid #ddd;
	background: #fff;
}
.container-footer text{
	flex: 1;
	display: block;
	text-align: center;
	height: 88rpx;
	line-height: 88rpx;
	font-size: 34rpx;
	border-left: 1rpx solid #ddd;
}
/* 入驻申请 按钮样式 */
.container-footer text.apply-btn{
	background: #f7982a;
	color: #fff;
	flex: 1.5;
}

js逻辑:

// pages/space/space.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    spacedata:{},
    spaceimgs:[],
    currentIndex:1,
  },

  // 点击图片预览
  imgPreview: function(){ //图片预览
    const imgs = this.data.spaceimgs;
    wx.previewImage({
      current: imgs[this.data.currentIndex-1], // 当前显示图片的http链接
      urls: imgs // 需要预览的图片http链接列表
    })
  },

  setCurrent: function(e){
    this.setData({
      currentIndex:e.detail.current+1
    })
  },

  // 点击“地理位置”之后,根据经纬度调起地图组件
  getAddress:function(e){
    const d = e.currentTarget.dataset;
    const address = d.address;
    const latitude = d.latitude;
    const longitude = d.longitude;
    wx.openLocation({
      latitude: latitude,
      longitude: longitude,
      scale: 18,
      // name: address,
      address: address,
      success:function(res){
        console.log(res);
      },
      fail:function(res){
        console.log(res);
      },
      success:function(res){
        console.log(res);
      }
    })
  },

  // 预约看房
  reserveHandle: function(){
    wx.navigateTo({
      url: '../spacereserve/spacereserve'
    })
  },
  // 入驻申请
  goApply: function(){
    wx.navigateTo({
      url: '../apply/apply'
    })
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.setData({
      spacedata:{
        "ParkCode": "ZCKJ20160831200444",
        "ParkName": "睿鼓众创",
        "FeeScale": 0,
        "FeeScaleUnit": "元/月",
        "FeeScaleUnitValue": 2,
        "FeeScaleRoom": 0,
        "FeeScaleRoomUnit": "元/㎡/天",
        "FeeScaleRoomUnitValue": 11,
        "Address": "上海市松江区莘砖公路518号双子楼1楼",
        "TagIDs": ["资金扶持","10个独立办公室在租","5个工位在租"],
        "latitude": 31.0921575226,
        "longitude": 121.3146194992,
        "TotalBulidingArea": 1017,
        "TotalWorkstation": 214,
        "TotalRoom": 8,
        "RoomRate": 65,
        "Summary": "阿里云创客+位于莘砖公路 518 号双子楼 1 楼,漕河泾开发区松江新兴产业园内,项目于 2015 年 12 月签约,2016 年 1 月完成设计方案,目前正进行装修施工,预计 5 月底前完工,6 月底前投入使用。交付标准为全装修,包括全部家具,无线网络、门禁、监控等系统 。",
        "Policy": "<p>A、入住企业工位费减免政策(每项减免 1~3 个月工位费,可累加计算)</p><p>1)"
      },
      spaceimgs:["http://139.196.218.128/SjPark/UserFile/Files/Thumbnail/46932530-4bc8-48dc-bf10-1e5e39d254b8_750x470.png","http://139.196.218.128/SjPark/UserFile/Files/Thumbnail/73efa039-6c54-43c6-8ad9-70f831723e2e_750x470.png","http://139.196.218.128/SjPark/UserFile/Files/Thumbnail/eb8bbf4d-e236-4c92-900c-67d8b941b02a_750x470.png"]
    })
    wx.setNavigationBarTitle({
      title: "众创空间"
    })
  },

  
})

6. 众创空间 -> 预约看房页面spacereserve

6.1. 概要图

6.2. 关键功能点

页面排版布局比较常规,只是里面有个地方要注意一下:在实现过程中,“确认预约”的按钮高度偏高,并且无法100%宽度,查看样式后,有一个部分是user agent stylesheet,百度得知这样的情况:https://developers.weixin.qq.com/community/develop/doc/00006a9e560b10f0f3893719351000。需要去掉app.json里面配置的style:v2

预约看房页面的wxml:

<view class="container">
	<view class="input-list">
		<view class="input-item">
			<text class="input-item-label">联系人</text>
			<view class="input-item-content">
				<input type="text" auto-focus placeholder="请输入您的姓名" bindinput="inputName">{{ name }}</input>
			</view>
		</view>
		<view class="input-item">
			<text class="input-item-label">手机号码</text>
			<view class="input-item-content">
				<input type="idcard" placeholder="请输入您的手机号码" maxlength="11" bindinput="inputPhone">{{ phonenumber }}</input>
			</view>
		</view>
	</view>
	<view class="btn-submit">
		<button class="btn-block btn-orange" bindtap="reserveSubmit" disabled="{{submited}}">确认预约</button>
	</view>
</view>

此页面样式(app.wxss里面有部分,Page、container、container-body):

/* 输入部分样式 */
.input-list {
  padding: 0 20rpx;
  margin: 20rpx 0;
  background: #fff;
  border-top: 1rpx solid #ddd;
  border-bottom: 1rpx solid #ddd;
}

/* 去掉第一个元素的上边框线 */
.input-list .input-item:first-child {
  border-top: 0;
}

.input-list .input-item {
  padding: 20rpx;
  line-height: 2;
  display: flex;
  font-size: 30rpx;
  border-top: 1rpx solid #e8e8e8;
}

/* 主要是为了让联系人和手机号码两个label占一样宽 */
.input-item-label {
  display: block;
  width: 5em;
  color: #666;
}

.input-item-content {
  color: #333;
  flex: 1;
}

/* 这里控制了输入框的高度,其实看起来还是有点不对齐,应该要上下对齐的 */
input {
  height: 60rpx;
  line-height: 60rpx;
  font-family: inherit;
}

/* “确认预约”,按钮样式,这里要注意的是,默认创建的项目在app.json里面有个style:v2的,不去掉的话,会有button的默认属性,user agent stylesheet,跟我们期望会不太一样,可参考:https://developers.weixin.qq.com/community/develop/doc/00006a9e560b10f0f3893719351000 */
.btn-submit {
  padding: 20rpx;
}

.btn-block {
  width: 100%;
  line-height: 88rpx;
}

.btn-orange {
  background: #f7982a;
  color: #fff;
}

逻辑层js,获取数据,提交后按钮置灰:

// pages/spacereserve/spacereserve.js
Page({

  data:{
    name:'',
    phonenumber:'',
    submited:false
  },
  inputName: function(e){
    this.setData({
      name:e.detail.value
    })
  },
  inputPhone: function(e){
    if(e.detail.cursor>=11){
      this.setData({
        phonenumber:e.detail.value
      })
      wx.hideKeyboard()
    }
  },
  reserveSubmit:function(){
    if(this.data.name && this.data.phonenumber){
      this.setData({submited:true});
      wx.showToast({
        title: '预约成功',
        icon: 'success',
        duration: 2000
      })
    }
    else{
      wx.showToast({
        title: 'toast的title过长会被截断,这种提示应该还是要用弹窗,体验好。',
        icon: 'loading',
        duration: 1000
      })
    }
  }
})

7. 众创空间 -> 入住申请apply

7.1. 概要图

7.2. 关键功能点

这里看起来是一些输入表单,输入框、富文本框、图片、下拉选择等,先把骨架搞出来,然后再一一填充表单元素。

先实现骨架及其样式,还是比较简单的

“项目图标”,此部分原先是float排布,改成flex布局也可实现效果,如下

这里主要学习一下使用pick组件,然后里面还有如何做多个块,输入样式,具体的页面、样式、逻辑js如下:

<view class="container container-gray">
	<view class="group">
		<view class="group-header">基本信息</view>
		<view class="group-body">
			<view class="input-list">
				<view class="input-item">
					<text class="input-item-label">项目名称</text>
					<view class="input-item-content">
						<input type="text" placeholder="请输入项目名称"></input>
					</view>
				</view>
				<view class="input-item">
					<text class="input-item-label">公司名称</text>
					<view class="input-item-content">
						<input type="text" placeholder="请输入公司名称"></input>
					</view>
				</view>
				<view class="input-item">
					<text class="input-item-label">项目行业</text>
					<picker class="input-item-content" bindchange="bindPickerChange" data-pickername="industry" value="{{industryindex}}" range="{{industryarr}}" mode="selector">{{industryarr[industryindex]}}
					</picker>
				</view>
				<view class="input-item">
					<text class="input-item-label">运营状态</text>
					<picker class="input-item-content" bindchange="bindPickerChange" data-pickername="status" value="{{statusindex}}" range="{{statusarr}}" mode="selector">{{statusarr[statusindex]}}
					</picker>
				</view>
				<view class="input-item input-item-full">
					<text class="input-item-label">一句话介绍</text>
					<textarea placeholder="可输入50字" maxlength="50"></textarea>
				</view>
				<view class="input-item input-item-full">
					<text class="input-item-label">项目图标</text>
					<view class="img-upload">
						<view class="img-add"></view>
						<view class="img-item">
							<image src="http://szimg.mukewang.com/5806de7c00014a3105400300-360-202.jpg" mode="aspectFill"></image>
						</view>
						<view class="img-item">
							<image src="http://szimg.mukewang.com/5806de7c00014a3105400300-360-202.jpg" mode="aspectFill"></image>
						</view>
					</view>
				</view>
			</view>
		</view>
		<view class="group-header">创始人</view>
		<view class="group-body">
			<view class="input-list">
				<view class="input-item">
					<text class="input-item-label">姓名</text>
					<view class="input-item-content">
						<input type="text" placeholder="请输入姓名"></input>
					</view>
				</view>
				<view class="input-item">
					<text class="input-item-label">职位</text>
					<picker class="input-item-content" bindchange="bindPickerChange" data-pickername="job" value="{{jobindex}}" range="{{jobarr}}" mode="selector">{{jobarr[jobindex]}}
					</picker>
				</view>
				<view class="input-item input-item-full">
					<text class="input-item-label">主要履历</text>
					<textarea placeholder="请输入主要履历"></textarea>
				</view>
			</view>
		</view>
		<view class="group-header">产品亮点</view>
		<view class="group-body">
			<textarea placeholder="请输入产品亮点"></textarea>
		</view>
		<view class="group-header">产品指标数据</view>
		<view class="group-body">
			<view class="input-list">
				<view class="input-item">
					<text class="input-item-label">用户总量</text>
					<view class="input-item-content">
						<input type="number"></input>
					</view>
				</view>
				<view class="input-item">
					<text class="input-item-label">DUA数据</text>
					<view class="input-item-content">
						<input type="number"></input>
					</view>
				</view>
				<view class="input-item input-item-adaption">
					<text class="input-item-label">月收入流水</text>
					<view class="input-item-content">
						<input type="number"></input>
					</view>
				</view>
				<view class="input-item input-item-adaption">
					<text class="input-item-label">公众号粉丝数</text>
					<view class="input-item-content">
						<input type="number"></input>
					</view>
				</view>
				<view class="input-item input-item-adaption">
					<text class="input-item-label">日均阅读量(近30日)</text>
					<view class="input-item-content">
						<input type="number"></input>
					</view>
				</view>
			</view>
		</view>
		<view class="group-header">融资信息</view>
		<view class="group-body">
			<view class="input-list">
				<view class="input-item">
					<text class="input-item-label">融资经历</text>
					<view class="input-item-content">
						<radio-group bindchange="setFinance">
							<label class="{{!hasfinancing ? 'checked' : ''}}">
								<radio value="未融资" checked="{{!hasfinancing}}" />未融资
							</label>
							<label class="{{hasfinancing? 'checked' : ''}}">
								<radio value="已融资" checked="{{hasfinancing}}" />已融资
							</label>
						</radio-group>
					</view>
				</view>
				<view wx:if="{{hasfinancing}}">
					<view class="input-item input-item-adaption">
						<text class="input-item-label">最后融资额(W)</text>
						<view class="input-item-content">
							<input type="number"></input>
						</view>
					</view>
					<view class="input-item input-item-adaption">
						<text class="input-item-label">最后融资时间</text>
						<view class="input-item-content">
							<input type="date"></input>
						</view>
					</view>
					<view class="input-item">
						<text class="input-item-label">投资主体</text>
						<view class="input-item-content">
							<radio-group bindchange="setIsorg">
								<label class="{{isorg?'checked':''}}">
									<radio value="机构" checked="{{isorg}}" />机构
								</label>
								<label class="{{!isorg?'checked':''}}">
									<radio value="个人" checked="{{!isorg}}" />个人
								</label>
							</radio-group>
						</view>
					</view>
					<view class="input-item" wx:if="{{isorg}}">
						<text class="input-item-label">机构名称</text>
						<view class="input-item-content">
							<input type="text"></input>
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
	<view class="btn-submit">
		<button class="btn-block btn-orange" bindtap="applySubmit">提交</button>
	</view>
</view>

样式也基本上都是在一个文件里体现,除了container

/* 整个页面的底色 */
.container-gray {
  background: #f9f9f9;
}

/* 基本信息、创始人、产品亮点、产品指标数据、融资信息这几个大块的样式 */
.group {
  display: block;
  width: 100%;
}

.group-header {
  line-height: 70rpx;
  display: flex;
  padding: 0 20rpx;
  background: #f9f9f9;
}

.group-body {
  background: #fff;
  border-top: 1rpx solid #ddd;
  border-bottom: 1rpx solid #ddd;
}

.group-body .input-list {
  margin: 0;
  border: none;
}

/* “提交”按钮的样式 */
.btn-submit {
  padding: 20rpx;
}

.btn-block {
  width: 100%;
  line-height: 88rpx;
}

.btn-orange {
  background: #f7982a;
  color: #fff;
}

.btn-gray {
  background: #e8e8e8;
  color: #333;
}

/* 输入部分样式 */
.input-list {
  padding: 0 20rpx;
  margin: 20rpx 0;
  background: #fff;
  border-top: 1rpx solid #ddd;
  border-bottom: 1rpx solid #ddd;
}

.input-list .input-item {
  padding: 20rpx;
  line-height: 2;
  display: flex;
  font-size: 30rpx;
  border-top: 1rpx solid #e8e8e8;
}

.input-list .input-item:first-child {
  border-top: 0;
}

.input-item-label {
  display: block;
  width: 5em;
  color: #666;
}

.input-item-content {
  color: #333;
  flex: 1;
}

/* 输入内容占用整行,行级元素 */
.input-item.input-item-full {
  display: block;
}

.input-item.input-item-full .input-item-label {
  width: 100%;
}

.input-item.input-item-full .input-item-content {
  width: 100%;
}

/* 富文本框样式 */
textarea {
  width: 100%;
  padding: 20rpx;
  box-sizing: border-box;
}

.input-item.input-item-full textarea {
  padding: 0;
  height: 150rpx;
  border: 1rpx solid #e8e8e8;
  padding: 10rpx;
}

/* 是让输入的label自适应,不要换行 */
.input-item.input-item-adaption .input-item-label {
  width: auto;
  margin-right: 20rpx;
}

/* “项目图标”相关样式 */
.img-upload {
  display: flex;
  padding: 20rpx;
  font-size: 0;
  overflow: hidden;
}

.img-upload .img-item,
.img-upload .img-add {
  width: 100rpx;
  height: 100rpx;
  margin: 10rpx;
  border: 1rpx solid transparent;
}

.img-upload .img-add {
  border: 1rpx dashed #ddd;
  /* 下面这种写法是不对的,要改成base64格式的数据 */
  background: url(../../images/add.png) no-repeat 50% 50% / 70% auto;
}

.img-upload .img-item image {
  width: 100rpx;
  height: 100rpx;
}

逻辑js比较简单:

// pages/apply/apply.js
Page({

  data: {
    industryarr: [],
    industryindex: 0,
    statusarr: [],
    statusindex: 0,
    jobarr: [],
    jobindex: 0,
    hasfinancing: false, //是否已融资
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.fetchData();
  },

  fetchData: function () {
    this.setData({
      industryarr: ["请选择", "移动互联网", "手机游戏", "互联网金融", "O2O", "智能硬件", "SNS社交", "旅游", "影视剧", "生活服务", "电子商务", "教育培训", "运动和健康", "休闲娱乐", "现代农业", "文化创意", "节能环保", "新能源", "生物医药", "IT软件", "硬件", "其他"],
      statusarr: ["请选择", "初创时期", "市场扩展期", "已经盈利"],
      jobarr: ["请选择", "创始人", "联合创始人", "产品", "技术", "营销", "运营", "设计", "行政", "其他"]
    })
  },
  bindPickerChange: function (e) { //下拉选择
    const eindex = e.detail.value;
    const name = e.currentTarget.dataset.pickername;
    // this.setData(Object.assign({},this.data,{name:eindex}))
    switch (name) {
      case 'industry':
        this.setData({
          industryindex: eindex
        })
        break;
      case 'status':
        this.setData({
          statusindex: eindex
        })
        break;
      case 'job':
        this.setData({
          jobindex: eindex
        })
        break;
      default:
        return
    }
  },

  setFinance: function (e) { //选择融资
    this.setData({
      hasfinancing: e.detail.value == "已融资" ? true : false
    })
  },
  setIsorg: function (e) { //选择投资主体
    this.setData({
      isorg: e.detail.value == "机构" ? true : false
    })
  },
  applySubmit: function () {
    wx.navigateTo({
      url: '../service/service'
    })
  }
})

8. 服务集市service

8.1. 概要图

从下图可见,主要是一个搜索、分类筛选和一个scroll-view

8.2. 关键功能点

8.2.1. 筛选过滤

这个主要还是用view来做的,增加各种样式控制来实现,本质上没有用到什么组件。

下图这样的过滤筛选功能还是比较常见的:

页面wxml:

<view class="container">
	<view class="search-flex {{scrolltop>200?'tophide':''}}">
		<view class="search-bar">
			<input type="text" maxlength="12" placeholder="请输入关键字查询" bindinput="inputSearch"></input>
			<button class="search-btn" bindtap="submitSearch" wx:if="{{showsearch}}">搜索</button>
		</view>
		<button class="search-extra-btn">服务商入驻</button>
	</view>

  <view class="filter-flex">
		<view class="filter-tab">
			<text bindtap="setFilterPanel" data-findex="1" class="{{showfilterindex==1?'active':''}}">服务类别</text>
			<text bindtap="setFilterPanel" data-findex="2" class="{{showfilterindex==2?'active':''}}">服务城市</text>
		</view>
		<view class="filter-content" wx:if="{{showfilter}}">
			<view class="filter-panel" wx:if="{{showfilterindex==1}}">
      <!-- 服务类别,这个tab点击后,下面会显示过滤面板,这个面板是二级的,比如“人力资源”点击后,还有二级的选择 -->
				<view class="filter-panel-left">
					<view wx:for="{{filterdata.sort}}" wx:key="{{item.id}}" bindtap="setSortIndex" data-sortindex="{{index}}" data-sortid="{{item.id}}" class="{{sortindex==index?'active':''}}">{{item.title}}</view>
				</view>
				<view class="filter-panel-right">
					<view wx:for="{{filterdata.sort[sortindex].subsort}}" wx:key="{{item.id}}" bindtap="setSubsortIndex" data-subsortindex="{{index}}" data-subsortid="{{item.id}}" class="{{subsortindex==index?'active':''}}">{{item.title}}</view>
				</view>
			</view>
			<view class="filter-panel" wx:if="{{showfilterindex==2}}">
      <!-- 服务城市,这个tab点击后,下面会显示过滤面板,这个面板是二级的,比如“湖北”点击后,还有二级的选择 -->
				<view class="filter-panel-left">
					<view wx:for="{{filterdata.city}}" wx:key="{{item.id}}" bindtap="setCityIndex" data-cityindex="{{index}}" data-cityid="{{item.id}}" class="{{cityindex==index?'active':''}}">{{item.title}}</view>
				</view>
				<view class="filter-panel-right">
					<view wx:for="{{filterdata.city[cityindex].subcity}}" wx:key="{{item.id}}" bindtap="setSubcityIndex" data-subcityindex="{{index}}" data-subcityid="{{item.id}}" class="{{subcityindex==index?'active':''}}">{{item.title}}</view>
				</view>
			</view>
		</view>
		<view class="filter-shadow" wx:if="{{showfilter}}" bindtap="hideFilter">这里不需要被看见,点击遮罩部分,会收起筛选panel</view>
	</view>

  <scroll-view class="container-body" scroll-y="true" scroll-top="{{scrolltop}}" bindscroll="scrollHandle" lower-threshold="50" bindscrolltolower="scrollLoading">
		<view class="service-list">
			<navigator class="service-item" wx:for="{{servicelist}}" wx:key="{{item.id}}" url="../servicedetail/servicedetail?id={{item.id}}">
				<view class="service-img">
					<image src="{{item.imgurl}}" mode="aspectFill"></image>
				</view>
				<view class="service-text">
					<view class="service-tite">{{item.name}}</view>
					<view class="service-tags">
						<text>{{item.tag}}</text>
					</view>
					<text class="service-city">服务城市:{{item.city}}</text>
				</view>
			</navigator>
		</view>
		<view class="gototop {{scrolltop>200?'active':''}}" bindtap="goToTop"></view>
	</scroll-view>

</view>

样式wxss:

/* pages/service/service.wxss */
.search-flex{
	display: flex;
	padding: 20rpx;
	border-bottom: 1rpx solid #ddd;
	position: relative;
	z-index: 13;
	background: #f9f9f9;
	/* transform:  translateY(-100%); */
	margin-top: 0;
	transition: all 0.3s;
}
/* 下拉超过一定距离,隐藏搜索框 */
.search-flex.tophide{
	margin-top: -117rpx;
}

/* 搜索框样式 */
.search-bar{
	flex: 1;
	display: flex;
	border: 1rpx solid #e8e8e8;
	border-radius: 6rpx;
}
/* 搜索框内输入提示文字样式 */
.search-bar input{
	flex: 1;
	height: 72rpx;
	line-height: 72rpx;
	padding: 0 10rpx;
	background: #fff;
}

/* “服务商入驻”按钮样式 */
.search-flex button{
	background: #f7982a;
	color: #fff;
	line-height: 72rpx;
	height: 72rpx;
	font-size: 30rpx;
	border-radius: 6rpx;
}
.search-extra-btn{
	margin-left: 20rpx;
	white-space: nowrap;
}

/* 分类选择tab */
.filter-tab{
	display: flex;
	width: 100%;
	line-height: 80rpx;
	border-bottom: 1rpx solid #ddd;
	position: relative;
	z-index: 2;
	background: #fff;
}
.filter-tab text.active{
	color: #f7982a;
}
/* 让两个分类选择的文本在一行内平分大小 */
.filter-tab text{
	flex: 1;
	text-align: center;
}
/* 过滤tab文案后面的下拉三角箭头 */
.filter-tab text:after{
	content: '';
	display: inline-block;
	vertical-align: 4rpx;
	width: 0;
	height: 0;
	border-left: 12rpx solid transparent;
	border-right: 12rpx solid transparent;
	border-top: 12rpx solid #bbb;
	margin-left: 8rpx;
}
/* 分类筛选下拉后面板的布局 */
.filter-panel{
	display: flex;
	background: #f5f5f5;
	position: absolute;
	width: 100%;
	z-index: 13;
	overflow: hidden;
}
.filter-panel-left,.filter-panel-right{
	flex: 1;
	line-height: 80rpx;
	text-align: center;
	max-height: 480rpx;
	overflow-y: auto;
}
/* 如果右边的“服务城市”里没有内容,那么就不展示:不占用空间,这样,左侧的“服务类别”下拉面板就可以根据flex布局撑满 */
.filter-panel-right:empty{
	display: none;
}

.filter-panel-left .active{
	background: #fff;
}
.filter-panel-right .active{
	color: #f7982a;
}
.filter-panel-right{
	background: #fff;
}
/* 这个是打开过滤面板的时候,下面出现遮罩效果,并且点击遮罩区域会触发hideFilter方法 */
.filter-shadow{
	position: absolute;
	width: 100%;
	top: 0;
	bottom: 0;
	z-index: 1;
	background: rgba(0,0,0,.5);
}

/* scroll-view列表样式 */
.container-body{
	flex: 1;
	overflow-y: auto;
	overflow-x: hidden;
}
.service-list{
	padding: 0 20rpx;
}
.service-item{
	display: flex;
	padding: 20rpx 0; 
	border-bottom: 1rpx solid #e8e8e8;
}
.service-item image{
	width: 220rpx;
	height: 156rpx;
}
.service-img{
	width: 220rpx;
	height: 156rpx;
}
.service-text{
	flex: 1;
	margin-left: 20rpx;
	width: 100%;
}
.service-text .service-tite{
	color: #333;
	width: 100%;
	font-size: 34rpx;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
/* “法律咨询”标签样式 */
.service-tags{
	margin: 6rpx 0;
}
.service-tags text{
	padding: 6rpx 16rpx;
	border: 1rpx solid #f7982a;
	line-height: 1;
	color: #f7982a;
	font-size: 28rpx;
	border-radius: 4rpx;
	margin-right: 10rpx;
	margin-bottom: 10rpx;
	white-space: nowrap;
}
.service-city{
	color: #666;
}

逻辑js:

// pages/service/service.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    showsearch:false,   //显示搜索按钮
    searchtext:'',  //搜索文字
    filterdata:{},  //筛选条件数据
    showfilter:false, //是否显示下拉筛选
    showfilterindex:null, //显示哪个筛选类目
    sortindex:0,  //一级分类索引
    sortid:null,  //一级分类id
    subsortindex:0, //二级分类索引
    subsortid:null, //二级分类id
    cityindex:0,  //一级城市索引
    cityid:null,  //一级城市id
    subcityindex:0,  //二级城市索引
    subcityid:null, //二级城市id
    servicelist:[], //服务集市列表
    scrolltop:null, //滚动位置
    page: 0  //分页
  },

  setFilterPanel: function(e){ //展开筛选面板
    const d = this.data;
    const i = e.currentTarget.dataset.findex;
    if(d.showfilterindex == i){
      this.setData({
        showfilter: false,
        showfilterindex: null
      })
    }else{    
      this.setData({
        showfilter: true,
        showfilterindex:i,
      })
    }
    console.log(d.showfilterindex);
  },
  setSortIndex:function(e){ //服务类别一级索引
    const d= this.data;
    const dataset = e.currentTarget.dataset;
    this.setData({
      sortindex:dataset.sortindex,
      sortid:dataset.sortid,
      subsortindex: d.sortindex==dataset.sortindex ? d.subsortindex:0
    })
    console.log('服务类别id:一级--'+this.data.sortid+',二级--'+this.data.subsortid);
  },
  setSubsortIndex:function(e){ //服务类别二级索引
    const dataset = e.currentTarget.dataset;
    this.setData({
      subsortindex:dataset.subsortindex,
      subsortid:dataset.subsortid,
      showfilter:false,// 这里增加了点击二级索引后,收起过滤面板的作用
      showfilterindex:null,
    })
    console.log('服务类别id:一级--'+this.data.sortid+',二级--'+this.data.subsortid);
  },
  setCityIndex:function(e){ //服务城市一级索引
    const d= this.data;
    const dataset = e.currentTarget.dataset;
    this.setData({
      cityindex:dataset.cityindex,
      cityid:dataset.cityid,
      subcityindex: d.cityindex==dataset.cityindex ? d.subcityindex:0
    })
    console.log('服务城市id:一级--'+this.data.cityid+',二级--'+this.data.subcityid);
  },
  setSubcityIndex:function(e){ //服务城市二级索引
    const dataset = e.currentTarget.dataset;
    this.setData({
      subcityindex:dataset.subcityindex,
      subcityid:dataset.subcityid,
      showfilter:false,// 这里增加了点击二级索引后,收起过滤面板的作用
      showfilterindex:null,
    })
    console.log('服务城市id:一级--'+this.data.cityid+',二级--'+this.data.subcityid);
  },
  hideFilter: function(){ //关闭筛选面板
    this.setData({
      showfilter: false,
      showfilterindex: null
    })
  },

  inputSearch:function(e){  //输入搜索文字
    this.setData({
      showsearch:e.detail.cursor>0,
      searchtext:e.detail.value
    })
  },
  submitSearch:function(){  //提交搜索
    console.log(this.data.searchtext);
    this.fetchServiceData();
  },

  scrollHandle:function(e){ //滚动事件
    this.setData({
      scrolltop:e.detail.scrollTop
    })
  },
  goToTop:function(){ //回到顶部
    this.setData({
      scrolltop:0
    })
  },
  scrollLoading:function(){ //滚动加载
    this.fetchServiceData();
  },
  fetchServiceData:function(){  //获取城市列表
    let _this = this;
    wx.showToast({
      title: '加载中',
      icon: 'loading'
    })
    const perpage = 10;
    this.setData({
      page:this.data.page+1
    })
    const page = this.data.page;
    const newlist = [];
    for (var i = (page-1)*perpage; i < page*perpage; i++) {
      newlist.push({
        "id":i+1,
        "name":"上海拜特信息技术有限公司"+(i+1),
        "city":"上海",
        "tag":"法律咨询",
        "imgurl":"http://img.mukewang.com/57fdecf80001fb0406000338-240-135.jpg"
      })
    }
    setTimeout(()=>{
      _this.setData({
        servicelist:_this.data.servicelist.concat(newlist)
      })
    },1500)
  },
  onPullDownRefresh:function(){ //下拉刷新
    this.setData({
      page:0,
      servicelist:[]
    })
    this.fetchServiceData();
    this.fetchFilterData();
    setTimeout(()=>{
      wx.stopPullDownRefresh()
    },1000)
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.fetchServiceData();
    this.fetchFilterData();
  },

  fetchFilterData:function(){ //获取筛选条件
    this.setData({
      filterdata:{
        "sort": [
            {
                "id": 0,
                "title": "全部"
            },
            {
              "id": 1,
              "title": "人力资源",
              "subsort": [
                {
                    "id": 1,
                    "title": "全部"
                },
                {
                    "id": 11,
                    "title": "社会及商业保险"
                },
                {
                    "id": 12,
                    "title": "招聘、猎头"
                },
                {
                    "id": 13,
                    "title": "薪酬绩效"
                },
              ]
            },
            {
              "id": 2,
              "title": "财务法务",
              "subsort": [
                {
                    "id": 2,
                    "title": "全部"
                },
                {
                    "id": 21,
                    "title": "知识产权保护"
                },
                {
                    "id": 22,
                    "title": "工商注册"
                },
                {
                    "id": 23,
                    "title": "法律咨询"
                },
              ]
            },
            {
              "id": 3,
              "title": "行政办公",
              "subsort": [
                {
                    "id": 3,
                    "title": "全部"
                },
                {
                    "id": 31,
                    "title": "翻译"
                },
                {
                    "id": 32,
                    "title": "速记"
                }
              ]
            },
            {
              "id": 4,
              "title": "创业指导",
              "subsort": [
                {
                    "id": 4,
                    "title": "全部"
                },
                {
                    "id": 41,
                    "title": "创业培训"
                }
              ]
            },
        ],
        "city": [
            {
                "id": 0,
                "title": "全部"
            },
            {
              "id": 1,
              "title": "湖北省",
              "subcity": [
                {
                    "id": 1,
                    "title": "全部"
                },
                {
                    "id": 11,
                    "title": "武汉市"
                },
                {
                    "id": 12,
                    "title": "襄阳市"
                },
                {
                    "id": 13,
                    "title": "孝感市"
                },
                {
                    "id": 14,
                    "title": "随州市"
                },
                {
                    "id": 15,
                    "title": "荆州市"
                },
                {
                    "id": 16,
                    "title": "黄冈市"
                },
                {
                    "id": 17,
                    "title": "天门市"
                },
                {
                    "id": 18,
                    "title": "仙桃市"
                },
                {
                    "id": 19,
                    "title": "潜江市"
                },
                {
                    "id": 20,
                    "title": "十堰市"
                },
                {
                    "id": 21,
                    "title": "宜昌市"
                },
                {
                    "id": 22,
                    "title": "咸宁市"
                },
              ]
            },
            {
              "id": 2,
              "title": "浙江省",
              "subcity": [
                {
                    "id": 2,
                    "title": "全部"
                },
                {
                    "id": 21,
                    "title": "杭州市"
                },
                {
                    "id": 22,
                    "title": "金华市"
                },
                {
                    "id": 23,
                    "title": "义乌市"
                },
              ]
            },
            {
              "id": 3,
              "title": "江苏省",
              "subcity": [
                {
                    "id": 3,
                    "title": "全部"
                },
                {
                    "id": 31,
                    "title": "南京市"
                },
                {
                    "id": 32,
                    "title": "苏州市"
                }
              ]
            }
        ],
      }
    })
  },

  
})

9. 服务详情页servicedetail

9.1. 概要图

这个服务详情页还是比较常规的,没什么特殊的地方

9.2. 关键功能点

具体的wxml、wxss、js如下:

<view class="container">
	<view class="container-body">
		<view class="service-item service-detail">
			<view class="service-img">
				<image src="{{servicedetail.imgurl}}" mode="aspectFill"></image>
			</view>
			<view class="service-text">
				<view class="service-tite">{{servicedetail.name}}</view>
				<view class="service-tags">
					<text>{{servicedetail.tag}}</text>
				</view>
				<text class="service-city">服务城市:{{servicedetail.city}}</text>
			</view>
		</view>
	</view>
	<view class="container-footer">
		<button class="btn-orange btn-block">立即咨询</button>
	</view>
</view>

/* 服务详情item的样式 */
.service-detail{
	padding:20rpx;
}
.service-item {
  display: flex;
}
.service-img{
	width: 220rpx;
	height: 156rpx;
}
.service-item image{
	width: 220rpx;
	height: 156rpx;
}

.service-text{
	flex: 1;
	margin-left: 20rpx;
	width: 100%;
}
.service-text .service-tite{
	color: #333;
	width: 100%;
	font-size: 34rpx;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
/* 标签样式 */
.service-tags{
	margin: 6rpx 0;
}
.service-tags text{
	padding: 6rpx 16rpx;
	border: 1rpx solid #f7982a;
	line-height: 1;
	color: #f7982a;
	font-size: 28rpx;
	border-radius: 4rpx;
	margin-right: 10rpx;
	margin-bottom: 10rpx;
	white-space: nowrap;
}
.service-city{
	color: #666;
}

/* 底部按钮样式 */
.container-footer .btn-block{
	border-radius: 0;
}
.btn-block{
	width: 100%;
	line-height: 88rpx;
}
.btn-orange{
	background: #f7982a;
	color: #fff;
}
// pages/servicedetail/servicedetail.js
Page({
  data: {
    servicedetail:{},
  },
  onLoad: function (options) {
    const i = options.id;
    this.setData({
      servicedetail:{
        "name":"上海拜特信息技术有限公司"+i,
        "city":"上海",
        "tag":"法律咨询",
        "imgurl":"http://img.mukewang.com/57fdecf80001fb0406000338-240-135.jpg"
      }
    })
    wx.setNavigationBarTitle({
      title: this.data.servicedetail.name
    })
  }
})

10. 会议室列表conference

10.1. 概要图

看起来这个主要是一个scroll-view,顶部的筛选比较特别,类似于一个表单,根据表单内容进行筛选,这是重点。

10.2. 关键功能点:筛选的条件是类似于表单

表单筛选,本质上还是样式,没有特别需要注意的地方。样式部分都已经加上了备注,便于理解。

还有一个就是修正了原先项目里,筛选 -> 提供设备部分选中没有高亮样式的问题。

页面wxml:

<view class="container">
	<view class="filter-flex">
		<view class="filter-tab">
			<text bindtap="setFilterPanel" data-findex="1" class="{{showfilterindex==1?'active':''}}">排序</text>
			<text bindtap="setFilterPanel" data-findex="2" class="{{showfilterindex==2?'active':''}}">筛选</text>
		</view>
		<view class="filter-content" wx:if="{{showfilter}}">
			<view class="filter-panel filter-sort" wx:if="{{showfilterindex==1}}">
				<view wx:for="{{filterdata.sort}}" wx:key="{{item.id}}" bindtap="setSort" data-sortindex="{{index}}" data-sortid="{{item.id}}" class="{{sortindex==index?'active':''}}">{{item.title}}</view>
			</view>
			<view class="filter-panel filter-multiple" wx:if="{{showfilterindex==2}}">
				<view class="group">
					<view class="group-header">会议时间</view>
					<view class="group-body">
						<view class="input-list">
							<view class="input-item">
								<text class="input-item-label">开始时间</text>
								<view class="input-item-content">
								<!-- 这里真机也没有时间选择 -->
									<input type="time" placeholder="" bindinput="inputStartTime" value="{{ filter.startime }}"></input>
								</view>
							</view>
							<view class="input-item">
								<text class="input-item-label">结束时间</text>
								<view class="input-item-content">
									<input type="time" placeholder="" bindinput="inputEndTime" value="{{ filter.endtime }}"></input>
								</view>
							</view>
						</view>
					</view>
					<view class="group-header">容纳人数</view>
					<view class="group-body">
						<view class="filter-tags">
							<text wx:for="{{filterdata.contain}}" wx:key="{{item.id}}" data-id="{{item.id}}" bindtap="chooseContain" class="{{filter.containid==item.id?'active':''}}">{{item.title}}</text>
						</view>
					</view>
					<view class="group-header">提供设备</view>
					<view class="group-body">
						<view class="filter-tags">
							<text wx:for="{{filterdata.equipments}}" data-id="{{item.id}}" wx:key="{{item.id}}" bindtap="chooseEquipment" class="{{ choosedEquipments[item.id] ?'active':''}}">{{item.title}}</text>
						</view>
					</view>
				</view>
				<view class="filter-btns">
					<button class="btn-block btn-gray" bindtap="cleanFilter">清空</button>
					<button class="btn-block btn-orange" bindtap="submitFilter">提交</button>
				</view>
			</view>
		</view>
		<view class="filter-shadow" wx:if="{{showfilter}}" bindtap="hideFilter"></view>
	</view>

	<scroll-view class="container-body" scroll-y="true" scroll-top="{{scrolltop}}" bindscroll="scrollHandle" lower-threshold="50" bindscrolltolower="scrollLoading">
		<view class="conference-list">
			<navigator class="conference-item" wx:for="{{conferencelist}}" wx:key="{{item.id}}" url="../conferencedetail/conferencedetail?id={{item.id}}&price={{item.price}}&name={{item.name}}&area={{item.area}}&contain={{item.contain}}&equipments={{item.equipments}}">
				<view class="conference-item-img">
					<image src="{{item.imgurl}}" mode="aspectFill"></image>
					<text>{{item.price}}元/小时</text>
				</view>
				<view class="conference-item-text">
					<view class="conference-item-title">{{item.name}}</view>
					<view class="conference-item-info">
						<text>容纳人数:{{item.contain}}人</text>
						<text>面积:{{item.area}}㎡</text>
					</view>
				</view>
				<view class="conference-item-tags">
					<text wx:for="{{item.equipments}}" wx:key="*this">{{item}}</text>
				</view>
			</navigator>
		</view>
		<view class="gototop {{scrolltop>200?'active':''}}" bindtap="goToTop"></view>
	</scroll-view>
</view>

样式wxss:

/* 分类选择tab */
.filter-tab{
	display: flex;
	width: 100%;
	line-height: 80rpx;
	border-bottom: 1rpx solid #ddd;
	position: relative;
	z-index: 2;
	background: #fff;
}
.filter-tab text.active{
	color: #f7982a;
}
/* 让两个分类选择的文本在一行内平分大小 */
.filter-tab text{
	flex: 1;
	text-align: center;
}
/* 过滤tab文案后面的下拉三角箭头 */
.filter-tab text:after{
	content: '';
	display: inline-block;
	vertical-align: 4rpx;
	width: 0;
	height: 0;
	border-left: 12rpx solid transparent;
	border-right: 12rpx solid transparent;
	border-top: 12rpx solid #bbb;
	margin-left: 8rpx;
}
/* 筛选排序的箭头上下和高亮,不设置的话点击后不会高亮,方向也不会变;这里有个疑问sort-tab不知道在哪儿使用的 */
.filter-tab:not(.sort-tab) text.active:after{
	border-top: 0;
	border-bottom: 12rpx solid #f7982a;
}
.filter-tab.sort-tab text.active:after{
	border-top: 12rpx solid #f7982a;
}
/* 分类筛选下拉后面板的布局 */
.filter-panel{
	display: flex;
	background: #f5f5f5;
	position: absolute;
	width: 100%;
	z-index: 13;
	overflow: hidden;
}

/* 这个是打开过滤面板的时候,下面出现遮罩效果,并且点击遮罩区域会触发hideFilter方法 */
.filter-shadow{
	position: absolute;
	width: 100%;
	top: 0;
	bottom: 0;
	z-index: 1;
	background: rgba(0,0,0,.5);
}

.filter-sort{
	display: block;
	background: #fff;
}
.filter-sort view{
	flex: 1;
	line-height: 80rpx;
	text-indent: 60rpx;
	max-height: 432rpx;
	overflow-y: auto;
	border-bottom: 1rpx solid #e8e8e8;
}
.filter-sort view.active{
	color: #f7982a;
}

/* 筛选表单部分样式 */
.filter-multiple{
	flex-direction: column;
}
.filter-multiple .group{
	max-height: 700rpx;
	overflow: auto;
}
.group{
	display: block;
	width: 100%;
}
.group-header{
	line-height: 70rpx;
	display: flex;
	padding: 0 20rpx;
	background: #f9f9f9;
}
.group-body{
	background: #fff;
	border-top: 1rpx solid #ddd;
	border-bottom: 1rpx solid #ddd;
}
.group-body .input-list{
	margin: 0;
	border: none;
}
input{
	height: 60rpx;
	line-height: 60rpx;
 	font-family: inherit;
}
.input-list{
	padding: 0 20rpx;
	margin: 20rpx 0;
	background: #fff;
	border-top: 1rpx solid #ddd;
	border-bottom: 1rpx solid #ddd;
}
.input-list .input-item{
	padding: 20rpx;
	line-height: 2;
	display: flex;
	font-size: 30rpx;
	border-top: 1rpx solid #e8e8e8;
}
.input-list .input-item:first-child{
	border-top: 0;
}
.input-item-label{
	display: block;
	width: 5em;
	color: #666;
}
.input-item-content{
	color: #333;
	flex:1;
}
/* 容纳人数tags */
.filter-tags{
	padding: 20rpx;
}
/* 容纳人数、提供设备tags的边框 */
.filter-tags text{
	padding: 20rpx 26rpx;
	border: 1rpx solid #ddd;
	display: inline-block;
	line-height: 1;
	color: #666;
	font-size: 28rpx;
	border-radius: 4rpx;
	margin: 10rpx;
	white-space: nowrap;
}
/* 容纳人数、提供设备tags的选中效果 */
.filter-tags text.active{
	background: #f7982a;
	color: #fff;
	border-color: #f7982a;
}

/* 清空和提交按钮样式 */
.filter-btns{
	display: flex;
	padding: 20rpx;
	border-top: 1rpx solid #ddd;
	margin-top: -1rpx;
}
.filter-btns button{
	margin: 0 10rpx;
	line-height: 80rpx;
}
.btn-block{
	width: 100%;
	line-height: 88rpx;
}
.btn-gray{
	background: #e8e8e8;
	color: #333;
}
.btn-orange{
	background: #f7982a;
	color: #fff;
}


.conference-item{
	padding: 20rpx;
	border-bottom: 1rpx solid #e8e8e8;
}
.conference-item-img{
	width: 100%;
	height: 360rpx;
	overflow: hidden;
	position: relative;
}
.conference-item-img image{
	width: 100%;
}
/* 会议室价格的样式 */
.conference-item-img text{
	position: absolute;
	right: 0;
	top: 0;
	background: #07b5e0;
	color: #fff;
	font-size: 32rpx;
	padding: 6rpx 20rpx;
}
.conference-item-title{
	font-size: 38rpx;
	color: #000;
}
.conference-item-info{
	display: flex;
}
.conference-item-info text{
	flex: 1;
}
/* 标签样式 */
.conference-item-tags:not(:empty){
	margin-top: 10rpx;
}
.conference-item-tags text{
	padding: 6rpx 16rpx;
	border: 1rpx solid #f7982a;
	line-height: 1;
	color: #f7982a;
	font-size: 28rpx;
	border-radius: 4rpx;
	margin-right: 10rpx;
	white-space: nowrap;
}

逻辑js:

import util from './../../utils/util.js';
Page({
  data: {
    filterdata:{},  //筛选条件数据
    showfilter:false, //是否显示下拉筛选
    showfilterindex:null, //显示哪个筛选类目
    sortindex:0,  //排序索引
    sortid:null,  //排序id
    filter:{},
    conferencelist:[], //会议室列表列表
    scrolltop:null, //滚动位置
    page: 0,  //分页,
    choosedEquipments: {0:false} // 这个是用来标识选中了哪些设备并且只是样式渲染作用(数据已经包含在了filter里面)。主要是不确定如何在wxml中使用indexOf函数,待后续优化
  },

  fetchFilterData:function(){ //获取筛选条件
    this.setData({
      filterdata:{
        "sort": [
            {
                "id": 0,
                "title": "价格最低"
            },
            {
                "id": 1,
                "title": "容量最多"
            },
            {
                "id": 2,
                "title": "设备最全"
            },
        ],
        "contain": [
            {
                "id": 0,
                "title": "4人以下"
            },
            {
                "id": 1,
                "title": "5-8人"
            },
            {
                "id": 2,
                "title": "8-12人"
            },
             {
                "id": 3,
                "title": "12-20人"
            },
            {
                "id": 4,
                "title": "20人以上"
            },
        ],
        "equipments": [
            {
                "id": 0,
                "title": "投影仪"
            },
            {
                "id": 1,
                "title": "欢迎屏"
            },
            {
                "id": 2,
                "title": "视屏设备"
            },
            {
                "id": 3,
                "title": "电话会议设备"
            },
            {
                "id": 4,
                "title": "钢笔"
            },
            {
                "id": 5,
                "title": "麦克风"
            },
        ],
      }
    })
  },
  fetchConferenceData:function(){  //获取会议室列表
    const perpage = 10;
    this.setData({
      page:this.data.page+1
    })
    const page = this.data.page;
    const newlist = [];
    for (var i = (page-1)*perpage; i < page*perpage; i++) {
      newlist.push({
        "id":i+1,
        "name":"A区会议室"+(i+1),
        "contain": Math.floor(Math.random()*50),
        "area": Math.floor(Math.random()*(200-20)+20),
        "price" : Math.floor(Math.random()*50)*10,
        "equipments":util.getRandomArray(["投影仪","欢迎屏","视屏设备","电话会议设备","钢笔","麦克风"],Math.floor(Math.random()*6)),
        "imgurl":"https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3390669789,3215835488&fm=26&gp=0.jpg"
      })
    }
    this.setData({
      conferencelist:this.data.conferencelist.concat(newlist)
    })
  },
  setFilterPanel: function(e){ //展开筛选面板
    const d = this.data;
    const i = e.currentTarget.dataset.findex;
    if(d.showfilterindex == i){
      this.setData({
        showfilter: false,
        showfilterindex: null
      })
    }else{    
      this.setData({
        showfilter: true,
        showfilterindex:i,
      })
    }
  },
  setSort:function(e){ //选择排序方式
    const d= this.data;
    const dataset = e.currentTarget.dataset;
    this.setData({
      sortindex:dataset.sortindex,
      sortid:dataset.sortid
    })
    console.log('排序方式id:'+this.data.sortid);
  },
  hideFilter: function(){ //关闭筛选面板
    this.setData({
      showfilter: false,
      showfilterindex: null
    })
  },
  chooseContain:function(e){  //选择会议室容纳人数
    this.setData({
      filter: Object.assign({},this.data.filter,{
        containid:e.currentTarget.dataset.id
      })
    })
    console.log('选择的会议室容量id:'+this.data.filter.containid);
  },
  chooseEquipment:function(e){  //选择会议室设备
    const equipments = this.data.filter.equipments || [];
    const eid = e.currentTarget.dataset.id;
    var choosedEquipments = this.data.choosedEquipments;
    choosedEquipments[eid] = choosedEquipments[eid] == true ? false : true;
    this.setData({
      choosedEquipments: choosedEquipments,
      filter: Object.assign({},this.data.filter,{
        equipments:equipments.indexOf(eid)>-1 ? equipments.filter(i=>i!=eid):equipments.concat([eid])
      })
    })
    console.log('选择的会议室设备id:'+this.data.filter.equipments);
  },
  inputStartTime:function(e){
    var filter = this.data.filter;
    filter.starttime = e.detail.value;
    // this.setData({filter: filter});// 这里不确定是什么情况,当输入任何一个数字的时候,输入框会被清空,但是data里的starttime是有数据的,所以只能先不设置,此时,数据其实也已经在data.filter中存在了。

    // this.setData({
    //   filter: Object.assign({},this.data.filter,{
    //     // starttime:e.detail.value
    //   })
    // })  //输入会议开始时间
  },
  inputEndTime:function(e){
    var filter = this.data.filter;
    filter.endtime = e.detail.value;
    // this.setData({filter: filter});
    // this.setData({
    //   filter: Object.assign({},this.data.filter,{
    //     endtime:e.detail.value
    //   })
    // })  //输入会议结束时间
  },
  cleanFilter:function(){ //清空筛选条件
    this.setData({
      filter:{},
      choosedEquipments:{},
    })
  },
  submitFilter:function(){ //提交筛选条件
    console.log(this.data.filter);
  },

  onLoad: function (options) {
    this.fetchConferenceData();
    this.fetchFilterData();
  },

  
  // 滚动相关事件
  scrollHandle:function(e){ //滚动事件
    this.setData({
      scrolltop:e.detail.scrollTop
    })
  },
  goToTop:function(){ //回到顶部
    this.setData({
      scrolltop:0
    })
  },
  scrollLoading:function(){ //滚动加载
    this.fetchConferenceData();
  },
  onPullDownRefresh:function(){ //下拉刷新
    this.setData({
      page:0,
      conferencelist:[]
    })
    this.fetchConferenceData();
    this.fetchFilterData();
    setTimeout(()=>{
      wx.stopPullDownRefresh()
    },1000)
  }
})

11. 会议室预订页面conferencedetail

这个跟“众创空间”页面非常类似,就不重新写了。

12. 云资源申请,这个页面空白,回头再看

13. 园区问问question

13.1. 概要图

有问题反馈和常见问题2个tab,图片如下

13.2. 关键功能点

13.2.1. 选择图片上传

13.2.2. 图片上传,长按图片删除

  • 顶部和底部的tab效果

  • js里面splice函数的使用

var fruits = [“Banana”, “Orange”, “Apple”, “Mango”];
fruits.splice(2,1,“Lemon”,“Kiwi”); // Banana,Orange,Lemon,Kiwi,Mango
// splice(i,j)是从第i位置删除j个元素,并把删除了哪些元素返回回来,原来的数组,会变成剔除已删除元素,不需要另外赋值
var indexRemove = 0
var testArr = [10,9,8]
console.log(testArr.splice(indexRemove,1)) // 输出10
console.log(testArr) // 输出9,8

页面wxml:

<view class="container">
	<view class="container-body container-gray" style="display:{{showfootertab==0?'block':'none'}}">
		<view class="group">
			<view class="group-header">问题描述</view>
			<view class="group-body">
				<textarea placeholder="请输入对问题的描述,可输入1000字" maxlength="1000"></textarea>
			</view>
			<view class="group-header">上传图片(长按删除)</view>
			<view class="group-body">
				<view class="img-upload">
					<view class="img-add" bindtap="chooseImage"></view>
					<view class="img-item" bindlongtap="editImage" wx:for="{{uploadimgs}}" wx:key="{{index}}">
						<icon type="clear" size="20" color="red" style="display:{{editable?'block':'none'}}" bindtap="deleteImg" data-index="{{index}}" />
						<image src="{{item}}" mode="aspectFill"></image>
					</view>
				</view>
			</view>
			<view class="group-header">联系信息</view>
			<view class="group-body">
				<view class="input-list">
					<view class="input-item">
						<text class="input-item-label">联系人</text>
						<view class="input-item-content">
							<input type="text" auto-focus placeholder="请输入您的姓名" bindinput="inputName"></input>
						</view>
					</view>
					<view class="input-item">
						<text class="input-item-label">手机号码</text>
						<view class="input-item-content">
							<input type="idcard" placeholder="请输入您的手机号码" maxlength="11" bindinput="inputPhone"></input>
						</view>
					</view>
				</view>
			</view>
		</view>
		<view class="btn-submit">
			<button class="btn-block btn-orange" bindtap="questionSubmit">确认提交</button>
		</view>
		<view class="question-text">
			<text>如问题无法简单描述清楚</text>
			<text>可以直接拨打电话</text>
			<text>我们将第一时间为您答疑解惑</text>
			<view bindtap="callContact" data-phonenumber="400-1234-567">400-1234-567</view>
		</view>
	</view>

  <view class="container-body container-gray" style="display:{{showfootertab==1?'block':'none'}}">
		<view class="tab">
			<view class="tab-nav">
				<text wx:for="{{tabnav.tabitem}}" bindtap="setTab" class="{{showtab==index?'active':''}}" data-tabindex="{{index}}" data-type="{{item.type}}" wx:key="{{item.type}}">{{item.text}}</text>
				<view class="tab-line" style="width:{{100/tabnav.tabnum}}%;transform:translateX({{100*showtab}}%);"></view>
			</view>
			<view class="tab-content">
				<view class="tab-panel">
					<view class="question-list">
						<view class="question-item {{showquestionindex==index?'active':''}}" wx:for="{{questions}}" wx:key="{{item.id}}" bindtap="foldQuestion" data-qindex="{{index}}">
							<view class="question-item-q">{{item.q}}类型:{{item.type}}</view>
							<view class="question-item-a">{{item.a}}</view>
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>

	<!-- 底部的tabBar标签栏 -->
	<view class="footer-tab footer-tab-widthicon">
		<view class="footer-tab-item {{showfootertab==0?'active':''}}" data-index="0" bindtap="showTab">
			<image src="../../images/{{showfootertab==0?'xinxifill':'xinxi'}}.png" mode="aspectFit"></image>
			<text>问题反馈</text>
		</view>
		<view class="footer-tab-item {{showfootertab==1?'active':''}}" data-index="1" bindtap="showTab">
			<image src="../../images/{{showfootertab==1?'wenhaofill':'wenhao'}}.png" mode="aspectFit"></image>
			<text>常见问题</text>
		</view>
	</view>
</view>

样式wxss:

.container-gray {
  background: #f9f9f9;
}

.group {
  display: block;
  width: 100%;
}

.group-header {
  line-height: 70rpx;
  display: flex;
  padding: 0 20rpx;
  background: #f9f9f9;
}

.group-body {
  background: #fff;
  border-top: 1rpx solid #ddd;
  border-bottom: 1rpx solid #ddd;
}

textarea {
  width: 100%;
  padding: 20rpx;
  box-sizing: border-box;
}


/* 上传图片部分样式 */
.img-upload {
  padding: 20rpx;
  font-size: 0;
  overflow: hidden;
}

.img-upload .img-item {
  position: relative;
}

.img-upload .img-item,
.img-upload .img-add {
  width: 100rpx;
  height: 100rpx;
  float: left;
  margin: 10rpx;
  border: 1rpx solid transparent;
}

.img-upload .img-add {
  border: 1rpx dashed #ddd;
  /* 是不能这些写rul的,需要转base64 */
  background: url(../../images/add.png) no-repeat 50% 50% / 70% auto;
}
.img-upload .img-item image{
	width: 100rpx;
	height: 100rpx;
}

.img-upload .img-item icon {
  position: absolute;
  right: -12rpx;
  top: -12rpx;
}

/* 联系人信息输入部分样式 */
.group-body .input-list{
	margin: 0;
	border: none;
}
.input-list{
	padding: 0 20rpx;
	margin: 20rpx 0;
	background: #fff;
	border-top: 1rpx solid #ddd;
	border-bottom: 1rpx solid #ddd;
}
.input-list .input-item:first-child{
	border-top: 0;
}
.input-list .input-item{
	padding: 20rpx;
	line-height: 2;
	display: flex;
	font-size: 30rpx;
	border-top: 1rpx solid #e8e8e8;
}
.input-item-label{
	display: block;
	width: 5em;
	color: #666;
}
.input-item-content{
	color: #333;
	flex:1;
}
input{
	height: 60rpx;
	line-height: 60rpx;
 	font-family: inherit;
}

/* 确认提交按钮样式 */
.btn-submit{
	padding: 20rpx;
}
.btn-block{
	width: 100%;
	line-height: 88rpx;
}
.btn-orange{
	background: #f7982a;
	color: #fff;
}

/* 热线电话部分 */
.question-text{
	padding: 20rpx;
	text-align: center;
}
.question-text text{
	display: block;
	color: #888;
	font-size: 28rpx;
}
.question-text view{
	font-size: 48rpx;
	color: #f7982a;
}

/* 底部的tabBar */
.footer-tab{
	display: flex;
	width: 100%;
	border-top: 1rpx solid #ddd;
}
.footer-tab .footer-tab-item{
	flex: 1;
	text-align: center;
}
.footer-tab-widthicon image{
	width: 44rpx;
	height: 44rpx;
	display: block;
	margin: 10rpx auto 0;
}
.footer-tab-item.active text{
	color: #f7982a;
}
.footer-tab-item text{
	font-size: 24rpx;
	color: #888;
}

/* 整个“常见问题”页面的样式 */
.tab{
	display: flex;
	flex-direction: column;
	height: 100%;
}
.tab-nav{
	height: 80rpx;
	background: #fff;
	border-bottom: 1rpx solid #ddd;
	display: flex;
	line-height: 79rpx;
	position: relative;
}
.tab-nav text{
	display: block;
	flex: 1;
	text-align: center;
	width: 25%;
}
.tab-nav text.active{
	color: #f7982a;
}
.tab-line{
	position: absolute;
	left: 0;
	bottom: -1rpx;
	height: 4rpx;
	background: #f7982a;
	transition: all 0.3s;
}
/* 常见问题的正文部分样式 */
.tab-content{
	flex: 1;
	overflow-y: auto;
	overflow-x: hidden;
}
/* 问题列表的样式 */
.question-list{
	padding: 20rpx;
}
.question-item{
	background: #fff;
	margin-bottom: 20rpx;
	border-bottom: 1rpx solid #ddd;
}
/* 问题的背景样式 */
.question-item-q{
	padding: 20rpx;
	background: #cecece;
	padding-left: 80rpx;
	padding-right: 70rpx;
	position: relative;
	line-height: 1.2;
	color: #fff;
}
.question-item-q:before,
.question-item-a:before{
	content: 'Q';
	display: block;
	width: 50rpx;
	height: 50rpx;
	border-radius: 50%;
	background: #f97c29;
	font-size: 34rpx;
	text-align: center;
	line-height: 50rpx;
	position: absolute;
	left: 20rpx;
	top: 14rpx;
}
.question-item-q:after{
	content: '';
	display: block;
	width: 40rpx;
	height: 50rpx;
	background: url('../../images/downwhite.png') no-repeat 50% 50% / 100% auto;
	position: absolute;
	right: 20rpx;
	top: 14rpx;
}
.question-item .question-item-a{
	display: -webkit-box;
	-webkit-line-clamp: 2;
	overflow: hidden;
	text-overflow: ellipsis;
	-webkit-box-orient: vertical;
	margin: 20rpx 0;
}
.question-item-a{
	padding: 0 20rpx;
	padding-left: 80rpx;
	position: relative;
	line-height: 1.4;
	color: #666;
}
.question-item-a:before{
	content: 'A';
	background: #f7982a;
	color: #fff;
	top: 0;
}
/* 选中后的高亮效果 */
.question-item.active .question-item-q{
	background: #f97c29;
}
.question-item.active .question-item-a{
	-webkit-line-clamp: inherit;
}

逻辑js:

import util from './../../utils/util.js';
Page({

  data: {
    showfootertab:0,  //底部标签页索引
    questions:[], //问题列表
    tabnav:{},  //顶部选项卡数据
    showtab:0,  //顶部选项卡索引
    showtabtype:'', //选中类型
  },

  showTab:function(e){  //切换选项卡
    const eindex = e.currentTarget.dataset.index;
    if(eindex==1 && !this.data.questions){
      console.log("text");
    }
    wx.setNavigationBarTitle({
      title:eindex==1?"常见问题":"问题反馈"
    })
    this.setData({
      showfootertab:eindex
    });
  },
  fetchQuestions:function(){  //获取问题列表
    const newquestions = [];
    for (let i = 0; i < 50; i++) {
      newquestions.push({
        "id":i+1,
        "type": util.getRandomArrayElement(["A","B","C","D"]),
        "q":"意外保护服务内容是什么-"+(i+1)+"?",
        "a":"服务名称适用品类服务实施详情服务期限服务生效时间摔碰管修一年笔记本本服务有效期内,如客户的数码摄照产品在正常使用过程中由于不慎将产品坠落、挤压、碰撞,而产生的硬件故障,本服务将免费提供硬件维修或更换,使产品重新恢复正常运行。12个月购机满30天后开始生效摔碰管修两年笔记本、数码相机、摄像机、手机、小数码"
      })
    }
    this.setData({
      questions:newquestions,
      questionsall:newquestions
    })
  },
  setTab:function(e){ //设置选项卡选中索引
    const edata = e.currentTarget.dataset;
    this.setData({
      showtab: edata.tabindex,// 当前是选中第几个tab,即index
      showtabtype: edata.type,// 这个貌似没有用到
      questions: !edata.type ? this.data.questionsall:this.data.questionsall.filter(l=>l.type === edata.type),
      showquestionindex: this.data.showtab==edata.tabindex?this.data.showquestionindex:null
    })
  },
  foldQuestion:function(e){ //点击问题列表的问题,展开收起效果,展开会把问题的A部分全部展开
    const eindex = e.currentTarget.dataset.qindex;
    const oldqindex = this.data.showquestionindex;
    this.setData({
      showquestionindex: eindex===oldqindex?null:eindex
    })
  },

  chooseImage:function() {
    let _this = this;
    wx.showActionSheet({
      itemList: ['从相册中选择', '拍照'],
      itemColor: "#f7982a",
      success: function(res) {
        if (!res.cancel) {
          if(res.tapIndex == 0){
            _this.chooseWxImage('album')
          }else if(res.tapIndex == 1){
            _this.chooseWxImage('camera')
          }
        }
      }
    })
  },
  chooseWxImage:function(type){
    let _this = this;
    wx.chooseImage({
      sizeType: ['original', 'compressed'],
      sourceType: [type],
      success: function (res) {
        _this.setData({
          uploadimgs: _this.data.uploadimgs.concat(res.tempFilePaths)
        })
      }
    })
  },
  editImage:function(){
    this.setData({
      editable: !this.data.editable
    })
  },
  deleteImg:function(e){
    
    // var fruits = ["Banana", "Orange", "Apple", "Mango"];
    // fruits.splice(2,1,"Lemon","Kiwi"); // Banana,Orange,Lemon,Kiwi,Mango
    // 但是这里好像不是这样的,splice(i,j)是从第i位置删除j个元素,并把删除了哪些元素返回回来
    // var indexRemove = 0
    // var testArr = [10,9,8]
    // console.log(testArr.splice(indexRemove,1))  // 输出10
    // console.log(testArr)  // 输出9,8

    var index = e.currentTarget.dataset.index
    var imgs = this.data.uploadimgs
    imgs.splice(index, 1) // 如果写成 imgs = imgs.splice(index, 1)也不对,因为splice是返回被删除的元素,imgs会踢掉呗删除的,留下的就是没删的
    this.setData({
      uploadimgs: imgs
    })
  },

  questionSubmit:function(){

  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

    

    this.fetchQuestions();
    this.setData({
      tabnav:{
        tabnum:5,
        tabitem:[
          {
            "id":0,
            "type":"",
            "text":"全部"
          },
          {
            "id":1,
            "type":"A",
            "text":"服务咨询"
          },
          {
            "id":2,
            "type":"B",
            "text":"空间查询"
          },
          {
            "id":3,
            "type":"C",
            "text":"活动咨询"
          },
          {
            "id":4,
            "type":"D",
            "text":"入驻信息"
          }
        ]
      },
      uploadimgs:[]
    })
  },
})

14. 物业服务perperty

14.1. 概要图

14.2. 关键功能点:多色块选择

多色块选择主要还是通过样式来完成

wxml

<view class="container container-gray">
	<view class="group">
		<view class="group-header">选择报销物品</view>
		<view class="group-body">
			<view class="multiple-select">
				<view wx:for="{{checitems}}" wx:key="{{item.id}}">
					<text data-id="{{item.id}}"bindtap="onSelectTag" class="{{selectedid==item.id?'active':''}}">{{item.text}}</text>
				</view>
			</view>
		</view>
		<view class="group-header">问题描述</view>
		<view class="group-body">
			<textarea placeholder="请输入您的详细问题,我们将尽快解决"></textarea>
		</view>
	</view>
	<view class="btn-submit">
		<button class="btn-block btn-orange">提交</button>
	</view>
</view>

样式wxss:

.container-gray{
	background: #f9f9f9;
}
.group{
	display: block;
	width: 100%;
}
.group-header{
	line-height: 70rpx;
	display: flex;
	padding: 0 20rpx;
	background: #f9f9f9;
}
.group-body{
	background: #fff;
	border-top: 1rpx solid #ddd;
	border-bottom: 1rpx solid #ddd;
}
/* 报销物品的排布 */
.multiple-select{
	padding: 20rpx;
	display: flex;
	flex-wrap: wrap;
}
/* 每个元素的排布 */
.multiple-select view{
	flex: 0 0 25%;
	max-width: 25%;
	padding: 10rpx;
	box-sizing: border-box;
}
/* 每个元素的边框 */
.multiple-select text{
	display: block;
	border: 1rpx solid #ddd;
	line-height: 66rpx;
	color: #666;
	font-size: 28rpx;
	text-align: center;
	border-radius: 4rpx;
}
/* 选中后的高亮效果 */
.multiple-select text.active{
	background: #f7982a;
	color: #fff;
	border-color: #f7982a;
}

/* 问题描述部分样式 */
textarea{
	width: 100%;
	padding: 20rpx;
  box-sizing: b
  order-box;
}


button{
	font-size: 32rpx;
	line-height: 72rpx;
}
.btn-block{
	width: 100%;
	line-height: 88rpx;
}
.btn-orange{
	background: #f7982a;
	color: #fff;
}
.btn-submit{
	padding: 20rpx;
}

逻辑js:无内容,只是初始化数据

// pages/property/property.js
Page({
  data: {
    checitems: [],
    selectedid: null
  },

  onLoad: function (options) {
    this.setData({
      checitems: [{
          "id": 1,
          "text": "灯"
        },
        {
          "id": 2,
          "text": "电路"
        },
        {
          "id": 3,
          "text": "空调"
        },
        {
          "id": 4,
          "text": "消防"
        },
        {
          "id": 5,
          "text": "电梯"
        },
        {
          "id": 6,
          "text": "门"
        },
        {
          "id": 7,
          "text": "下水道"
        },
        {
          "id": 8,
          "text": "墙面"
        },
        {
          "id": 9,
          "text": "窗户"
        },
        {
          "id": 10,
          "text": "天花板"
        },
        {
          "id": 11,
          "text": "其他"
        }
      ]
    })
  },

  onSelectTag: function(e){
    const eid = e.currentTarget.dataset.id;
    const selected = this.data.selected;
    this.setData({
      // selected:selected.indexOf(eid)>-1?selected.filter(i=>i!=eid):selected.concat(eid)
      selectedid:eid
    })
    console.log(this.data.selectedid);
  }
})

15. 我发起的my

15.1. 概要图

15.2. 关键功能点:列表

页面wxml:

<view class="container">
	<view class="my-list">
		<navigator class="my-item" url="../myconferencelist/myconferencelist">
			<image src="../../images/icon_24.png" mode="aspectFit"></image>
			<text>入驻申请</text>
		</navigator>
		<navigator class="my-item" url="../myconferencelist/myconferencelist">
			<image src="../../images/icon_26.png" mode="aspectFit"></image>
			<text>物业服务</text>
		</navigator>
		<navigator class="my-item" url="../myconferencelist/myconferencelist">
			<image src="../../images/icon_28.png" mode="aspectFit"></image>
			<text>会议室预订</text>
		</navigator>
		<navigator class="my-item" url="../myconferencelist/myconferencelist">
			<image src="../../images/icon_30.png" mode="aspectFit"></image>
			<text>问题反馈</text>
		</navigator>
		<navigator class="my-item" url="../myconferencelist/myconferencelist">
			<image src="../../images/icon_32.png" mode="aspectFit"></image>
			<text>云资源申请</text>
		</navigator>
	</view>
</view>

样式wxss:

.my-item{
	border-bottom: 1rpx solid #ddd;
	padding: 20rpx;
	font-size: 32rpx;
	background: #fff url('../../images/xiangyou1.png') no-repeat 98% 50% / auto 36rpx;
}

.my-item image{
	width: 40rpx;
	height: 40rpx;
	margin-right: 20rpx;
	vertical-align: -6rpx;
}

逻辑js:无内容

Page({

})
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值