心理咨询类_微信小程序项目实战、含:标注图、效果图、视频、源码

一、项目概述

1.1 教程导读

        本套教程以项目为导向,从零构建一整套微信小程序项目,从静态页面实现,到后台数据mock服务搭建、最后前后台数据交互。

        本套教程是模拟线上微信小程序应用:十方智育实现。

        本套教程相关素材、代码、视频,如有需要的,可以私信我 或 评论区留下邮箱。

1.2 适合人群

        有一定的HTML/CSS/JavaScript基础,无需精通。

       有一定基础的同学,可以按照教程文档,逐步实现项目;本套教程同样适用于零基础的同学,在配套视频中,是以零基础的方式进行的讲解。

1.3 项目效果图

首页

 咨询页面

课程页面

我的页面

 文章列表页

 咨询师详情页 

登录页面

注册页面

1.4 配套资料

效果图

标注图

切图素材

视频讲解

二、项目环境搭建

2.1 开发工具的下载和安装

        1、下载微信开发者工具:
                https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html
        2、下载对应操作系统版本的工具即可;

        3、安装注意事项:
                大家在学习过程中,会安装各种各样的工具;
                3.1 尽量避免出现中文目录,但是国内的开发工具其实可以出现中文目录;
                3.2 尽量避免出现空格、特殊符号(_不归纳到特殊符号中);
                3.3 尽量避免安装在C盘,如果磁盘多,可以用一个磁盘专门安装软件,如果磁盘少,那么就定义一个文件夹,专门安装软件;
    
        4、安装步骤
                4.1 双击wechat_devtools_1.05.2108130_x64.exe进行安装
                4.2 进入安装向导界面,直接点击下一步
                4.3 进入许可协议界面,点击我接受
                4.4 选定安装目录(参照3),我的安装目录:D:\Tools\微信web开发者工具,点击安装
                4.5 等待安装完毕,点击完成

2.2 账号的注册

        1、必须得有微信账号,你使用微信开发者工具,需要通过微信登录;

        2、必须得有小程序帐号,最终小程序帐号要和微信用户绑定;绑定之后,你的微信账号就是小程序的管理员;

        3、一个微信账号可以绑定很多个微信小程序;

        4、申请地址:    https://mp.weixin.qq.com/cgi-bin/wx?token=&lang=zh_CN
                4.1 点击页面底部的前往注册按钮
                4.2 需要邮箱作为登录帐号,你可以使用QQ、126、163、雅虎等;
                    申请一个126邮箱;
                4.3 帐号信息:填写帐号、密码、验证码等信息,会向邮箱发送一个激活链接;
                4.4 邮箱激活:去邮箱进行激活即可;
                4.5 信息登记:
                        注册国家/地区:中国大陆
                        主体类型:个人
                        主体信息登记:身份证姓名、身份证号码、管理员手机号码等
                4.6 提交完成之后,点击弹出中的前往小程序;

2.3 项目搭建

        1、双击桌面上的微信开发者工具图标,第一次使用,需要通过微信账号进行扫码登录;

        2、在左侧:选择小程序项目 -> 小程序

        3、再右侧:点击 + 号,创建微信小程序;

        4、创建小程序的选项:
                项目名称:sfzy
                目录:D:\WeChatProjects\sfzy
                AppID:把我们刚才注册的AppID粘贴过来即可;
                        左侧菜单:开发管理 -> 开发设置 -> 找到AppID
                开发模式:小程序
                后端服务:不使用云服务
                语言:JavaScript
    
        5、点击确定,即可创建一个微信小程序项目。所有的微信小程序创建出来以后,都会自带一些demo代码;

2.4 开发者工具界面介绍

2.4.1 三大区域

        模拟器区域:模拟真机环境,我们的代码在不同手机上呈现的基本效果;可以在左上角选择机型、百分比、字体大小等;
                机型:主要是看分辨率;而不是必须找到对应的厂商品牌;如果真的很纠结的话,可以自定义;
                显示比例:可以让我们更完整的看到效果;
                字体大小:不要更改,16即可;
                注:开发微信小程序,机型推荐都选择iphone6/7/8

        编辑器区域:项目结构目录 和 编辑代码;
                包含两部分:资源管理器 和 编辑器;
                资源管理器:项目目录结构

        调试器区域:代码调试;

2.4.2 菜单栏

        1、头像:用来切换登录用户;

        2、模拟器、编辑器、调试器:三个按钮,用来打开或关闭三大区域

        3、编译模式:可以切换编译模式
                普通编译默认打开的项目首页;
                点击编译下拉菜单,选择添加编译模式。
                        模式名称:自定义,可以出现中文;
                        启动页面:选择模式对应的页面;
                        点击确定即可;

        4、编译按钮:手动编译;

        5、预览按钮:出现二维码,通过微信扫码,可以在手机端查看效果;

        6、真机调试:在手机端预览,并通过调试台查看真实反馈;

        7、清缓存:清理缓存数据

        8、上传:把代码上传到微信小程序服务器

        9、详情:包含了小程序的基本信息设置

三、静态页面实现

3.1 首页

3.1.1 导航栏和tabBar

全局配置介绍

        微信小程序端中实现导航栏和tabBar,是通过配置实现的;这是区别于移动端开发的点;

        参考文档: https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
        
        小程序的配置分为三部分:
                全局配置:对微信小程序进行全局配置,它是对整个视口(可视化窗口)的设置;
                页面配置:对本页面的窗口表现进行配置。
                sitemap 配置:对微信小程序的索引规则的配置。

        小程序根目录下的 app.json 文件用来对微信小程序进行全局配置。文件内容为一个 JSON 对象,有以下属性:

entryPagePath

        指定小程序的默认启动路径(首页),常见情景是从微信聊天列表页下拉启动、小程序列表启动等。如果不填,将默认为 pages 列表的第一项。不支持带页面路径参数。

{
  "entryPagePath": "pages/index/index"
}

pages

        用于指定小程序由哪些页面组成,每一项都对应一个页面的 路径(含文件名) 信息。文件名不需要写文件后缀,框架会自动去寻找对应位置的 .json.js.wxml.wxss 四个文件进行处理。

        未指定 entryPagePath 时,数组的第一项代表小程序的初始页面(首页)。

        小程序中新增/减少页面,都需要对 pages 数组进行修改。

        定义四个tabBar页面:

{
    "pages": [
        "pages/index/index",
        "pages/consult/consult",
        "pages/course/course",
        "pages/my/my"
    ]
}

window

        用于设置小程序的状态栏、导航条、标题、窗口背景色。

属性 类型 默认值 描述 最低版本
navigationBarBackgroundColor HexColor #000000 导航栏背景颜色,如 #000000
navigationBarTextStyle string white 导航栏标题颜色,仅支持 black / white
navigationBarTitleText string 导航栏标题文字内容
navigationStyle string default 导航栏样式,仅支持以下值:
default 默认样式
custom 自定义导航栏,只保留右上角胶囊按钮。参见注 2。
iOS/Android 微信客户端 6.6.0,Windows 微信客户端不支持
backgroundColor HexColor #ffffff 窗口的背景色
backgroundTextStyle string dark 下拉 loading 的样式,仅支持 dark / light
backgroundColorTop string #ffffff 顶部窗口的背景色,仅 iOS 支持 微信客户端 6.5.16
backgroundColorBottom string #ffffff 底部窗口的背景色,仅 iOS 支持 微信客户端 6.5.16
enablePullDownRefresh boolean false 是否开启全局的下拉刷新。
onReachBottomDistance number 50 页面上拉触底事件触发时距页面底部距离,单位为 px。
pageOrientation string portrait 屏幕旋转设置,支持 auto / portrait / landscape
  • 注 1:HexColor(十六进制颜色值),如"#ff00ff"
  • 注 2:关于navigationStyle
    • iOS/Android 客户端 7.0.0 以下版本,navigationStyle 只在 app.json 中生效。
    • iOS/Android 客户端 6.7.2 版本开始,navigationStyle: custom 对web-view组件无效
    • 开启 custom 后,低版本客户端需要做好兼容。开发者工具基础库版本切到 1.7.0(不代表最低版本,只供调试用)可方便切到旧视觉
    • Windows 客户端 3.0 及以上版本,为了给用户提供更符合桌面软件的使用体验,统一了小程序窗口的导航栏,navigationStyle: custom 不再生效

        全局窗口配置如下:

{
    "window": {
        "backgroundTextStyle": "light",
        "navigationBarBackgroundColor": "#fff",
        "navigationBarTitleText": "十方智育",
        "navigationBarTextStyle": "black",
        "navigationStyle": "default",
        "backgroundColor": "#eee",
        "onReachBottomDistance": 60
    }
}

tabBar

        如果小程序是一个多 tab 应用(客户端窗口的底部或顶部有 tab 栏可以切换页面),可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面。

属性 类型 必填 默认值 描述 最低版本
color HexColor tab 上的文字默认颜色,仅支持十六进制颜色
selectedColor HexColor tab 上的文字选中时的颜色,仅支持十六进制颜色
backgroundColor HexColor tab 的背景色,仅支持十六进制颜色
borderStyle string black tabbar 上边框的颜色, 仅支持 black / white
list Array tab 的列表,详见 list 属性说明,最少 2 个、最多 5 个 tab
position string bottom tabBar 的位置,仅支持 bottom / top
custom boolean false 自定义 tabBar,见详情

其中 list 接受一个数组,只能配置最少 2 个、最多 5 个 tab。tab 按数组的顺序排序,每个项都是一个对象,其属性值如下:

属性 类型 必填 说明
pagePath string 页面路径,必须在 pages 中先定义
text string tab 上按钮文字
iconPath string 图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。
当 position 为 top 时,不显示 icon。
selectedIconPath string 选中时的图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。
当 position 为 top 时,不显示 icon。

tabBar配置如下:

{
  "tabBar": {
    "color": "#898989",
    "selectedColor": "#87cefa",
    "list": [{
        "pagePath": "pages/index/index",
        "text": "主页",
        "iconPath": "/images/@2x_home_line.png",
        "selectedIconPath": "/images/@2x_home.png"
      },
      {
        "pagePath": "pages/consult/consult",
        "text": "咨询",
        "iconPath": "/images/@2x_talk_line.png",
        "selectedIconPath": "/images/@2x_talk.png"
      },
      {
        "pagePath": "pages/course/course",
        "text": "课程",
        "iconPath": "/images/@2x_class_line.png",
        "selectedIconPath": "/images/@2x_class.png"
      },
      {
        "pagePath": "pages/my/my",
        "text": "我的",
        "iconPath": "/images/@2x_my_line.png",
        "selectedIconPath": "/images/@2x_my.png"
      }
    ]
  }
}

完整配置

{
  "entryPagePath": "pages/index/index",
  "pages": [
    "pages/index/index",
    "pages/consult/consult",
    "pages/course/course",
    "pages/my/my"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "十方智育",
    "navigationBarTextStyle": "black",
    "navigationStyle": "default",
    "backgroundColor": "#eee",
    "onReachBottomDistance": 60
  },
  "tabBar": {
    "color": "#898989",
    "selectedColor": "#87cefa",
    "list": [{
        "pagePath": "pages/index/index",
        "text": "主页",
        "iconPath": "/images/@2x_home_line.png",
        "selectedIconPath": "/images/@2x_home.png"
      },
      {
        "pagePath": "pages/consult/consult",
        "text": "咨询",
        "iconPath": "/images/@2x_talk_line.png",
        "selectedIconPath": "/images/@2x_talk.png"
      },
      {
        "pagePath": "pages/course/course",
        "text": "课程",
        "iconPath": "/images/@2x_class_line.png",
        "selectedIconPath": "/images/@2x_class.png"
      },
      {
        "pagePath": "pages/my/my",
        "text": "我的",
        "iconPath": "/images/@2x_my_line.png",
        "selectedIconPath": "/images/@2x_my.png"
      }
    ]
  },
  "style": "v2",
  "sitemapLocation": "sitemap.json"
}

删除自带的logs页面

        1、删除小程序根目录下的 app.json 文件中pages里面的logs路径配置;
        2、删除logs目录;

3.1.2 搜索框

        结合效果图和标注图,我们可以分析得出结论:搜索框区域是由两个容器组成的;
                一个外部容器 和 一个内部容器;
                外部容器包裹内部容器;而且内部容器正好在外部容器的居中(水平垂直居中)位置

        微信小程序的一个页面对应了四个文件,js文件、json文件、wxml文件、wxss文件
                wxml文件 -> html文件
                wxss文件 -> css文件
                js文件   -> js文件
                json文件 -> 配置文件
                        app.json    全局配置文件
                        index/my/course/..json文件    页面配置文件

页面结构

        1、删除index.wxml里面的demo代码;

        2、在index.wxml文件中定义两个嵌套view,布局容器的特点:宽度占据100%视口,但是高度是随着内容;
                在微信小程序中,定义布局容器使用的是view;可以在view里面定义内容;

        3、在内部view引入图片和文字;
                在微信小程序中,定义图片使用的是image组件;通过image组件的src属性引入图片;
                在微信小程序中,定义部分文字,可以使用text组件;
    
        4、有了结构之后,效果没有达到我们的预期,那么我们需要添加修饰;添加修饰,需要区分不同的元素,那么我们可以给组件添加id属性。

<!-- 顶部搜索框的实现 -->
<view id="searchOuterView">
  <view id="searchInnerView">
    <image src="/images/@2x_find.png"></image>
    <text> 搜索</text>
  </view>
</view>

样式实现

        微信小程序的样式都是写在对应的wxss文件中;
        
        1、删除index.wxss里面的demo样式代码;

        2、搜索图片太大,我们可以给这个图片设置大小;
                通过searchInnerView查找图片
                #searchInnerView > image ->选择id为searchInnerView组件里面的image组件
                标注图里面的pt,在微信小程序使用的单位是rpx;
                1pt = 1px = 2rpx;
    
        3、给搜索文字设置大小和文字颜色;
                给搜索文本之前添加一个空格,可以让图片和文字拉开一点间距;

        4、图片和文字居中,给searchInnerView设置内容居中;

        5、给searchInnerView设置宽、高、背景颜色、边框、圆角;
    
        6、图片和文字垂直水平居中,并且对齐;    
                6.1 给searchInnerView里面的文字设置行高
                6.2 给图片和文字分别设置垂直对齐方式

        7、给searchOuterView设置内边距
                内边距:边框到内容之间的距离;

/* 顶部搜索框样式 */
#searchOuterView{
  /* 设置内边距 */
  padding: 15rpx;
}

#searchInnerView{
  /* 内容居中 */
  text-align: center;
  /* 设置宽高 */
  width: 720rpx;
  height: 58rpx;
  /* 设置背景颜色 */
  background: #EEEEEE;
  /* 设置边框 */
  border: 2rpx solid #ECECEE;
  /* 设置边框圆角 */
  border-radius: 8rpx;
  /* 设置行高 */
  line-height: 52rpx;
  /* 设置边框包含在宽高之内 */
  box-sizing: border-box;
}

#searchInnerView > image{
  /* 给图片设置宽和高 */
  width: 36rpx;
  height: 36rpx;
  /* 设置垂直对齐方式 */
  vertical-align: middle;
}

#searchInnerView > text{
  /* 给文字设置大小 */
  font-size: 24rpx;
  /* 给文字设置颜色 */
  color: #B2B2B2;
  /* 设置垂直对齐方式 */
  vertical-align: middle;
}

3.1.3 轮播图

页面结构

        微信小程序的轮播图特别简单即可实现,因为微信给我们提供了轮播图组件;
        swiper组件文档:https://developers.weixin.qq.com/miniprogram/dev/component/swiper.html
    
        1、从swiper组件文档的最底部的wxml中复制swiper组件的相关代码;

        2、从swiper组件文档的最底部的JavaScript中复制data数据,放在index.js的data里面;
                把index.js里面原有的data数据给删掉;

        3、把swiper-item里面的view改成image,因为每个滑块展示出来的都是一张图片;

        4、swiper-item是定义在block wx:for这个语法里面,wx:for是引用的js里面data的数据,data里面对应的数组值有几个,那么就会生成几个swiper-item;
                4.1 wx:for引用的值改为imgUrls,这样是为了见名知意
                4.2 把imgUrls数组里面写成需要使用的图片的路径
                4.3 在image组件中引入对应的图片路径
    
        5、通过swiper相关属性来设置自动轮播、轮播间隔、轮播方向等;
                indicator-dots        是否显示面板指示点
                indicator-active-color        当前选中的指示点颜色
                autoplay        是否自动切换
                interval        自动切换时间间隔
                duration        滑动动画时长
                circular        是否采用衔接滑动

<!-- 轮播图 -->
<!-- 
  swiper组件是用来定义滑块视图容器; swiper-item就是每一个滑块;
  我们需要展示三张图片,三张图片的轮播,那么也就是说需要三个swiper-item
-->
<swiper indicator-dots="{
   
   {indicatorDots}}" indicator-active-color="{
   
   {activeColor}}" autoplay="{
   
   {autoplay}}"
  interval="{
   
   {interval}}" duration="{
   
   {duration}}" circular="{
   
   {circular}}">
  <!-- 
    block是一个辅助性组件,它不会有任何展示效果; 
    wx:for 用来定义for循环,wx:for="数组"
    {
   
   {表达式}} wxml的插值表达式,从js的data里面引用值;
      {
   
   {background}},从js的data中获取background对应的值
    在wxml页面中需要使用的数据,我们最好都定义在data中
  -->
  <block wx:for="{
   
   {imgUrls}}" wx:key="*this">
    <swiper-item>
      <!-- swiper-item里面承载的是一张图片,不同的swiper-item承载的不同图片 -->
      <image src="{
   
   {item}}"></image>
    </swiper-item>
  </block>
</swiper>
data: {
    imgUrls: ['/images/img1.png', '/images/img2.png', '/images/img3.png'],
    indicatorDots: true,
    vertical: false,
    autoplay: true,
    interval: 3500,
    duration: 500,
    activeColor: "#fff",
    circular: true
  },

样式实现

        1、标注图对于轮播图区域的高度定义的是160pt,但是实际开发的时候,为了展示效果更好,调高了一些,那么我们高度使用200pt;给swiper设置高度;
    
        2、给图片设置宽、高;

/* 轮播图样式 */
swiper{
  height: 400rpx;
}

/* 选择swiper里面的后代元素image */
swiper image{
  width: 750rpx;
  height: 400rpx;
}

3.1.4 导航菜单

页面结构

        通过分析标注图,我们得出结论,一个大的view,包含了6个小的view,每个小view里面都有一个图片和文字;

        1、定义一个view,用来承载所有的导航菜单,给其定义id:navView

        2、在navView里面定义6个子view,给其定义class:navItemView

        3、在每个navItemView里面定义image和text;

<!-- 导航菜单 -->
<view id="navView">
  <view class="navItemView">
    <image src="/images/@2x_ceping.png"></image>
    <text>心理测评</text>
  </view>
  <view class="navItemView">
    <image src="/images/@2x_yuyue.png"></image>
    <text>咨询预约</text>
  </view>
  <view class="navItemView">
    <image src="/images/@2x_dayi.png"></image>
    <text>心理答疑</text>
  </view>
  <view class="navItemView">
    <image src="/images/@2x_zhishi.png"></image>
    <text>心理知识</text>
  </view>
  <view class="navItemView">
    <image src="/images/@2x_FM.png"></image>
    <text>FM</text>
  </view>
  <view class="navItemView">
    <image src="/images/@2x_gongyi.png"></image>
    <text>公益中心</text>
  </view>
</view>

样式实现

        在微信小程序里面,所有的image都默认赋予了指定的宽高;

        1、给navItemView里面的所有图片设置宽高;

        2、给navItemView设置宽度,宽度和图片宽度一致,设置文本居中;
                view组件的特点是独占一行,及时设置了宽高;
    
        3、想要让navItemView不独占一行,有很多种方式,但是在移动端更多的是使用flex布局;
        flex布局教程:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
                3.1 给navView应用flex布局,采用了flex布局之后,所有的子元素都会排列在一行;
                3.2 给navView设置换行显示;
                3.3 给navItemView设置左右间距,我们称之为外边距;
                3.4 给navView设置高度。
                3.5 给navView设置多根轴线的对齐方式。

/* 导航菜单样式 */
#navView{
  /* 应用flex布局 */
  display: flex;
  /* 设置换行显示 */
  flex-wrap: wrap;
  height: 464rpx;
  /* 多轴线的垂直排列方式 */
  align-content:space-around;
  font-size: 26rpx;
  /* 字体加粗 */
  font-weight: bold;
}

.navItemView{
  width: 150rpx;
  text-align: center;
  /* 设置左右外边距 */
  margin: 0 50rpx;
}

.navItemView > image{
  width: 150rpx;
  height: 150rpx;
}

3.1.5 在线客服

        理念:不要添加无意义的组件或标签;

        给页面添加一个整体的灰色背景色,然后给必要的组件添加白色背景;

页面结构

        1、定义一个view,用来承载在线客服相关内容,给其定义id:onlineView
    
        2、在onlineView定义图片、文本;

<!-- 在线客服 -->
<view id="onlineView">
  <image src="/images/@2x_zixunpeixun.png"></image>
  <text> 咨询助理在线客服</text>
  <!-- 右箭头实现 -->
  <view class="arrow"></view>
</view>

样式实现

        1、给onlineView里面的图片设置宽、高;

        2、给onlineView设置高度、背景颜色、上下外边距、左右内边距、设置行高;

        3、给onlineView文本设置字体大小、字体加粗;
                设计图上的24pt有点问题,我们只需要26rpx即可;
                记得把导航菜单里面的字体也改成26rpx 加粗;

        4、图片和文字对齐;

右箭头实现

        右箭头的实现:一个正方形、定义上边框和右边框、旋转45度、然后通过定位放到指定位置;

        给arrow元素设置 position: absolute; 使用绝对定位,绝对定位是相对于父元素进行定位,前提父元素必须具有定位属性。
        给#onlineView设置position: relative; 让父元素具有定位属性;

/* 在线客服样式 */
#onlineView{
  height: 88rpx;
  background: #fff;
  /* 设置上下外边距 */
  margin: 24rpx 0;
  /* 设置左右内边距 */
  padding: 0 30rpx;
  line-height: 88rpx;
  position: relative;
}

#onlineView > image{
  width: 60rpx;
  height: 60rpx;
  vertical-align: middle;
}

#onlineView > text{
  font-size: 26rpx;
  /* 字体加粗 */
  font-weight: bold;
  vertical-align: middle;
}

/* 右箭头的实现原理: 一个正方形,定义上/右边框,旋转45度 */
.arrow{
  width: 16rpx;
  height: 16rpx;
  border-top: 4rpx solid #999;
  border-right: 4rpx solid #999;
  /* 旋转45度 */
  transform: rotate(45deg);
  /* 调整位置 */
  position: absolute;
  right: 30rpx;
  top: 38rpx;
}

3.1.6 精选文章

页面结构

        1、定义view,用来承载文章标题、所有文章列表、查看更多;给其添加id:hotArticleView

        2、定义view,用来承载文章总标题,给其添加id:hotArticleTitleView

        3、定义三个view,用来承载三个精选文章列表,这三个view,效果都是一样的,区别点在于图片和文字不同;给这三个view添加class:articleView
    
        4、在articleView里面分了左右两部分
                4.1 在articleView定义两个子view;左边承载图片,右边承载文字;给右侧的view添加class:articleContent;
                4.2 在articleContent分为上下两部分,定义两个子view,分别添加class:articleTitle、articleDesc;

        5、定义view,用来表示查看更多,给其添加id:moreView
                在这个view里面定义文本和右箭头

<!-- 精选文章 -->
<view id="hotArticleView">
  <!-- 文章总标题 -->
  <view id="hotArticleTitleView">
    精选文章
  </view>
  <!-- 文章列表 -->
  <view class="articleView">
    <view>
      <image src="/images/article01.png"></image>
    </view>
    <view class="articleContent">
      <view class="articleTitle">
        你活出自我的样子,真美
      </view>
      <view class="articleDesc">
        千百年来,古人总是把人的品格与自然之物相联系起来,以花草树木之品性喻人的精神情操。
      </view>
    </view>
  </view>
  <view class="articleView">
    <view>
      <image src="/images/article02.png"></image>
    </view>
    <view class="articleContent">
      <view class="articleTitle">
        你活出自我的样子,真美
      </view>
      <view class="articleDesc">
        千百年来,古人总是把人的品格与自然之物相联系起来,以花草树木之品性喻人的精神情操。
      </view>
    </view>
  </view>
  <view class="articleView">
    <view>
      <image src="/images/article03.png"></image>
    </view>
    <view class="articleContent">
      <view class="articleTitle">
        你活出自我的样子,真美
      </view>
      <view class="articleDesc">
        千百年来,古人总是把人的品格与自然之物相联系起来,以花草树木之品性喻人的精神情操。
      </view>
    </view>
  </view>

  <!-- 查看更多 -->
  <view id="moreView"> 
    <text>查看更多</text>
    <view class="arrow"></view>
  </view>
</view>

 样式实现

        1、给hotArticleView添加左右内边距、背景颜色;

        2、给hotArticleTitleView设置高度、字体大小、字体粗细;下边框、行高;

        3、给articleView 里面的图片设置大小;

        4、给articleView应用flex布局、上下内边距、下边框;

        5、给articleView 里面的图片设置右外边距;

        6、给右侧文章标题和描述内容分别设置文字大小、颜色、行高;
                文章标题设置28rpx;

        7、给moreView设置高度、行高、相对定位;

        8、给moreView里面的文字设置大小、颜色;

        9、给hotArticleView添加下外边距;

/* 精选文章 */
#hotArticleView{
  padding: 0 30rpx;
  background: #fff;
  margin-bottom: 24rpx;
}

#hotArticleTitleView{
  height: 88rpx;
  font-size: 30rpx;
  font-weight: bold;
  border-bottom: 1rpx solid #F1F1F1;
  line-height: 88rpx;
}

.articleView {
  display: flex;
  padding: 30rpx 0;
  border-bottom: 1rpx solid #F1F1F1;
}

.articleView image{
  width: 120rpx;
  height: 120rpx;
  margin-right: 20rpx;
}

.articleTitle{
  font-size: 28rpx;
  font-weight: bold;
  line-height: 50rpx;
}

.articleDesc{
  font-size: 26rpx;
  color: #A9A9A9;
  line-height: 35rpx;
}

#moreView{
  height: 88rpx;
  line-height: 88rpx;
  font-size: 28rpx;
  color: #A6A6A6;
  position: relative;
}

3.1.7 请求回答

页面结构

        定义一个view,给其添加id:askView,在其中定义一张图片;

<!-- 请求回答 -->
<view id="askView">
  <image src="/images/@2x_fudong.png"></image>
</view>

样式实现

        1、设置图片的大小

        2、给askView添加固定定位(无论页面内容怎么滚动,元素一致在窗口的指定位置),设置对应的位置即可;

/* 请求回答 */
#askView{
  position: fixed;
  bottom: 100rpx;
  right: 10rpx;
}

#askView > image{
  width: 100rpx;
  height: 100rpx;
}

3.2 咨询页面

3.2.1 页面标题

        我们之前在app.json里面进行了全局配置,设置标题为十方智育;

        现在咨询预约页面的标题不是十方智育,那么我们可以通过页面配置将全局配置给覆盖掉;
    
        页面配置:https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/page. html

        每一个小程序页面也可以使用 .json 文件来对本页面的窗口表现进行配置。页面中配置项在当前页面会覆盖 app.json 的 window 中相同的配置项。文件内容为一个 JSON 对象,有以下属性:

        页面配置的所有配置项,我们都在全局配置中给大家说过。

        注:为了方便查看所写页面效果,我们可以添加编译模式;

        在consult.json中配置页面标题;

{
  "usingComponents": {},
  "navigationBarTitleText":"咨询预约"
}

3.2.2 筛选框

页面结构

        1、定义一个view,给其添加id:filterView;

        2、在filterView里面定义图片和文本;

<!-- 筛选框 -->
<view id="filterView">
  <image src="/images/@2x_touch.png"></image>
  <text> 点击筛选</text>
</view>

样式实现

        1、给filterView里面的图片设置大小;

        2、给filterView里面的文本设置大小、字体颜色;

        3、给filterView设置文本居中、高度、背景颜色、行高;

        4、给filterView里面的图片和文字设置垂直对齐方式;

/* 筛选框样式 */
#filterView{
  background: #87cefa;
  height: 88rpx;
  text-align: center;
  line-height: 88rpx;
}

#filterView > image{
  width: 48rpx;
  height: 48rpx;
  vertical-align: middle;
}

#filterView > text{
  font-size: 30rpx;
  color: #fff;
  vertical-align: middle;
}

3.2.3 咨询师列表

页面结构

        1、定义一个view,给其定义id:consultListView,用来承载所有的咨询师;

        2、在consultListView定义一个view,给其定义class:consultView;

        3、在consultView里面定义两个view,左边的view是用来承载图片,右边的view是用来承载咨询师信息,给其定义class:consultInfoView,我们把咨询师的信息放在三个子view里面;
                一个咨询师的结构实现了,其他的就是复制粘贴即可;
                将来结合数据的时候,其实就只需要一个view结构,因为view放在循环里面使用,有多少数据就遍历多少个view;

    
        选择器:用来选择页面元素给其添加样式;
                #xx    根据id选择元素;
                .yy    根据类选择元素;
                zz    根据组件名选择元素
                父元素 > 子元素    选择父元素的所有子元素
                父元素 子元素    选择父元素的所有后代元素
                父元素 > 子元素:nth-child(num)    选择父元素的第num个子元素

<!-- 咨询师列表 -->
<view id="consultListView">
  <!-- 一个咨询师的结构 -->
  <view class="consultView">
    <view>
      <image src="/images/zxs01.jpg"></image>
    </view>
    <view class="consultInfoView">
      <view>张婧</view>
      <view>国家二级咨询师</view>
      <view>中国专业人才库全国心理学考评管理中心专家评委、中国全脑效能研能指导师...</view>
    </view>
  </view>
  <view class="consultView">
    <view>
      <image src="/images/zxs02.jpg"></image>
    </view>
    <view class="consultInfoView">
      <view>憨豆</view>
      <view>国家二级咨询师</view>
      <view>中国专业人才库全国心理学考评管理中心专家评委、中国全脑效能研能指导师...</view>
    </view>
  </view>
  <view class="consultView">
    <view>
      <image src="/images/zxs03.jpg"></image>
    </view>
    <view class="consultInfoView">
      <view>韩梅梅</view>
      <view>国家二级咨询师</view>
      <view>中国专业人才库全国心理学考评管理中心专家评委、中国全脑效能研能指导师...</view>
    </view>
  </view>
  <view class="consultView">
    <view>
      <image src="/images/zxs04.jpg"></image>
    </view>
    <view class="consultInfoView">
      <view>李维嘉</view>
      <view>国家二级咨询师</view>
      <view>中国专业人才库全国心理学考评管理中心专家评委、中国全脑效能研能指导师...</view>
    </view>
  </view>
  <view class="consultView">
    <view>
      <image src="/images/zxs05.jpg"></image>
    </view>
    <view class="consultInfoView">
      <view>刘诗诗</view>
      <view>国家二级咨询师</view>
      <view>中国专业人才库全国心理学考评管理中心专家评委、中国全脑效能研能指导师...</view>
    </view>
  </view>
  <view class="consultView">
    <view>
      <image src="/images/zxs06.jpg"></image>
    </view>
    <view class="consultInfoView">
      <view>黎曼</view>
      <view>国家二级咨询师</view>
      <view>中国专业人才库全国心理学考评管理中心专家评委、中国全脑效能研能指导师...</view>
    </view>
  </view>
</view>

样式实现

        1、给consultListView设置左右内边距;
    
        2、给consultView设置上下内边距、下边框、flex布局;
    
        3、给consultView里面的图片设置大小、右外边距;
    
        4、给consultInfoView里面的三个子元素,分别设置文字大小、粗细、颜色、行高;

/* 咨询师列表样式 */
#consultListView{
  padding: 0 10rpx;
}

.consultView{
  padding: 10rpx 0;
  border-bottom: 1rpx solid #F1F1F1;
  display: flex;
}

.consultView image{
  width: 180rpx;
  height: 180rpx;
  margin-right: 10rpx;
}

.consultInfoView > view:nth-child(1){
  font-size: 34rpx;
  font-weight: bold;
  line-height: 50rpx;
}

.consultInfoView > view:nth-child(2){
  font-size: 30rpx;
  color: #5E5E5E;
  line-height: 50rpx;
}

.consultInfoView > view:nth-child(3){
  font-size: 24rpx;
  color: #A9A9A9;
  line-height: 40rpx;
}

3.2.4 正在加载

页面结构

        1、定义view,给其添加id:loadingView
    
        2、在loadingView里面定义图片和文字即可;
    
        注:正在加载区域,要结合动态数据使用,当我们从后台获取数据,但是数据还没拿到的时候,展示loadingView,如果拿到了数据,因此loadingView;

<!-- 正在加载 -->
<view id="loadingView">
  <image src="/images/loading.gif"></image>
  <text> 正在加载更多数据</text>
</view>

样式实现

        1、给loadingView里面的图片设置大小;

        2、给loadingView里面的文本设置大小;

        3、给loadingView设置文本居中、高度、背景颜色、行高;

        4、给loadingView里面的图片和文字设置垂直对齐方式;

/* 正在加载样式 */

#loadingView{
  text-align: center;
  height: 88rpx;
  background: #F0EFF5;
  line-height: 88rpx;
}

#loadingView > image{
  width: 48rpx;
  height: 48rpx;
  vertical-align: middle;
}

#loadingView > text{
  font-size: 28rpx;
  vertical-align: middle;
}

3.3 课程页面

3.3.1 页面标题和搜索框

        页面标题也是通过页面配置实现;
    
        搜索框如果不考虑代码复用,那么直接从首页的代码中复制粘贴相关的结构和样式即可;

3.3.2 小导航

页面结构

        1、定义一个view,给其定义id:smallNavView;

        2、在smallNavView定义三个子view

        3、子view里面分别承载对应的图片和文字即可;

<!-- 小导航 -->
<view id="smallNavView">
  <view>
    <image src="/images/@2x_online.png"></image>
    <text> 在线课程</text>
  </view>
  <view>
    <image src="/images/@2x_teacher.png"></image>
    <text> 师资团队</text>
  </view>
  <view>
    <image src="/images/@2x_gonggao.png"></image>
    <text> 咨询公告</text>
  </view>
</view>

样式实现

        1、给smallNavView里面的所有图片设置大小;
    
        2、给smallNavView里面的文本设置字体大小、颜色;

        3、给smallNavView里面的view设置背景颜色、高度、行高;

        4、给smallNavView里面的文字和图片设置垂直对齐方式;

        5、给smallNavView设置flex布局;给smallNavView的子view等比放大1;

        6、给smallNavView的子view设置文本居中

        7、给smallNavView的第二个子view,设置左右边框即可;

/* 小导航样式实现 */
/* 应用了flex布局的,我们称之为flex容器 */
#smallNavView {
  display: flex;
}

/* flex的子元素,我们称之为flex项目 */
#smallNavView > view{
  height: 88rpx;
  line-height: 88rpx;
  background: #87cefa;
  flex-grow: 1;
  text-align: center;
}

#smallNavView > view:nth-child(2){
  border-left: 2rpx solid #fff;
  border-right: 2rpx solid #fff;
}

#smallNavView image{
  width: 44rpx;
  height: 44rpx;
  vertical-align: middle;
}

#smallNavView text{
  font-size: 30rpx;
  color: #fff;
  vertical-align: middle;
}

3.3.3 轮播图

        从首页复制粘贴相关的结构和样式即可,然后修改下图片资源即可;

<!-- 轮播图 -->
<swiper indicator-dots="{
   
   {indicatorDots}}" indicator-active-color="{
   
   {activeColor}}" autoplay="{
   
   {autoplay}}"
  interval="{
   
   {interval}}" duration="{
   
   {duration}}" circular="{
   
   {circular}}">
  <block wx:for="{
   
   {imgUrls}}" wx:key="*this">
    <swiper-item>
      <!-- swiper-item里面承载的是一张图片,不同的swiper-item承载的不同图片 -->
      <image src="{
   
   {item}}"></image>
    </swiper-item>
  </block>
</swiper>
data: {
    imgUrls: ['/images/kc01.jpg', '/images/kc02.jpg', '/images/kc03.jpg'],
    indicatorDots: true,
    vertical: false,
    autoplay: true,
    interval: 3500,
    duration: 500,
    activeColor: "#fff",
    circular: true
  },

3.3.4 热门课程

页面结构

        1、定义一个view,给其添加id:hotCourseView
    
        2、在hotCourseView定义hotCourseTitleView,用来承载总标题
    
        3、在hotCourseView定义courseListView,用来承载四门课程,每个课程都是一个view,给其添加class:courseView
    
        4、在courseView里面定义图片和文字即可;

<!-- 热门课程 -->
<view id="hotCourseView">
  <!-- 热门课程标题 -->
  <view id="hotCourseTitleView">
    热门课程
  </view>
  <!-- 课程列表 -->
  <view id="courseListView">
    <!-- 一门课程 -->
    <view class="courseView">
      <image src="/images/hotkc01.jpg"></image>
      <text>心理科普:巴纳姆效应</text>
    </view>

    <view class="courseView">
      <image src="/images/hotkc02.jpg"></image>
      <text>心理科普:巴纳姆效应</text>
    </view>

    <view class="courseView">
      <image src="/images/hotkc03.jpg"></image>
      <text>心理科普:巴纳姆效应</text>
    </view>

    <view class="courseView">
      <image src="/images/hotkc04.jpg"></image>
      <text>心理科普:巴纳姆效应</text>
    </view>
  </view>
    
  <!-- 查看更多 -->
  <view id="moreView"> 
    <text>查看更多</text>
    <view class="arrow"></view>
  </view>
</view>

样式实现

        1、给hotCourseView设置左右内边距;

        2、给hotCourseTitleView设置高度、文字大小、加粗、文本居中、行高;

        3、给courseListView里面的所有图片设置大小;

        4、给courseView设置宽度,和图片一致;

        5、给courseListView设置flex布局、换行、项目在主轴上的对齐方式;

        6、给courseView设置下外边距、文本居中;

/* 热门课程样式 */
#hotCourseView{
  padding: 0 20rpx;
}

#hotCourseTitleView{
  height: 108rpx;
  line-height: 108rpx;
  font-size: 30rpx;
  text-align: center;
  font-weight: bold;
}

#courseListView{
  display: flex;
  flex-wrap: wrap;
  /* 项目在主轴上的对齐方式 */
  justify-content: space-between;
}

.courseView{
  width: 346rpx;
  margin-bottom: 40rpx;
  text-align: center;
}

#courseListView image{
  width: 346rpx;
  height: 220rpx;
}

#moreView{
  height: 88rpx;
  line-height: 88rpx;
  font-size: 28rpx;
  color: #A6A6A6;
  position: relative;
}

.arrow{
  width: 16rpx;
  height: 16rpx;
  border-top: 4rpx solid #999;
  border-right: 4rpx solid #999;
  /* 旋转45度 */
  transform: rotate(45deg);
  /* 调整位置 */
  position: absolute;
  right: 30rpx;
  top: 38rpx;
}

3.4 我的页面

3.4.1 用户信息展示

页面结构

        1、定义一个view,给其定义id:userInfoView;

        2、在userInfoView里面定义三个子view,分别用来承载昵称、来自哪里、积分;

<!-- 用户信息展示区域 -->
<view id="userInfoView">
  <view>昵称: 少年先锋队员</view>
  <view>来自: 河南·郑州</view>
  <view>积分: 1080</view>
</view>

样式实现

        1、给userInfoView设置背景颜色、上下内边距、文本居中;
                padding不同值的表示方式:
                *    上下左右的内边距
                **    上下、左右的内边距
                *** 上、左右、下的内边距
                **** 上、右、下、左的内边距(顺时针)
                注:给父元素的内容设置的样式,可以被子元素继承得到;比如:字体颜色、字体大小、文本居中;

        2、给三个子view的文字设置大小、颜色;

        3、给第二个子view设置上下外边距 或 内边距;

/* 用户信息展示样式 */
#userInfoView{
  background: #87cefa;
  padding: 30rpx 0 40rpx;
  text-align: center;
}

#userInfoView > view:nth-child(1){
  color: #fff;
  font-size: 34rpx;
}

#userInfoView > view:nth-child(2){
  color: #fff;
  font-size: 30rpx;
  padding: 30rpx 0;
}

#userInfoView > view:nth-child(3){
  color: #0f9ffb;
  font-size: 34rpx;
}

3.4.2 个人中心列表项

页面结构

         1、定义一个view,给其添加class:userItemListView;

        2、在userItemListView里面定义对应个数的子view;

        3、每个子view里面定义对应的文本和箭头;

<!-- 用户列表选项 -->
<view class="userItemListView">
  <view>
    <text>我的测评</text>
    <view class="arrow"></view>
  </view>
  <view>
    <text>我的咨询</text>
    <view class="arrow"></view>
  </view>
  <view>
    <text>我的回答</text>
    <view class="arrow"></view>
  </view>
  <view>
    <text>我的通知</text>
    <view class="arrow"></view>
  </view>
  <view>
    <text>课程收藏</text>
    <view class="arrow"></view>
  </view>
</view>

<view class="userItemListView">
  <view>
    <text>绑定手机</text>
    <view class="arrow"></view>
  </view>
  <view>
    <text>修改密码</text>
    <view class="arrow"></view>
  </view>
  <view>
    <text>关于我们</text>
    <view class="arrow"></view>
  </view>
  <view>
    <text>退出登录</text>
    <view class="arrow"></view>
  </view>
</view>

样式实现

        1、给页面设置整体的背景色;

        2、给userItemListView设置背景色、左右内边距、上下外边距;

        3、给userItemListView里面的子view设置高度、行高、下边框、相对定位;

        4、给文字设置大小、粗细;

        5、设置箭头样式;

        注:垂直外边距的合并;当两个外边距垂直堆叠的时候,不是累加,而是以两者大的为主;

/* 用户列表选项样式 */
.userItemListView{
  background: #fff;
  padding: 0 50rpx;
  margin: 24rpx 0;
}

.userItemListView > view{
  height: 88rpx;
  line-height: 88rpx;
  border-bottom: 1rpx solid #F1F1F1;
  position: relative;
}

/* 移除最后一个元素的下边框 */
.userItemListView > view:last-child{
  border: none;
}

.arrow{
  width: 16rpx;
  height: 16rpx;
  border-top: 4rpx solid #999;
  border-right: 4rpx solid #999;
  /* 旋转45度 */
  transform: rotate(45deg);
  /* 调整位置 */
  position: absolute;
  right: 30rpx;
  top: 38rpx;
}


.userItemListView text{
  font-size: 30rpx;
}

3.5 精选文章页面

3.5.1 前言

        目前我们已经实现了4张页面,分别是首页、咨询页面、课程页面、我的页面;这四张页面,我们都可以通过tabBar来实现跳转,这四个页面也就是我们所说的tabBar页面;
    
        对于非tabBar页面,怎么跳转呢?比如:我们现在要写的精选文章页面,是点击首页精选文章区域的查看更多跳转过来的;怎么实现跳转,这是我们这一节要讨论的重点;

        精选文章页面对大家来说,已经没有什么难度了;

3.5.2 文章列表

页面结构

          1、在app.json的pages配置里面定义pages/hotArticle/hotArticle;

        2、为hotArticle页面添加编译模式,否则无法查看效果;

        3、定义一个view,给其添加id:hotArticleView;

        4、给hotArticleView里面添加6个子view,结构和首页的精选文章类似;给6个ziview添加class:articleView;然后把首页的相关结构负责过来即可;
        注:
                虽说我们可以从首页复制结构,但是明显代码存在大量的冗余;我们在之后会给大家讲解模版;
                大家目前不用太纠结里面的文本内容,因为后续我们会用真实数据覆盖;

<!-- 文章列表区域 -->
<view id="hotArticleView">
  <view class="articleView">
    <view>
      <image src="/images/article01.png"></image>
    </view>
    <view class="articleContent">
      <view class="articleTitle">
        你活出自我的样子,真美
      </view>
      <view class="articleDesc">
        千百年来,古人总是把人的品格与自然之物相联系起来,以花草树木之品性喻人的精神情操。
      </view>
    </view>
  </view>

  <view class="articleView">
    <view>
      <image src="/images/article02.png"></image>
    </view>
    <view class="articleContent">
      <view class="articleTitle">
        你活出自我的样子,真美
      </view>
      <view class="articleDesc">
        千百年来,古人总是把人的品格与自然之物相联系起来,以花草树木之品性喻人的精神情操。
      </view>
    </view>
  </view>

  <view class="articleView">
    <view>
      <image src="/images/article03.png"></image>
    </view>
    <view class="articleContent">
      <view class="articleTitle">
        你活出自我的样子,真美
      </view>
      <view class="articleDesc">
        千百年来,古人总是把人的品格与自然之物相联系起来,以花草树木之品性喻人的精神情操。
      </view>
    </view>
  </view>

  <view class="articleView">
    <view>
      <image src="/images/article04.jpg"></image>
    </view>
    <view class="articleContent">
      <view class="articleTitle">
        你活出自我的样子,真美
      </view>
      <view class="articleDesc">
        千百年来,古人总是把人的品格与自然之物相联系起来,以花草树木之品性喻人的精神情操。
      </view>
    </view>
  </view>

  <view class="articleView">
    <view>
      <image src="/images/article05.jpg"></image>
    </view>
    <view class="articleContent">
      <view class="articleTitle">
        你活出自我的样子,真美
      </view>
      <view class="articleDesc">
        千百年来,古人总是把人的品格与自然之物相联系起来,以花草树木之品性喻人的精神情操。
      </view>
    </view>
  </view>

  <view class="articleView">
    <view>
      <image src="/images/article06.jpg"></image>
    </view>
    <view class="articleContent">
      <view class="articleTitle">
        你活出自我的样子,真美
      </view>
      <view class="articleDesc">
        千百年来,古人总是把人的品格与自然之物相联系起来,以花草树木之品性喻人的精神情操。
      </view>
    </view>
  </view>
</view>

样式实现

        1、给hotArticleView设置左右内边距;

        2、从index.css赋值articleView及其子元素的相关样式;

/* 文章列表区域*/
#hotArticleView{
  padding: 0 22rpx;
}

.articleView {
  display: flex;
  padding: 30rpx 0;
  border-bottom: 1rpx solid #F1F1F1;
}

.articleView image{
  width: 120rpx;
  height: 120rpx;
  margin-right: 20rpx;
}

.articleTitle{
  font-size: 28rpx;
  font-weight: bold;
  line-height: 50rpx;
}

.articleDesc{
  font-size: 26rpx;
  color: #A9A9A9;
  line-height: 35rpx;
}

3.5.3 正在加载

        和咨询预约页面的类似,复制相应的代码即可;

3.5.4 页面跳转

        当我们点击首页-精彩文章-查看更多的时候,跳转到精选文章页面;

组件跳转方式

        组件跳转方式,类似于html中的超链接;

        组件方式依赖于navigator组件,navigator组件就是页面链接。
    
        组件文档:https://developers.weixin.qq.com/miniprogram/dev/component/navigator.html

        该组件有很多数据,但是我们只需要使用常用的几个即可,其他的大家自行查阅文档;

        当我们点击页面的每个区域,来实现跳转的话,一般都使用组件跳转;

属性 类型 默认值 必填 说明
target string self 在哪个目标上发生跳转,默认当前小程序
url string 当前小程序内的跳转链接
open-type string navigate 跳转方

 target 的合法值

说明
self 当前小程序
miniProgram 其它小程序

open-type 的合法值

说明
navigate 对应 wx.navigateTowx.navigateToMiniProgram 的功能,保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。
redirect 对应 wx.redirectTo 的功能,关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。
switchTab 对应 wx.switchTab 的功能,跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
reLaunch 对应 wx.reLaunch 的功能
navigateBack 对应 wx.navigateBack 的功能
exit 退出小程序,target="miniProgram"时生效

        点击查看更多,跳转到精选文章页面,那么我们使用哪一种?第一种;

        1、把首页的查看更多的view,改为navigator组件;
    
        2、给navigator组件添加url属性,open-type属性;
                url: 精选文章的页面地址
                open-type:navigate

<navigator id="moreView" url="/pages/hotArticle/hotArticle" open-type="navigate"> 
    <text>查看更多</text>
    <view class="arrow"></view>
</navigator>

API跳转方式

        API跳转方式,类似于JS实现页面跳转;

        API跳转是需要结合事件,并且结合JS来实现;
    
        如果需要结合数据或逻辑来实现跳转的话,一般使用API跳转方式;比如登录成功跳转到我的页面;

        1、给查看更多view添加tap事件:手指触摸后马上离开;事件需要对应一个函数,当我们点击这个查看更多的时候,去执行函数里面的代码;

        2、在index.js里面添加goHotArticlePage函数,
                把index.js里面的bindViewTap、getUserProfile、getUserInfo函数都删除掉;把onload里面的代码也删除,但是onload留着;
        
        3、在goHotArticlePage函数里面写页面跳转的API即可;

<!-- 查看更多 -->
<view id="moreView" bindtap="goHotArticlePage"> 
    <text>查看更多</text>
    <view class="arrow"></view>
</view>
goHotArticlePage(){
    wx.navigateTo({
        url: '/pages/hotArticle/hotArticle',
    })
},

3.6 关于我们页面

3.6.1 页面效果实现

页面结构

        在app.json里面的pages里面定义"pages/aboutUs/aboutUs"

        1、定义一个view,给其添加id:qrCodeView,然后在其中定义图片和文字;

        2、定义一个view,给其添加id:companyView;

        3、在companyView里面定义5个子view,分别来承载公司名称、地址、电话、邮箱、简介,给这5个子view添加class=companyItemView;

        4、在companyItemView里面分别定义两个view,用来承载标题和文字;

        5、在第四个view和第五个view中间添加图片;

<!-- 二维码区域 -->
<view id="qrCodeView">
  <image src="/images/@2x_2weima.png"></image>
  <text>微信扫一扫关注我们</text>
</view>

<!-- 公司信息区域 -->
<view id="companyView">
  <view class="companyItemView">
    <view>公司名称</view>
    <view>河南十方心理咨询有限公司</view>
  </view>
  <view class="companyItemView">
    <view>公司地址</view>
    <view>河南自贸试验区郑州片区绿地新都会2号楼A座1007</view>
  </view>
  <view class="companyItemView">
    <view>联系电话</view>
    <view>0371-68105666</view>
  </view>
  <view class="companyItemView">
    <view>客服邮箱</view>
    <view>[email protected]</view>
  </view>

  <image src="/images/@2x_about.png"></image>
  
  <view class="companyItemView">
    <view>公司简介</view>
    <view>河南十方心理咨询有限公司成立于2017年5月23日, 是第一批有能力搭建社会心理服务体系的机构;是对企业全面实施EAP整体项目的专业供应商; 是为个体和企业提供个性化“心理测评”服务的心理健康机构;是对个体、团体进行心理咨询的心理服务机构; 是首个注重并开展青少年素质培养的心理教育机构。我们以“培育健康的人格素质” 为首要任务,一切以来访者的的个人成长和客户的收获为中心,在众多经验丰富的心理咨询专家的共同努力下,获得了社会。</view>
  </view>
</view>

样式实现

        1、给qrCodeView添加宽度、上下左右外边距;
    
        2、给qrCodeView里面的图片设置宽、高、下外边距(和文字拉开距离);给文字设置大小、居中即可;

        3、给companyView设置左右内边距;

        4、给companyItemView设置下外边距;

        5、给companyView里面的图片设置下外边距、宽、高;

        6、给companyItemView里面的子view设置文字大小和颜色;第一个子view添加下外边距/下内边距;

/* 二维码区域样式 */
#qrCodeView{
  width: 300rpx;
  margin: 20rpx auto 60rpx;
  font-size: 26rpx;
  text-align: center;
}

#qrCodeView > image{
  width: 300rpx;
  height: 300rpx;
  padding-bottom: 10rpx;
}


/* 公司信息区域 */
#companyView{
  padding: 0 40rpx;
}

.companyItemView{
  padding-bottom: 30rpx;
}

#companyView > image{
  width: 670rpx;
  height: 500rpx;
  margin-bottom: 40rpx;
}

.companyItemView > view:nth-child(1){
  font-size: 30rpx;
  color: #87cefa;
  padding-bottom: 20rpx;
}

.companyItemView > view:nth-child(2){
  font-size: 26rpx;
  color: #888;
}

3.6.2 关联跳转

        在我的页面中,把关于我们的view改为navigator,然后设置跳转路径和方式;

        注:把我的页面的每一项的view都换成navigator;然后样式稍微变更一下

<navigator url="/pages/aboutUs/aboutUs" open-type="navigate">
    <text>关于我们</text>
    <view class="arrow"></view>
</navigator>

...
.userItemListView > navigator{
  height: 88rpx;
  line-height: 88rpx;
  border-bottom: 1rpx solid #F1F1F1;
  position: relative;
}

/* 移除最后一个元素的下边框 */
.userItemListView > navigator:last-child{
  border: none;
}

3.7 咨询师详情页

3.7.1 咨询师信息

页面结构

         在app.json里面的pages里面定义"pages/consultDetails/consultDetails"

        1、定义一个view,给其添加id:consultInfoView;

        2、在consultInfoView定义4个view,分别承载咨询师头像、名称、等级、证书等;

        3、在第四个view里面定义两个view,分别承载已认证和查看证书的文本;给第四个view添加一个id:ccieView,是为了方便我们后续的样式添加;

<!-- 咨询师信息 -->
<view id="consultInfoView">
  <view>
    <image src="/images/zxs01.jpg"></image>
  </view>
  <view>
    张婧
  </view>
  <view>
    郑州市  国家二级心理咨询师
  </view>
  <view id="ccieView">
    <view>已认证</view>
    <view>查看证书</view>
  </view>
</view>

样式实现

        1、给consultInfoView设置背景色;
    
        2、给consultInfoView里面的第一个子view设置宽、高、外边距居中、上下外边距、背景色、圆角、文本居中;给第一个子view里面的图片设置大小、圆角、上外边距;
        注意:当我们给父元素的第一个子元素设置上外边距的时候,应用到了父元素,这叫上外边距的塌陷,给父元素设置overflow:hidden;

        3、给consultInfoView里面的第二个子view上设置文字大小、颜色、文本居中、加粗;

        4、给consultInfoView里面的第三个子view上设置文字大小、颜色、文本居中、下边框、上下内边距、宽度、居中;

        5、给ccieView设置上下左右内边距、flex布局、上下内边距;

        6、给ccieView里面的子view添加背景颜色、文字颜色、圆角、宽高、行高;

/* 咨询师信息样式 */
#consultInfoView{
  background: #87cefa;
  /* 解决上外边距的塌陷 */
  overflow: hidden;
  color: white;
}

#consultInfoView > view:nth-child(1){
  width: 200rpx;
  height: 200rpx;
  margin: 40rpx auto;
  border-radius: 100rpx;
  background: #fff;
  text-align: center;
}

#consultInfoView image{
  width: 160rpx;
  height: 160rpx;
  border-radius: 80rpx;
  margin-top: 20rpx;
}

#consultInfoView > view:nth-child(2){
    font-size: 36rpx;
    text-align: center;
    font-weight: bold;
}

#consultInfoView > view:nth-child(3){
  font-size: 30rpx;
  text-align: center;
  padding: 28rpx 0;
  border-bottom: 2rpx solid #fff;
  width: 690rpx;
  margin: 0 auto;
}

#ccieView {
  padding: 20rpx 76rpx;
  display: flex;
  justify-content: space-between;
}

#ccieView > view{
  width: 200rpx;
  height: 60rpx;
  height: 60rpx;
  background: #29AFF4;
  text-align: center;
  line-height: 60rpx;
  border-radius: 30rpx;
}

3.7.2 擅长领域

页面结构

        1、定义一个view,给其添加id:domainView;

        2、在domainView定义三个子view,分别来承载不同的文本;

<!-- 擅长领域 -->
<view id="domainView">
  <view>恋爱关系</view>
  <view>婚姻家庭</view>
  <view>情绪管理</view>
</view>

样式实现

        1、给domainView设置上下左右内边距、flex布局、水平排版、背景色;

        2、给domainView的三个子view设置背景色、宽、高、文字颜色、文本居中、行高、圆角、字体大小;

/* 擅长领域 */
#domainView{
  padding: 30rpx 76rpx;
  display: flex;
  justify-content: space-between;
  background: #fff;
}

#domainView > view{
  width: 150rpx;
  height: 50rpx;
  line-height: 50rpx;
  text-align: center;
  background: #87cefa;
  color: #fff;
  font-size: 24rpx;
  border-radius: 6rpx;
}

3.7.3 收费标准

页面结构

         1、定义view,给其添加class:consultItemView;

        2、在consultItemView里面定义view,给其添加class:titleView,用来承载标题;

        3、在consultItemView定义三个子view,给其添加class:chargeItemView;

        4、在chargeItemView里面定义三个子view,分别用来承载收费类型、收费金额、咨询人数等文本;

        5、在consultItemView定义一个view,用来承载查看更多和右箭头;

<!-- 收费标准 -->
<view class="consultItemView">
  <!-- 标题 -->
  <view class="titleView">
    收费标准
  </view>
  <!-- 收费项 -->
  <view class="chargeItemView">
    <view>语音咨询</view>
    <view>18人已咨询</view>
    <view>
      <text>500</text>/次(1小时)
    </view>
  </view>

  <view class="chargeItemView">
    <view>视频咨询</view>
    <view>18人已咨询</view>
    <view>
      <text>500</text>/次(1小时)
    </view>
  </view>

  <view class="chargeItemView">
    <view>倾诉咨询</view>
    <view>18人已咨询</view>
    <view>
      <text>500</text>/次(1小时)
    </view>
  </view>

  <!-- 查看更多 -->
  <view id="moreView" bindtap="goHotArticlePage"> 
    <text>查看更多</text>
    <view class="arrow"></view>
  </view>
</view>

样式实现

        1、给页面设置整体背景色;

        2、给consultItemView设置左右内边距和上下外边距、背景颜色;

        3、给titleView设置上下内边距、字体大小、粗细、下边框;

        4、给chargeItemView设置下边框、上下内边距、相对定位;

        5、给chargeItemView里面的三个子view分别设置字体大小、颜色;

        6、给chargeItemView第二个子view,设置绝对定位改变其位置;

        7、给chargeItemView第三个子view,设置上内边距;给它里面的text设置字体大小和颜色;

/* 收费标准 */
.consultItemView{
  margin: 24rpx 0;
  padding: 0 30rpx;
  background: #fff;
}

.titleView{
  padding: 30rpx 0;
  font-size: 30rpx;
  font-weight: bold;
  border-bottom: 1rpx solid #F1F1F1;
}

.chargeItemView{
  padding: 20rpx 0;
  border-bottom: 1rpx solid #F1F1F1;
  position: relative;
  color: #9F9F9F;
}

.chargeItemView > view:nth-child(1){
  font-size: 30rpx;
}

.chargeItemView > view:nth-child(2){
  font-size: 24rpx;
  position: absolute;
  top: 20rpx;
  right: 30rpx;
}

.chargeItemView > view:nth-child(3){
  font-size: 30rpx;
}

.chargeItemView > view:nth-child(3) text{
  color: #fe3000;
  font-size: 30rpx;
  font-weight: bold;
  padding-top: 20rpx;
}

3.7.4 回复留言

页面结构

        1、定义view,给其添加class:consultItemView;

        2、在consultItemView里面定义view,给其添加class:titleView,用来承载标题;

        3、在consultItemView定义三个子view,给其添加class:replyItemView;

        4、在replyItemView里面定义两个子view,分别用来承载问、答;

        5、在consultItemView定义一个view,用来承载查看更多和右箭头;

<!-- 回复留言 -->
<view class="consultItemView">
  <!-- 标题 -->
  <view class="titleView">
    回复留言
  </view>
  <!-- 收费项 -->
  <view class="replyItemView">
    <view>问: 家庭矛盾,情绪抑郁,社交恐惧症,自卑,时长心慌不安,巴拉拉巴拉</view>
    <view>
      答: 这里是咨询师回答的相关问题,第一,第二,第三。这里是咨询师回答的相关问题,第一,第二,第三。
      这里是咨询师回答的相关问题,第一,第二,第三。这里是咨询师回答的相关问题,第一,第二,第三。
      这里是咨询师回答的相关问题,第一,第二,第三。这里是咨询师回答的相关问题,第一,第二,第三。
    </view>
  </view>

  <view class="replyItemView">
    <view>问: 家庭矛盾,情绪抑郁,社交恐惧症,自卑,时长心慌不安,巴拉拉巴拉</view>
    <view>
      答: 这里是咨询师回答的相关问题,第一,第二,第三。这里是咨询师回答的相关问题,第一,第二,第三。
      这里是咨询师回答的相关问题,第一,第二,第三。这里是咨询师回答的相关问题,第一,第二,第三。
      这里是咨询师回答的相关问题,第一,第二,第三。这里是咨询师回答的相关问题,第一,第二,第三。
    </view>
  </view>

  <view class="replyItemView">
    <view>问: 家庭矛盾,情绪抑郁,社交恐惧症,自卑,时长心慌不安,巴拉拉巴拉</view>
    <view>
      答: 这里是咨询师回答的相关问题,第一,第二,第三。这里是咨询师回答的相关问题,第一,第二,第三。
      这里是咨询师回答的相关问题,第一,第二,第三。这里是咨询师回答的相关问题,第一,第二,第三。
      这里是咨询师回答的相关问题,第一,第二,第三。这里是咨询师回答的相关问题,第一,第二,第三。
    </view>
  </view>

  <!-- 查看更多 -->
  <view id="moreView" bindtap="goHotArticlePage"> 
    <text>查看更多</text>
    <view class="arrow"></view>
  </view>
</view>

样式实现

        1、给replyItemView设置下边框、上下内边距;

        2、给replyItemView里面的两个子view分别设置字体大小、颜色;

        3、给replyItemView里面的第一个子view,设置文本不换行,超出部分隐藏,用省略号替代、宽、高、行高、文本加粗;

        4、给replyItemView里面的第二个子view,设置高度、超出部分隐藏,用省略号替代、两行文本显示、多余的内容省略号隐藏、宽、高;
        参考文档:https://blog.csdn.net/weixin_33910759/article/details/89760530
        注:一行省略和两行省略实现方式不太一样;

/* 回复留言 */
.replyItemView{
  padding: 30rpx 0;
  border-bottom: 1rpx solid #F1F1F1;
}

.replyItemView > view:nth-child(1){
  font-size: 30rpx;
  width: 690rpx;
  height: 60rpx;
  line-height: 60rpx;
  font-weight: bold;
  /* 超出部分隐藏 */
  overflow: hidden;
  /* 文本不换行 */
  white-space: nowrap;
  /* 多余文本使用省略号替代 */
  text-overflow: ellipsis;
}

.replyItemView > view:nth-child(2){
  font-size: 24rpx;
  color: #9F9F9F;
  height: 80rpx;
  line-height: 40rpx;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  align-content: center;
}

3.7.5 用户评价

        用户评价和收费标准结构类似,样式稍微有一定的差异,根据效果图和标注图进行简单的修改即可;

五角星实现:参考文档:https://blog.csdn.net/sxs161028/article/details/107512671

<!-- 用户评价 -->
<view class="consultItemView">
  <!-- 标题 -->
  <view class="titleView">
    用户评价
  </view>
  <!-- 用户评论项 -->
  <view class="reviewItemView">
    <view class="userNameView">
      匿名用户
      <view>
        <view class="star">
          <view class="icon icon_yellow"></view>
        </view>
        <view class="star">
          <view class="icon icon_yellow"></view>
        </view>
        <view class="star">
          <view class="icon icon_yellow"></view>
        </view>
        <view class="star">
          <view class="icon icon_yellow"></view>
        </view>
        <view class="star half_star">
          <view class="icon icon_gray">
            <view class="icon icon_gray"></view>
          </view>
        </view>
      </view>
    </view>
    <view>昨天</view>
    <view>
      老师很细心,主要声音好听,长得美!
    </view>
  </view>

  <view class="reviewItemView">
    <view class="userNameView">
      匿名用户
      <view>
        <view class="star">
          <view class="icon icon_yellow"></view>
        </view>
        <view class="star">
          <view class="icon icon_yellow"></view>
        </view>
        <view class="star">
          <view class="icon icon_yellow"></view>
        </view>
        <view class="star">
          <view class="icon icon_yellow"></view>
        </view>
        <view class="star half_star">
          <view class="icon icon_gray">
            <view class="icon icon_yellow"></view>
          </view>
        </view>
      </view>
    </view>
    <view>昨天</view>
    <view>
      老师很细心,主要声音好听,长得美!
    </view>
  </view>

  <view class="reviewItemView">
    <view class="userNameView">
      匿名用户
      <view>
        <view class="star">
          <view class="icon icon_yellow"></view>
        </view>
        <view class="star">
          <view class="icon icon_yellow"></view>
        </view>
        <view class="star">
          <view class="icon icon_yellow"></view>
        </view>
        <view class="star">
          <view class="icon icon_gray"></view>
        </view>
        <view class="star half_star">
          <view class="icon icon_gray">
            <view class="icon icon_gray"></view>
          </view>
        </view>
      </view>
    </view>
    <view>昨天</view>
    <view>
      老师很细心,主要声音好听,长得美!
    </view>
  </view>


  <!-- 查看更多 -->
  <view id="moreView" bindtap="goHotArticlePage">
    <text>查看更多</text>
    <view class="arrow"></view>
  </view>
</view>
/* 用户评价 */
.reviewItemView {
  padding: 20rpx 0;
  border-bottom: 1rpx solid #F1F1F1;
  position: relative;
}

.reviewItemView>view:nth-child(1) {
  font-size: 24rpx;
  color: #9F9F9F;
}

.reviewItemView>view:nth-child(2) {
  font-size: 24rpx;
  position: absolute;
  top: 20rpx;
  right: 30rpx;
  color: #9F9F9F;
}

.reviewItemView>view:nth-child(3) {
  font-size: 30rpx;
  padding-top: 20rpx;
}

@font-face {
  font-family: 'FontAwesome';
  src: url('https://netdna.bootstrapcdn.com/font-awesome/3.2.1/font/fontawesome-webfont.woff?v=3.2.1') format('woff');
}

.userNameView {
  position: relative;
}

.userNameView > view{
  display:flex;
  position: absolute;
  left: 130rpx;
  top: 6rpx;
}

/*五角星之间的间距*/
.star {
  margin-right: 4rpx;
}

/*五角星*/
.star .icon:before {
  content: '\f005';
  font-family: FontAwesome;
  position: absolute;
  left: 0;
  top: 0;
  display: block;
  overflow: hidden;
}

.star .icon {
  display: block;
  font-size: 24rpx;
  text-align: center;
  width: 24rpx;
  height: 24rpx;
  line-height: 24rpx;
  position: relative;
  white-space: pre;
}

/*灰色五角星*/
.star .icon_gray {
  color: #DDDDDD;
}

/*黄色五角星*/
.star .icon_yellow:before {
  color: #FED300;
}

3.7.6 底部区域

页面结构

        1、定义一个view,然后给其添加id:bottomView;
    
        2、在bottomView定义两个子view,分成承载发私信和咨询;

<!-- 底部 -->
<view id="bottomView">
  <view>发私信</view>
  <view>咨询</view>
</view>

样式实现

        1、给bottomView使用flex布局;
    
        2、给bottomView里面的子view设置高度、等比放大、设置背景、设置文字大小颜色;

/* 底部样式 */
#bottomView{
  display: flex;
  text-align: center;
  border-top: 2rpx solid #F1F1F1;
}

#bottomView > view{
  flex-grow: 1;
  height: 98rpx;
  font-size: 36rpx;
  line-height: 98rpx;
}

#bottomView > view:nth-child(1){
  background: #F7F7FA;
  color: #979798;
  
}

#bottomView > view:nth-child(2){
  background: #87cefa;
  color: #fff;
}

注:点击咨询师列表中咨询师,跳转到对应的咨询师详情页,咨询师详情页就这一个页面,这是该页面中展示不同的动态数据,我们在后面结合数据的时候讲解;

3.8 登录页面

3.8.1 表单相关组件

button

        button 按钮。

        常用属性如下:

属性 类型 默认值 必填 说明
size string default 按钮的大小
type string default 按钮的样式类型
plain boolean false 按钮是否镂空,背景色透明
disabled boolean false 是否禁用
loading boolean false 名称前是否带 loading 图标
form-type string 用于 form 组件,点击分别会触发 form 组件的 submit/reset 事件
open-type string 微信开放能力
<button size="default">default</button>
<button size="mini">mini</button>
<button size="default" type="primary">primary</button>
<button size="default" type="default">default</button>
<button size="default" type="warn">warn</button>
<button size="default" plain="true">plain</button>
<button size="default" disabled>disabled</button>
<button size="default" loading>loading</button>

checkbox

        checkbox 多选项目。

        常用属性如下:

属性 类型 默认值 必填 说明
value string checkbox标识,选中时触发checkbox-group的 change 事件,并携带 checkbox 的 value
disabled boolean false 是否禁用
checked boolean false 当前是否选中,可用来设置默认选中
color string #09BB07 checkbox的颜色,同css的colo
<!-- 组件之间的文本是给用户看的,value是要提交的数据 -->
<checkbox value="足球">足球</checkbox>
<checkbox value="篮球" checked>篮球</checkbox>
<checkbox value="羽毛球">羽毛球</checkbox>
<checkbox value="禁用" disabled>禁用</checkbox>
<checkbox value="指定颜色" color="#87cefa">指定颜色</checkbox>

form

        表单。将组件内的用户输入的switch input checkbox slider radio picker 提交。

        当点击 form 表单中 form-type 为 submit 的 button 组件时,会将表单组件中的 value 值进行提交,需要在表单组件中加上 name 来作为 key。

        常用属性如下:

属性 类型 默认值 必填 说明
bindsubmit eventhandle 携带 form 中的数据触发 submit 事件,event.detail = {value : {'name': 'value'} , formId: ''}
bindreset eventhandle 表单重置时会触发 reset 事件

input

        输入框。该组件是原生组件,使用时请注意相关限制。

        常用属性如下:

属性 类型 默认值 必填 说明
value string 输入框的初始内容
type string text input 的类型
password boolean false 是否是密码类型
placeholder string 输入框为空时占位符
placeholder-style string 指定 placeholder 的样式
placeholder-class string input-placeholder 指定 placeholder 的样式类
disabled boolean false 是否禁用
maxlength number 140 最大输入长度,设置为 -1 的时候不限制最大长度
cursor-spacing number 0 指定光标与键盘的距离,取 input 距离底部的距离和 cursor-spacing 指定的距离的最小值作为光标与键盘的距离
auto-focus boolean false (即将废弃,请直接使用 focus )自动聚焦,拉起键盘
focus boolean false 获取焦点
<!-- 一般输入框不需要定义value,单选框和复选框经常需要使用value -->
<!-- 输入框输入的文本就是value的值,但是单选框和复选框需要指定value提交给服务器 -->
文本输入键盘:
<input type="text" value="张三123"/>
数字输入键盘:
<input type="number"/>
身份证输入键盘:
<input type="idcard"/>
带小数点的数字键盘:
<input type="digit"/>
密码安全输入键盘:
<input type="safe-password"/>
密码输入键盘:
<input type="text" password/>
带提示文本的输入框:
<input type="text" placeholder="请输入用户名"/>

picker

        从底部弹起的滚动选择器。

<view class="section">
  <view class="section__title">普通选择器</view>
  <picker bindchange="bindPickerChange" value="{
   
   {index}}" range="{
   
   {array}}">
    <view class="picker">
      当前选择:{
   
   {array[index]}}
    </view>
  </picker>
</view>
<view class="section">
  <view class="section__title">多列选择器</view>
  <picker mode="multiSelector" bindchange="bindMultiPickerChange" bindcolumnchange="bindMultiPickerColumnChange" value="{
   
   {multiIndex}}" range="{
   
   {multiArray}}">
    <view class="picker">
      当前选择:{
   
   {multiArray[0][multiIndex[0]]}},{
   
   {multiArray[1][multiIndex[1]]}},{
   
   {multiArray[2][multiIndex[2]]}}
    </view>
  </picker>
</view>
<view class="section">
  <view class="section__title">时间选择器</view>
  <picker mode="time" value="{
   
   {time}}" start="09:01" end="21:01" bindchange="bindTimeChange">
    <view class="picker">
      当前选择: {
   
   {time}}
    </view>
  </picker>
</view>

<view class="section">
  <view class="section__title">日期选择器</view>
  <picker mode="date" value="{
   
   {date}}" start="2015-09-01" end="2017-09-01" bindchange="bindDateChange">
    <view class="picker">
      当前选择: {
   
   {date}}
    </view>
  </picker>
</view>
<view class="section">
  <view class="section__title">省市区选择器</view>
  <picker mode="region" bindchange="bindRegionChange" value="{
   
   {region}}" custom-item="{
   
   {customItem}}">
    <view class="picker">
      当前选择:{
   
   {region[0]}},{
   
   {region[1]}},{
   
   {region[2]}}
    </view>
  </picker>
</view>
Page({
  data: {
    array: ['美国', '中国', '巴西', '日本'],
    objectArray: [
      {
        id: 0,
        name: '美国'
      },
      {
        id: 1,
        name: '中国'
      },
      {
        id: 2,
        name: '巴西'
      },
      {
        id: 3,
        name: '日本'
      }
    ],
    index: 0,
    multiArray: [['无脊柱动物', '脊柱动物'], ['扁性动物', '线形动物', '环节动物', '软体动物', '节肢动物'], ['猪肉绦虫', '吸血虫']],
    objectMultiArray: [
      [
        {
          id: 0,
          name: '无脊柱动物'
        },
        {
          id: 1,
          name: '脊柱动物'
        }
      ], [
        {
          id: 0,
          name: '扁性动物'
        },
        {
          id: 1,
          name: '线形动物'
        },
        {
          id: 2,
          name: '环节动物'
        },
        {
          id: 3,
          name: '软体动物'
        },
        {
          id: 3,
          name: '节肢动物'
        }
      ], [
        {
          id: 0,
          name: '猪肉绦虫'
        },
        {
          id: 1,
          name: '吸血虫'
        }
      ]
    ],
    multiIndex: [0, 0, 0],
    date: '2016-09-01',
    time: '12:01',
    region: ['广东省', '广州市', '海珠区'],
    customItem: '全部'
  },
  bindPickerChange: function(e) {
    console.log('picker发送选择改变,携带值为', e.detail.value)
    this.setData({
      index: e.detail.value
    })
  },
  bindMultiPickerChange: function (e) {
    console.log('picker发送选择改变,携带值为', e.detail.value)
    this.setData({
      multiIndex: e.detail.value
    })
  },
  bindMultiPickerColumnChange: function (e) {
    console.log('修改的列为', e.detail.column, ',值为', e.detail.value);
    var data = {
      multiArray: this.data.multiArray,
      multiIndex: this.data.multiIndex
    };
    data.multiIndex[e.detail.column] = e.detail.value;
    switch (e.detail.column) {
      case 0:
        switch (data.multiIndex[0]) {
          case 0:
            data.multiArray[1] = ['扁性动物', '线形动物', '环节动物', '软体动物', '节肢动物'];
            data.multiArray[2] = ['猪肉绦虫', '吸血虫'];
            break;
          case 1:
            data.multiArray[1] = ['鱼', '两栖动物', '爬行动物'];
            data.multiArray[2] = ['鲫鱼', '带鱼'];
            break;
        }
        data.multiIndex[1] = 0;
        data.multiIndex[2] = 0;
        break;
      case 1:
        switch (data.multiIndex[0]) {
          case 0:
            switch (data.multiIndex[1]) {
              case 0:
                data.multiArray[2] = ['猪肉绦虫', '吸血虫'];
                break;
              case 1:
                data.multiArray[2] = ['蛔虫'];
                break;
              case 2:
                data.multiArray[2] = ['蚂蚁', '蚂蟥'];
                break;
              case 3:
                data.multiArray[2] = ['河蚌', '蜗牛', '蛞蝓'];
                break;
              case 4:
                data.multiArray[2] = ['昆虫', '甲壳动物', '蛛形动物', '多足动物'];
                break;
            }
            break;
          case 1:
            switch (data.multiIndex[1]) {
              case 0:
                data.multiArray[2] = ['鲫鱼', '带鱼'];
                break;
              case 1:
                data.multiArray[2] = ['青蛙', '娃娃鱼'];
                break;
              case 2:
                data.multiArray[2] = ['蜥蜴', '龟', '壁虎'];
                break;
            }
            break;
        }
        data.multiIndex[2] = 0;
        break;
    }
    console.log(data.multiIndex);
    this.setData(data);
  },
  bindDateChange: function(e) {
    console.log('picker发送选择改变,携带值为', e.detail.value)
    this.setData({
      date: e.detail.value
    })
  },
  bindTimeChange: function(e) {
    console.log('picker发送选择改变,携带值为', e.detail.value)
    this.setData({
      time: e.detail.value
    })
  },
  bindRegionChange: function (e) {
    console.log('picker发送选择改变,携带值为', e.detail.value)
    this.setData({
      region: e.detail.value
    })
  }
})

switch

        开关选择器。

        常用属性如下:

属性 类型 默认值 必填 说明
checked boolean false 是否选中
disabled boolean false 是否禁用
type string switch 样式,有效值:switch, checkbox
color string #04BE02 switch 的颜色,同 css 的 color
bindchange eventhandle checked 改变时触发 change 事件,event.detail={ value}
<switch >开关</switch>
<switch checked>开关</switch>
<switch disabled>开关</switch>
<switch type="checkbox">开关</switch>

3.8.2 页面实现

页面结构

        在app.json里面的pages里面定义"pages/login/login"    

        1、定义一个form组件,form组件是表单。将组件内的用户输入的switch input checkbox slider radio picker 提交。
        
        2、定义view,给其添加id:inputView,在inputView里面定义文本框和密码框;无论是文本框还是密码框都依赖于input组件,input组件是输入框。该组件是原生组件,使用时请注意相关限制;

        3、定义view,给其添加id:buttonView,在buttonView里面定义提交按钮和注册按钮;无论是什么按钮,都是依赖于button组件。

        4、在buttonView里面添加一个view,用来承载忘记密码;

<!-- 定义form组件 -->
<form>
  <!-- 输入框区域 -->
  <view id="inputView">
    <!-- 文本框 -->
    <input type="text" placeholder="手机号/用户名"></input>
    <!-- 密码框 -->
    <input type="text" placeholder="密码" password></input>
  </view>

  <!-- 按钮区域 -->
  <view id="buttonView">
    <button>登录</button>
    <button>注册</button>
    <view>忘记密码</view>
  </view>
</form>

样式实现

        1、给页面添加整体背景色;

        2、给inputView添加白色背景,左右内边距;

        3、给inputView里面的input设置高度,第一个input设置下边框;

        4、给buttonView设置宽度、上外边距、左右居中;

        5、给buttonView里面的第一个按钮,设置背景颜色、宽、高、字体大小、颜色;

        6、给buttonView里面的第二个按钮,设置上下外边距、背景颜色、边框、文字颜色、大小;

        7、给buttonView里面的子view设置文字大小、颜色、右对齐;


/* 给页面设置整体背景色 */
page{
  background: #F0EFF5;
}

/* 输入框区域样式 */
#inputView{
  background: #fff;
  padding: 0 30rpx;
}

#inputView > input{
  height: 88rpx;
}

#inputView > input:nth-child(1){
  border-bottom: 1rpx solid #F1F1F1;
}

/* 按钮区域样式 */
#buttonView{
  width: 690rpx;
  margin: 80rpx auto 0;
}

#buttonView > button{
  width: 690rpx;
  height: 88rpx;
  font-size: 36rpx;
}

#buttonView > button:nth-child(1){
  background: #87cefa;
  color: #fff;
}

#buttonView > button:nth-child(2){
  background: #fff;
  color: #87cefa;
  border: 2rpx solid #87cefa;
  margin: 36rpx 0;
}

#buttonView > view{
  font-size: 28rpx;
  color: #87cefa;
  text-align: right;
}

3.8.3 表单数据提交

        什么时候(怎么样)提交数据?
                当点击 form 表单中 form-type 为 submit 的 button 组件时,会将表单组件中的 value 值进行提交,需要在表单组件中加上 name 来作为 key。

        1、给form组件添加bindsubmit事件,在js里面定义对应的事件函数;

        2、给button按钮添加form-type属性,值:submit,提交表单;

        3、在事件函数里面获取要提交的数据;
                3.1 需要给input组件添加name属性;
                3.2 通过事件函数的事件对象获取值;
    
        4、后续我们可以通过API发送请求;

<!-- 定义form组件 -->
<form bindsubmit="toLogin">
  <!-- 输入框区域 -->
  <view id="inputView">
    <!-- 文本框 -->
    <input type="text" placeholder="手机号/用户名" name="userName"></input>
    <!-- 密码框 -->
    <input type="text" placeholder="密码" password name="userPwd"></input>
  </view>

  <!-- 按钮区域 -->
  <view id="buttonView">
    <button form-type="submit">登录</button>
    <button>注册</button>
    <view>忘记密码</view>
  </view>
</form>
// 登录函数
toLogin(e){
    // 获取要提交的用户名和密码,用变量存储
    var userName = e.detail.value.userName;
    var userPwd = e.detail.value.userPwd;
    console.log("要提交给服务器的用户名和密码是:",userName,userPwd);
},

3.9 注册页面

3.9.1 页面实现

        注册页面和登录页面,无非就是换一下组件;

<!-- 定义form组件 -->
<form bindsubmit="toRegister">
  <!-- 输入框区域 -->
  <view id="inputView">
    <!-- 文本框 -->
    <input type="text" placeholder="用户名" name="userName"></input>
    <!-- 密码框 -->
    <input type="text" placeholder="输入6-12位字母、数字组合" password name="userPwd"></input>
    <input type="text" placeholder="确认密码" password name="userPwd1"></input>
    <!-- 昵称 -->
    <input type="text" placeholder="昵称" name="nickName"></input>
    <!-- 真实姓名 -->
    <input type="text" placeholder="真实姓名" name="realName"></input>
    <!-- 手机号 -->
    <input type="number" placeholder="手机号" name="phone"></input>
    <!-- 地址 -->
    <picker mode="region" bindchange="bindRegionChange" value="{
   
   {region}}" custom-item="{
   
   {customItem}}">
      <view class="picker">
        {
   
   {region[0]}} - {
   
   {region[1]}} - {
   
   {region[2]}}
      </view>
    </picker>
  </view>

  <!-- 按钮区域 -->
  <view id="buttonView">
    <button form-type="submit">注册</button>
    <view>已有账号,去登录</view>
  </view>
</form>

/* 给页面设置整体背景色 */
page{
  background: #F0EFF5;
}

/* 输入框区域样式 */
#inputView{
  background: #fff;
  padding: 0 30rpx;
}

#inputView > input{
  height: 88rpx;
  border-bottom: 1rpx solid #F1F1F1;
}

#inputView > picker{
  height: 88rpx;
  line-height: 88rpx;
}

/* 按钮区域样式 */
#buttonView{
  width: 690rpx;
  margin: 80rpx auto 0;
}

#buttonView > button{
  width: 690rpx;
  height: 88rpx;
  font-size: 36rpx;
}

#buttonView > button:nth-child(1){
  background: #87cefa;
  color: #fff;
}

#buttonView > view{
  font-size: 28rpx;
  color: #87cefa;
  text-align: right;
  margin-top: 36rpx;
}
/**
   * 页面的初始数据
   */
  data: {
    region: ['河南省', '郑州市', '中原区'],
    customItem: '全部'
  },
  bindRegionChange: function (e) {
    console.log('picker发送选择改变,携带值为', e.detail.value)
    this.setData({
      region: e.detail.value
    })
  },
  toRegister(e){
    console.log(e)
  },

3.9.2 页面跳转

        1、登录页面,当我们点击tabBar的时候,如果用户没有登录,那么我们跳转到登录页面;目前暂且实现不了,需要结合后面的动态数据来实现登录功能;
    
        2、在登录页面,点击注册,跳转到注册页面;

<button bindtap="toRegPage">注册</button>
toRegPage(){
    wx.navigateTo({
        url: '/pages/register/register',
    })
},

四、数据交互

        实现小程序数据交互,需要对微信小程序概念、代码构成、宿主环境、生命周期等有一定的了解,具体介绍见:深入理解小程序

        实现小程序数据交互,需要掌握微信小程序WXML语法,具体介绍见:WXML语法详解

        实现小程序数据交互,是基于json-server实现的数据mock,json-server环境搭建与使用见:json-server详解

4.1 首页

4.1.1 前置

        把十方智育的图片资源、视频资源等都放在json-server的public目录下面的指定文件夹中;
                public    json-server的静态资源目录
                        images    所有的图片资源
                        audio    所有的音频资源
                        video    所有的视频资源
    
        我们在实际开发中,图片、视频、音频等资源都是放在外部服务器上的,tabBar对应的图片必须是本地图片;因为微信小程序的代码包必须控制在2M以内;

        既然我们的json-server服务器已经搭建完成,那么我们肯定要进行数据交互;我们页面中需要的图片、数据都从json-server中获取;

        注:把除tabBar图片外的所有图片,都放在json-server public文件夹的images文件夹中;

        数据交互三步:
                1、数据定义,在json-server定义所需数据
                2、数据操作,在微信小程序的对应的js文件中,发送请求操作数据(查询/更新/删除/修改)
                3、数据处理,把得到的反馈数据进行对应的处理

        对于页面中无需改变的图片,我们直接在wxml写路径即可,比如:搜索框里面的放大镜;但是对于需要改变的图片,我们最后不要在wxml中直接写路径,而是通过数据的方式引入图片的地址(图片的路径是定义在json-server的data中),比如导航菜单、轮播图;

4.1.2 搜索框图片

        1、搜索框的图片不怎么会改变,我们可以直接写图片路径;
                <image src="http://localhost:3004/images/@2x_find.png"></image>
                上述写法的问题: 如果整个项目中有1000张图片都是这么写的路径,如果将来把存储图片的服务器给换了一个,那么ip地址肯定发生了改变,那么我们需要把1000张图片的路径都改了; 
                代码可维护性太低;
                把ip地址和端口号路径都定义成变量,然后在页面中引入变量即可;将来只需要改变这个变量即可;
                但是这个最好定义成全局的,因为所有的页面都要使用;
    
        2、在app.js的globalData里面定义baseUrl:"http://localhost:3004/"

        3、哪个页面需要用到baseUrl,就在对应的js通过app对象获取得到即可;
                3.1 怎么获取全局唯一app实例? const app = getApp()
                3.2 通过app实例获取得到baseUrl
                3.3 把baseUrl赋值给当前页面的某个变量

app.js代码:

// app.js
App({
  onLaunch (options) {
    // 生命周期回调——监听小程序初始化。
    console.log("监听小程序初始化 - 小程序启动了...");
  },
  onShow (options) {
    // 生命周期回调——监听小程序启动或切前台
    console.log("小程序切换到前台");
  },
  onHide () {
    // 生命周期回调——监听小程序切后台。
    console.log("小程序切换到后台");
  },
  onError (msg) {
    console.log(msg)
  },
  globalData: {
    userInfo: null,
    baseUrl:"http://localhost:3004/"
  }
})

index.js代码:

// 获取应用实例
const app = getApp()

data: {
    baseUrl:"",
}

onLoad() {
	// 获取baseUrl,赋值给当前页面的data里面的baseUrl变量
	var baseUrl = app.globalData.baseUrl;

	// 把获取得到的baseUrl赋值给当前页面的baseUrl
	// this表示当前页面的page对象
	this.setData({
		baseUrl:baseUrl
	})
}

index.wxml代码:

<!-- 顶部搜索框的实现 -->
<view id="searchOuterView">
  <view id="searchInnerView">
    <image src="{
   
   {baseUrl}}images/@2x_find.png"></image>
    <text> 搜索</text>
  </view>
</view>

4.1.3 轮播图

        轮播图是可以点击的,点击跳转到对应的详情页去;轮播图详情页和热门文章的详情页是类似的,我们目前仅使用动态数据,后面我们实现具体的详情展示;

        1、定义轮播图所需的数据;在db.json里面定义news数组,用来存储轮播图所需的数据;
                id                新闻编号
                news_title        新闻标题
                news_info        新闻内容,新闻都是通过PC端的后台来添加的,使用的是富文本,但是富文本微信小程序不识别,后续的课程,会给大家讲解富文本解析;
                image            新闻展示图片
                source            新闻来源
                cjsj            新闻创建时间

"news":[
    {
        "id": "2c9065246df6837f016e8d29c47f0082",
        "news_title": "社会心理服务体系建设试点工作方案",
        "news_info": "略...",
        "image": "images/img1.png",
        "source": "十方智育",
        "cjsj": 1574325884000
    },
    {
        "id": "2c9065246df6837f016e8d2298280081",
        "news_title": "关于加强心理健康服务的指导意见 ",
        "news_info": "略...",
        "image": "images/img2.png",	
        "source": "十方智育",
        "cjsj": 1574325884000
    },
    {
        "id": "2c90652467500e6801685fa5514b0035",
        "news_title": "加强社会心理服务体系建设",
        "news_info": "略...",
        "image": "images/img3.png",
        "source": "十方智育",
        "cjsj": 1547792896000
    }
]

        2、在index.js的onload函数,获取json-server中news的数据(目前news的数据我们指定要了三条,就当成轮播图来用即可,也不用考虑分页了);
        wx.request(Object object)    发起 HTTPS 网络请求。

属性 类型 默认值 必填 说明
url string 开发者服务器接口地址
data string/object/ArrayBuffer 请求的参数
header Object 设置请求的 header,header 中不能设置 Referer。 content-type 默认为 application/json
timeout number 超时时间,单位为毫秒
method string GET HTTP 请求方法
dataType string json 返回的数据格式
responseType string text 响应的数据类型
enableHttp2 boolean false 开启 http2
enableQuic boolean false 开启 quic
enableCache boolean false 开启 cache
enableHttpDNS boolean false 是否开启 HttpDNS 服务。如开启,需要同时填入 httpDNSServiceId 。 HttpDNS 用法详见 移动解析HttpDNS
httpDNSServiceId boolean HttpDNS 服务商 Id 。 HttpDNS 用法详见 移动解析HttpDNS
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

object.method 的合法值

说明 最低版本
OPTIONS HTTP 请求 OPTIONS
GET HTTP 请求 GET
HEAD HTTP 请求 HEAD
POST HTTP 请求 POST
PUT HTTP 请求 PUT
DELETE HTTP 请求 DELETE
TRACE HTTP 请求 TRACE
CONNECT HTTP 请求 CONNECT

        报错信息:
                http://localhost:3004 不在以下 request 合法域名列表中,请参考文档:https://developers.weixin.qq.com/miniprogram/dev/framework/ability/network.html(env: Windows,mp,1.05.2108130; lib: 2.19.5)

        错误解析:
                微信小程序不推荐http,推荐https;我们可以在详情-》本地设置-》不校验合法域名....

        3、把获取的数据展示在index.wxml中,那么就在data中定义news,把获取得到是数据赋值给news;然后在页面中遍历展示即可;
                注:我们只需要res里面的data数据即可;
                this表示当前页面对象,可以在page对象的函数中使用,但是不能在函数的函数中使用;我们可以在当前页面的函数中通过_this变量来存储this值;

index.js代码:

data: {
    ...
    news:"",
    ...    
}
    
onLoad() {
    var _this = this;

    // 获取baseUrl,赋值给当前页面的data里面的baseUrl变量
    var baseUrl = app.globalData.baseUrl;
    /*
      把获取得到的baseUrl赋值给当前页面的baseUrl
      this表示当前页面的page对象
    */
    _this.setData({
        baseUrl:baseUrl
    })

    // 获取得到news的数据
    wx.request({
        url: baseUrl+"news",
        method: "GET",
        header: {
            'content-type': 'application/json'
        },
        success (res) { // res是服务器响应的数据
            _this.setData({
                news: res.data
            })
        }
    })

}

index.wxml代码:

<swiper indicator-dots="{
   
   {indicatorDots}}" indicator-active-color="{
   
   {activeColor}}" autoplay="{
   
   {autoplay}}"
  interval="{
   
   {interval}}" duration="{
   
   {duration}}" circular="{
   
   {circular}}">
  <block wx:for="{
   
   {news}}" wx:key="*this">
    <swiper-item>
      <!-- 跳转路径目前可以空置,后续我们讲解富文本解析的时候,再说 -->
      <navigator open-type="navigate" url="...">
        <image src="{
   
   {baseUrl + item.image}}"></image>
      </navigator>
    </swiper-item>
  </block>
</swiper>

4.1.4 导航菜单

        导航菜单图片可以定义成动态的,因为很多app或pc端网站,在某个节日,比如春节、三八妇女节等都会改变图片的图标,那么我们也通过数据来定义;

        1、定义导航菜单所需的数据;在db.json里面定义navs数组,用来存储导航菜单所需的数据;
                navImg        导航菜单的图片
                navText        导航菜单的文本

"navs":[
    {
        "navImg":"images/@2x_ceping.png",
        "navText":"心理测评"
    },
    {
        "navImg":"images/@2x_yuyue.png",
        "navText":"咨询预约"
    },
    {
        "navImg":"images/@2x_dayi.png",
        "navText":"心理答疑"
    },
    {
        "navImg":"images/@2x_zhishi.png",
        "navText":"心理知识"
    },
    {
        "navImg":"images/@2x_FM.png",
        "navText":"FM"
    },
    {
        "navImg":"images/@2x_gongyi.png",
        "navText":"公益中心"
    }
]

        2、在index.js的onload中请求navs数据,然后复制给data的中navs,然后遍历到index.wxml中;

index.js代码:

data:{
    ...
    navs:"",
    ...    
}

// 获取得到navs的数据
wx.request({
    url: baseUrl+"navs",
    method: "GET",
    header: {
        'content-type': 'application/json'
    },
    success (res) { // res是服务器响应的数据
        _this.setData({
            navs: res.data
        })
    }
})

index.wxml代码:

<!-- 导航菜单 -->
<view id="navView">
  <view class="navItemView" wx:for="{
   
   {navs}}" wx:key="*this">
    <image src="{
   
   {baseUrl + item.navImg}}"></image>
    <text>{
   
   {item.navText}}</text>
  </view>
</view>

4.1.5 在线客服/请求回答

        在线客服和请求回答直接使用图片路径即可;

<!-- 在线客服 -->
<view id="onlineView">
  <image src="{
   
   {baseUrl}}/images/@2x_zixunpeixun.png"></image>
  <text> 咨询助理在线客服</text>
  <!-- 右箭头实现 -->
  <view class="arrow"></view>
</view>

<!-- 请求回答 -->
<view id="askView">
  <image src="{
   
   {baseUrl}}/images/@2x_fudong.png"></image>
</view>

4.1.6 精选文章

        首页的精选文章获取的是访问量前3的数据;

        1、定义精选文章所需的数据;在db.json里面定义hotArticles数组,用来存储精选文章所需的数据;

"hotArticles":[
    {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "失眠—你失控情绪的另一个出口",
        "CJSJ": 1585708931000,
        "ID": "2c9065246e96ad950171339e1a1f07b1",
        "IMAGE": "/images/rmwz01.jpg",
        "INFO": "失眠,已经成为当下许多年轻人的困扰。正如一句网络流行语调侃的那样,许多人的现状就是“也不是不困,就是想再等等……到底等什么呢?不知道,就是想再等等。”失眠造成的困扰不言而喻,有时会伴随着焦虑、抑郁、烦躁等情绪问题。尤其在隔离环境当中,突然没有平日忙碌的工作来填补时间的情况下,那些",
        "pv":9999
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "最易让人生病的八种心理情绪",
        "CJSJ": 1572253623000,
        "ID": "2c9065246df6837f016e119e63b6002a",
        "IMAGE": "/images/rmwz02.jpg",
        "INFO": "  生活中总是伴随着各种情绪,反映着我们的喜怒哀乐。不过丰富的情绪并不是件好事,有时还会影响我们的身心健康。下面是男人常见的八种心理情绪,小心这些情绪也会让你生病!  恶劣情绪NO.1:敌意  这是个讲究TEAMWORK的社会,不能和他人积极合作更容易引发敌意。专家发现:“敌视情",
        "pv":996
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "成人磨牙暗示着心理压力大",
        "CJSJ": 1572253453000,
        "ID": "2c9065246df6837f016e119bccf90029",
        "IMAGE": "/images/rmwz03.jpg",
        "INFO": "在入睡后磨牙,医学上称为“磨牙症”,磨牙症多见于儿童。不过成年磨牙也逐渐增多趋势,据了解,这与成人的心理状况有关,属于潜意识中的心理压力。 磨牙意味潜意识中的压力  口腔生理学与心理学认为,口腔是人体首先兴奋的源点,是与外界交流的渠道,且口腔具有表示紧张、悲观等情绪的功能。当今人",
        "pv":38
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "职场解压的15个心理技巧",
        "CJSJ": 1572253333000,
        "ID": "2c9065246df6837f016e1199f6e80028",
        "IMAGE": "/images/rmwz04.jpg",
        "INFO": "练习日常用来减压的技巧职场人士必须学会用简单方法放松自己,这是能够有效地减轻各种压力所导致的紧张不安的一种重要途径。 下面列出了日常放松自己或者减轻压力的一些简单方法,只要你稍加练习就可以掌握。  1、当面对繁重压力时,小睡一会。打盹被认为是减少和预防压力最有效的办法之一。  2",
        "pv":10
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "从性格判断你的健康状况",
        "CJSJ": 1572253131000,
        "ID": "2c9065246df6837f016e1196e18c0027",
        "IMAGE": "/images/rmwz05.jpg",
        "INFO": "从一个人的性格能判断其健康状况吗?答案是“能”,而且性格还会很大程度上影响到人的健康。健康心理学家表示,人的个性受到遗传基因和生活环境的双重影响。个性基本上可以分为以下八类,同时它们也能分别映射出不同疾病。虽然人们不能绝对对号入座,但它至少能提醒我们身边存在的潜在风险。  1",
        "pv":1088
    }
]

        2、在index.js的onload函数中,获取得到访问量前三的文章,赋值给data里面的hotArticles变量,然后遍历在wxml精选文章列表中;

        3、模版图片展示问题:我们引入模版,不会走模版的js文件,并且引入过来之后,当前页面的baseUrl识别不出来;那么我们可以对获取的数据进行操作,把数据的url拼接上baseUrl;

articleTemplate.wxml代码:

<!-- 文章列表结构模版 -->
<template name="articleTemplate">
  <!-- 一个文章列表结构,肯定对应的是一个对象数据,所以插值表达式在引用数据的时候,使用对象写法 -->
  <!-- 模版中的动态数据,只需要使用对象的key即可 -->
  <view class="articleView">
    <view>
      <image src="{
   
   {IMAGE}}"></image>
    </view>
    <view class="articleContent">
      <view class="articleTitle">
        {
   
   {ARTICLES_TITLE}}
      </view>
      <view class="articleDesc">
        {
   
   {INFO}}
      </view>
    </view>
  </view>
</template>

articleTemplate.wxss代码:

.articleTitle{
  font-size: 28rpx;
  font-weight: bold;
  line-height: 50rpx;
  height: 50rpx;
  /* 超出部分隐藏 */
  overflow: hidden;
  /* 文本不换行 */
  white-space: nowrap;
  /* 多余文本使用省略号替代 */
  text-overflow: ellipsis;
}

.articleDesc{
  font-size: 26rpx;
  color: #A9A9A9;
  line-height: 35rpx;
  height: 70rpx;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  align-content: center;
}

index.js代码:

data:{
    ...
    hotArticles:""
    ...
}

// 获取得到hotArticles的数据
wx.request({
    url: baseUrl+"hotArticles?_sort=pv&_order=desc&_limit=3",
    method: "GET",
    header: {
        'content-type': 'application/json'
    },
    success (res) { // res是服务器响应的数据
        // 把响应过来的数据的IMAGE的路径之前拼接上baseUrl
        for(var i = 0;i < res.data.length;i++){
            res.data[i].IMAGE = baseUrl + res.data[i].IMAGE;
        }

        _this.setData({
            hotArticles: res.data
        })
    }
})

index.wxml代码:

<!-- 文章列表 - 使用模版 -->
<block wx:for="{
   
   {hotArticles}}" wx:for-item="article" wx:key="*this">
    <template is="articleTemplate" data="{
   
   {...article}}"></template>
</block>

4.1.7 报错处理

        控制台会报渲染层错误,加载本地图片失败;但是页面显示正常;

        原因:当渲染层渲染wxml的时候,碰到images/xxx.png,肯定先从根目录的images文件夹中查找,然而images里面并没有这张图片,所以报错;后续加载js里面的data的数据,又从外部服务器获取了图片地址,找到了,就显示图片;这就是为什么控制台会报渲染层错误,加载本地图片失败;但是页面显示正常;

        我们可以把图片也定义成动态的,解决报错信息;

 index.wxml代码:

<!-- 顶部搜索框的实现 -->
<view id="searchOuterView">
  <view id="searchInnerView">
    <image src="{
   
   {baseUrl + findImg}}"></image>
    <text> 搜索</text>
  </view>
</view>

<!-- 在线客服 -->
<view id="onlineView">
  <image src="{
   
   {baseUrl + kefuImg}}"></image>
  <text> 咨询助理在线客服</text>
  <!-- 右箭头实现 -->
  <view class="arrow"></view>
</view>

<!-- 请求回答 -->
<view id="askView">
  <image src="{
   
   {baseUrl + fudongImg}}"></image>
</view>

index.js代码:

data: {
    findImg:"",
    kefuImg:"",
    fudongImg:"",
}

_this.setData({
    baseUrl:baseUrl,
    findImg:"images/@2x_find.png",
    kefuImg:"images/@2x_zixunpeixun.png",
    fudongImg:"images/@2x_fudong.png"
})

4.2 登录页面

4.2.1 数据定义

        登录和注册使用的是一套数据,无非登录是进行了用户数据的查询,注册是用户数据的添加;
                id            用户编号
                userName    用户名
                userPwd        密码
                nickName    昵称
                realName    真实姓名
                integral    积分
                address        地址
                phone        手机号

"users":[
    {
        "id": 1,
        "userName": "zhangsan",
        "userPwd": "123456",
        "nickName": "奔放的三哥",
        "realName": "张三",
        "integral": 100,
        "address": "河南-郑州",
        "phone": 17600000012
    },
    {
        "id": 2,
        "userName": "lisi",
        "userPwd": "123456",
        "nickName": "嚣张的李四",
        "realName": "李四",
        "integral": 960,
        "address": "河南-郑州",
        "phone": 17600000011
    }
]

4.2.2 登录验证

        所谓的登录验证,就是就说从json-server查询是否有对应键值对的用户名和密码;我们之前已经给表单绑定了提交事件,并且在事件函数里面已经获取得到了提交给服务器的用户名和密码;
    
        用户名是唯一的,所以根据用户名和密码查找,如果匹配到了,那么肯定找到的是一条数据(json-server反馈的是一个数组,数组里面是一条数据,只要判定数组长度>0即可);如果错误,没有数据(数组长度为0);

        判断数组的长度,如果大于0,表示登录成功!否则登录失败,登录失败给其弹框提示;
                消息提示框:见下文
        其实有很多种情况,如果没有登录,都需要跳转到登录页面; 比如请求回答,视频收藏,我的页面;
        实际开发的情况: 访问哪个页面,需要登录的,那么登录成功之后,跳转之前的页面;
        但是我们目前不做这种业务了,直接跳转到我的页面

// pages/login/login.js

// 获取应用实例
const app = getApp()

Page({

  /**
   * 页面的初始数据
   */
  data: {
    baseUrl: ""
  },

  // 登录函数
  toLogin(e) {
    var _this = this;

    // 获取要提交的用户名和密码,用变量存储
    var userName = e.detail.value.userName;
    var userPwd = e.detail.value.userPwd;
    console.log("要提交给服务器的用户名和密码是:", userName, userPwd);

    // 根据用户名和密码从json-server服务器查询数据
    wx.request({
      url: _this.data.baseUrl + "users?userName=" + userName + "&userPwd=" + userPwd,
      method: "GET",
      header: {
        'content-type': 'application/json'
      },
      success(res) { // res是服务器响应的数据
        // 判断数组的长度,如果大于0,表示登录成功!否则登录失败,登录失败给其弹框提示
        if (res.data.length > 0) {
          // 其实有很多种情况,都需要跳转到登录页面; 比如请求回答,视频收藏,我的页面;
          // 实际开发的情况: 访问哪个页面,需要登录的,那么登录成功之后,跳转之前的页面;
          // 但是我们目前不做这种业务了,直接跳转到我的页面
          wx.switchTab({
            url: '/pages/my/my',
          })
        } else {
          wx.showToast({
            title: '用户名或密码错误!',
            icon: 'none',
            duration: 1500
          })
        }
      }
    })

  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 获取baseUrl
    var _this = this;
    var baseUrl = app.globalData.baseUrl;
    _this.setData({
      baseUrl: baseUrl
    })

  }
  ....
})

4.2.3 消息提示框

        wx.showToast(Object object)        显示消息提示框

Object object参数

属性 类型 默认值 必填 说明 最低版本
title string 提示的内容
icon string success 图标
image string 自定义图标的本地路径,image 的优先级高于 icon 1.1.0
duration number 1500 提示的延迟时间
mask boolean false 是否显示透明蒙层,防止触摸穿透
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

object.icon 的合法值

说明 最低版本
success 显示成功图标,此时 title 文本最多显示 7 个汉字长度
error 显示失败图标,此时 title 文本最多显示 7 个汉字长度
loading 显示加载图标,此时 title 文本最多显示 7 个汉字长度
none 不显示图标,此时 title 文本最多可显示两行,1.9.0及以上版本支持

4.2.4 本地缓存

        我们在使用app的时候,经常会输入账号和密码,下次打开,之前输入的账号和密码会显示在输入框中;那么想要实现该功能,需要使用本地缓存;

存储用户名和密码

        把输入的用户名和密码放在本地缓存;
        wx.setStorage(Object object)    将数据存储在本地缓存中指定的 key 中。会覆盖掉原来该 key 对应的内容。除非用户主动删除或因存储空间原因被系统清理,否则数据都一直可用。单个 key 允许存储的最大数据长度为 1MB,所有数据存储上限为 10MB。
        wx.setStorageSync(string key, any data)        wx.setStorage 的同步版本
        
        同步:按照顺序执行;
            1 -> 2 -> 3
        异步:同时执行;
            1 ->
            2 ->
            3 ->
        我们存储数据到本地缓存,使用wx.setStorage(Object object);

// 登录函数
toLogin(e) {
    var _this = this;

    // 获取要提交的用户名和密码,用变量存储
    ...

    // 只要输入了用户名和密码,都缓存在本地缓存
    // 如果不存在该key,那么就是创建;如果存在该key,那么就是更新
    wx.setStorage({
        // 本地缓存的key
        key: "loginUserInfo",
        data: {
            userName: userName,
            userPwd: userPwd
        }
    })

    // 根据用户名和密码从json-server服务器查询数据
    ...
},

获取用户名和密码

        在onload函数中获取本地缓存数据,然后把缓存的用户名和密码显示到输入框中;
                wx.getStorage(Object object)        从本地缓存中异步获取指定 key 的内容。
                wx.getStorageSync(string key)        wx.getStorage 的同步版本
        
                我们获取缓存数据,使用wx.getStorageSync(string key);

login.js代码:

/**
   * 生命周期函数--监听页面加载
   */
onLoad: function (options) {
    // 获取baseUrl
    var _this = this;

    // 获取本地缓存数据
    wx.getStorage({
        key: 'loginUserInfo',
        success(res) {
            console.log("onload函数中,从本地缓存获取得到的数据:",res.data)
            // 把本次缓存获取得到的数据放到data里面
            _this.setData({
                loginUserInfo:res.data
            })
        }
    })

},

login.wxml代码:

<!-- 输入框区域 -->
<view id="inputView">
    <!-- 文本框 -->
    <input type="text" placeholder="手机号/用户名" name="userName" value="{
   
   {loginUserInfo.userName}}"></input>
<!-- 密码框 -->
<input type="text" placeholder="密码" password name="userPwd" value="{
   
   {loginUserInfo.userPwd}}"></input>
</view>

4.2.5 登录状态保存

        在项目中,很多页面都是需要登录之后才能访问,比如:我的页面,请求回答页面,咨询客服页面,收藏课程页面等,但是如果已经登录,那么这些页面还需要跳转登录页面;
    
        那么我们登录成功之后,肯定要保存登录状态,让其他页面知道已经登录成功了;那么登录状态数据肯定要全局唯一实例App中,可以在app.js的globalData的userInfo中存储登录用户的数据;
        如果没有登录,那么userInfo是null,如果登录,把登录成功的用户的信息赋值给userInfo,那么userInfo就不为null,那么我们就可以通过判定userInfo来考量是否登录;

app.js代码:

// app.js
App({
  // 略
  globalData: {
    userInfo: null,
    baseUrl:"http://localhost:3004/"
  }
})

login.js代码:

if (res.data.length > 0) {
    // 把登录成功的用户数据放到globalData的userInfo中
    console.log(res.data);
    app.globalData.userInfo = res.data[0];

    // 其实有很多种情况,都需要跳转到登录页面; 比如请求回答,视频收藏,我的页面;
    // 略
} else {
   ...
}

4.3 我的页面

        1、如果用户没有登录,那么跳转到登录页面;如果已经登录,则进入我的页面;

        2、在我的页面,展示用户的动态信息;

my.js代码:

// pages/my/my.js

// 获取应用实例
const app = getApp()

Page({

  /**
   * 页面的初始数据
   */
  data: {
    userInfo:""
  },

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

    // 判断用户是否登录,就是判断app.globalData.userInfo是否为null
    var userInfo = app.globalData.userInfo;
    if(userInfo == null){
      // 如果userInfo为null,没有登录
      wx.redirectTo({
        url: '/pages/login/login',
      })
    }else{
      // 如果不为null,表示已经登录
      _this.setData({
        userInfo:userInfo
      })
    }
  },

})

my.wxml代码:

<!-- 用户信息展示区域 -->
<view id="userInfoView">
  <view>昵称: {
   
   {userInfo.nickName}}</view>
  <view>来自: {
   
   {userInfo.address}}</view>
  <view>积分: {
   
   {userInfo.integral}}</view>
</view>

4.4 注册页面

        关于注册,我们不对数据进行校验了,大家在填写数据的时候,尽量避免已经存在的用户名;

        我们在前静态页面阶段,已经绑定了提交事件,并且可以通过事件对象,获取得到表单提交的数据;
        表单提交过来的数据要和json-server里面的数据格式保持一致;
                缺少:
                        id:id不需要写,json-server会自动给我们创建id;
                        integral:积分我们自己添加,刚注册的用户,我们给其定义0;
                        address:address的值在picker对应的数组;
                多余:
                        userPwd1:正常来说,需要userPwd和userPwd1保持一致;但是我们不做校验,直接删除userPwd1即可;

        我们把数据整理好之后,发送给json-server,如果数据添加成功,则表示注册成功;注册成功去登录页面,注册失败,提示;

register.js代码:

// pages/register/register.js
// 获取应用实例
const app = getApp()

Page({

  /**
   * 页面的初始数据
   */
  data: {
    baseUrl: "",
    region: ['河南省', '郑州市', '中原区'],
    customItem: '全部'
  },
  bindRegionChange: function (e) {
    console.log('picker发送选择改变,携带值为', e.detail.value)
    this.setData({
      region: e.detail.value
    })
  },
  toRegister(e){
    var _this = this;
    
    // 要提交给服务器的数据
    var submitData = e.detail.value;
    // 删除userPwd
    delete submitData.userPwd1;
    // 添加integral
    submitData.integral = 0;
    // 添加address,把region数组转换为字符串
    submitData.address = _this.data.region.join("-");

    // 把数据添加json-server
    wx.request({
      url: _this.data.baseUrl + "users",
      method: "POST",
      header: {
        'content-type': 'application/json'
      },
      data:submitData,
      success(res) { // res是服务器响应的数据
        if(res.data){ // 注册成功
            wx.navigateTo({
              url: '/pages/login/login',
            })
        }else{
          wx.showToast({
            title: '注册失败!',
            icon: 'none',
            duration: 1500
          })
        }
      }
    })
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 获取baseUrl
    var _this = this;
    var baseUrl = app.globalData.baseUrl;
    _this.setData({
      baseUrl: baseUrl
    })
  },
})

4.5 精选文章列表页

4.5.1 数据定义

        精选文章页面的数据结构之前我们已经定义过了,在首页的精选文章部分,之前我们只定义了5条,现在无非弄多一点数据而已,因为我们要做上提加载(分页);

    怎么获取数据?
                1、进入官网,访问对应的页面,比如精选文章:    
                        https://www.hnsfxlzx.com/sf/p/view/article/rmwz
        
                2、打开浏览器控制台(谷歌浏览器->右键->检查),NetWork,刷新页面,在控制台搜索框里面搜索page,一般都是要使用的数据;点击路径,右侧Response,复制数据;

                3、通过https://www.sojson.com/页面,格式化json;从中拿需要的数据;

"hotArticles": [
    {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "失眠—你失控情绪的另一个出口",
        "CJSJ": 1585708931000,
        "ID": "2c9065246e96ad950171339e1a1f07b1",
        "IMAGE": "/images/rmwz01.jpg",
        "INFO": "失眠,已经成为当下许多年轻人的困扰。正如一句网络流行语调侃的那样,许多人的现状就是“也不是不困,就是想再等等……到底等什么呢?不知道,就是想再等等。”失眠造成的困扰不言而喻,有时会伴随着焦虑、抑郁、烦躁等情绪问题。尤其在隔离环境当中,突然没有平日忙碌的工作来填补时间的情况下,那些",
        "pv": 9999
    },
    {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "最易让人生病的八种心理情绪",
        "CJSJ": 1572253623000,
        "ID": "2c9065246df6837f016e119e63b6002a",
        "IMAGE": "/images/rmwz02.jpg",
        "INFO": "  生活中总是伴随着各种情绪,反映着我们的喜怒哀乐。不过丰富的情绪并不是件好事,有时还会影响我们的身心健康。下面是男人常见的八种心理情绪,小心这些情绪也会让你生病!  恶劣情绪NO.1:敌意  这是个讲究TEAMWORK的社会,不能和他人积极合作更容易引发敌意。专家发现:“敌视情",
        "pv": 996
    },
    {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "成人磨牙暗示着心理压力大",
        "CJSJ": 1572253453000,
        "ID": "2c9065246df6837f016e119bccf90029",
        "IMAGE": "/images/rmwz03.jpg",
        "INFO": "在入睡后磨牙,医学上称为“磨牙症”,磨牙症多见于儿童。不过成年磨牙也逐渐增多趋势,据了解,这与成人的心理状况有关,属于潜意识中的心理压力。 磨牙意味潜意识中的压力  口腔生理学与心理学认为,口腔是人体首先兴奋的源点,是与外界交流的渠道,且口腔具有表示紧张、悲观等情绪的功能。当今人",
        "pv": 38
    },
    {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "职场解压的15个心理技巧",
        "CJSJ": 1572253333000,
        "ID": "2c9065246df6837f016e1199f6e80028",
        "IMAGE": "/images/rmwz04.jpg",
        "INFO": "练习日常用来减压的技巧职场人士必须学会用简单方法放松自己,这是能够有效地减轻各种压力所导致的紧张不安的一种重要途径。 下面列出了日常放松自己或者减轻压力的一些简单方法,只要你稍加练习就可以掌握。  1、当面对繁重压力时,小睡一会。打盹被认为是减少和预防压力最有效的办法之一。  2",
        "pv": 10
    },
    {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "从性格判断你的健康状况",
        "CJSJ": 1572253131000,
        "ID": "2c9065246df6837f016e1196e18c0027",
        "IMAGE": "/images/rmwz05.jpg",
        "INFO": "从一个人的性格能判断其健康状况吗?答案是“能”,而且性格还会很大程度上影响到人的健康。健康心理学家表示,人的个性受到遗传基因和生活环境的双重影响。个性基本上可以分为以下八类,同时它们也能分别映射出不同疾病。虽然人们不能绝对对号入座,但它至少能提醒我们身边存在的潜在风险。  1",
        "pv": 1088
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "这个救赎,因校园霸凌而起",
        "CJSJ": 1547801589000,
        "ID": "2c90652467500e6801686029f76b006e",
        "IMAGE": "/images/rmwz06.jpg",
        "INFO": "继《你的名字》之后,日本又出现了一个现象级的动漫电影---《声之形》。《你的名字》讲述关于爱情的缘分与奇妙,《声之形》则引起对友谊和成长的人性思考。 这是一个有关于听觉障碍的少女和曾经伤害过她的少年石田将也的成长故事。 作为小学转校生的女主角西宫硝子来到了男主角石田将也的班上,由"
        ,"pv": 1188
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "张韶涵从落魄走向开挂:所谓自由,就是被人讨厌",
        "CJSJ": 1547801545000,
        "ID": "2c90652467500e68016860294c97006d",
        "IMAGE": "/images/rmwz07.jpg",
        "INFO": "前几天看了一本书《被讨厌的勇气》,关于阿德勒的个体心理学,看完以后感触颇多。 书的副标题是:“所谓的自由,就是被人讨厌”。像裴多菲说的那样:生命诚可贵,爱情价更高,若为自由故,两者皆可抛,这个时代的每个人更是都在捶胸顿足的渴望着自由。 他们是上学的孩子、上班的职员、已婚的父母、有"
        ,"pv": 18
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "在你不知道的时候,你已经被美食毒害了",
        "CJSJ": 1547801504000,
        "ID": "2c90652467500e6801686028ac13006c",
        "IMAGE": "/images/rmwz08.jpg",
        "INFO": "是不是有点奇怪,为什么你会一直吃零食,根本管不住自己的嘴?实际上,你可能是能管住自己的。但是我想你一定已经看过了电视纪录片里讲的有些人管不住自己的嘴,哪怕他们已经胖得没法出门,仍然无法控制自己。为什么会这样?他们就是所谓的食物成瘾者?或者说这些食物成瘾者没有足够的意志力?你是怎么"
        ,"pv": 112
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "原生家庭的苦,怎样才能不白受?",
        "CJSJ": 1547801446000,
        "ID": "2c90652467500e6801686027ca0c006b",
        "IMAGE": "/images/rmwz09.jpg",
        "INFO": "培养安全依恋需要父母的热情、稳定和心理健康,那么,被原生家庭伤害过的人能不能培养安全依恋的孩子呢? -01-“妈妈酗酒、爸爸躁郁症,但我没有疯” 丽的妈妈酗酒,爸爸有躁郁症,她从来无法确定每天家中会是什么状态,也许妈妈会暴跳如雷,爸爸会拒绝服药,一会忧郁、一会躁狂。 但是,丽并没"
        ,"pv": 96
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "优秀的你,是不是个优秀的家长",
        "CJSJ": 1547801396000,
        "ID": "2c90652467500e680168602705c8006a",
        "IMAGE": "/images/rmwz10.jpg",
        "INFO": "在怎么教养孩子这方面,没有人可以给出来标准答案。每个孩子都不一样,做的少了怕不够,做得多了怕太过。 之前有一个朋友问我:是不是所有的父母都是爱他们的孩子的? 我告诉他,是的,确实所有的父母都爱他们的孩子,但不是所有的父母都是无条件爱孩子的。会有家长说:你要学习好,有才艺,要听话…"
        ,"pv": 168
    },
    {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "永不消失的爱",
        "CJSJ": 1547801366000,
        "ID": "2c90652467500e68016860268e210069",
        "IMAGE": "/images/rmwz11.jpg",
        "INFO": "听一个女孩儿讲她与父母的事,我却觉得,我们每个人的父母也是如此。 如果你觉得岁月静好,那一定是有人为你负重前行。 01 在我还没有开始工作的时候,我总觉得我是家里最累的那个人——每天都在上课,走的最早,回的最晚,在家还要写作业到半夜。我理所当然的觉得家里的事情就应该是父母在操心,"
        ,"pv": 54
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "抑郁症与抑郁情绪",
        "CJSJ": 1547801334000,
        "ID": "2c90652467500e680168602612d80068",
        "IMAGE": "/images/rmwz12.jpg",
        "INFO": "什么是抑郁症? 抑郁症是一种常见的精神疾病,主要表现为情绪低落,兴趣减低,悲观,思维迟缓,缺乏主动性,自责自罪,饮食、睡眠差,担心自己患有各种疾病,感到全身多处不适,严重者可出现自杀念头和行为。主要表现为:心境低落主要表现为显著而持久的情感低落,抑郁悲观。轻者闷闷不乐、无愉快感、"
        ,"pv": 99
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "研究生被导师压迫跳楼:“人际弱势者”如何自救?",
        "CJSJ": 1547801295000,
        "ID": "2c90652467500e68016860257c490067",
        "IMAGE": "/images/rmwz13.jpg",
        "INFO": "这两天看到一条新闻:武汉理工大学,研三的学生陶崇园,长期受到其导师的精神压迫。在长期的压力之下,陶崇园最终不堪重负,选择了跳楼自杀。看到这个新闻我非常的痛心。为陶崇园在重负之下选择终结自己的生命,感到非常的惋惜。但陶崇园绝非个例,这世上还有不知多少如陶崇园一样的人,在承受着来自别"
        ,"pv": 9
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "心理咨询的作用之一——在情绪中存活",
        "CJSJ": 1547801256000,
        "ID": "2c90652467500e6801686024e1dd0066",
        "IMAGE": "/images/rmwz14.jpg",
        "INFO": "当我们意外的掉入一条河里,这时候我们可能会先让自己浮出水面,深呼吸让自己镇定下来,观察下周围最近的岸边,是否需要喊人帮忙……有读者会说了,这种情况是基于你会游泳,没错。如果你在水里处在一个沉溺淹没的状态,我们根本不可能做出更多思考,以及采取对自己最有利的选择。 有时候我们甚至都没"
        ,"pv": 20
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "心理史上最大骗局:“星座测试太准啦!”",
        "CJSJ": 1547801193000,
        "ID": "2c90652467500e6801686023ec1c0065",
        "IMAGE": "/images/rmwz15.jpg",
        "INFO": "-01- “他要和我分手,嫌弃我是个处女!”He Broke Up With Me Coz I'm a Virgin话说,电视剧《龙门镖局》里有个四处留情的风流男子 —— 恭叔。这一天,镖局来了个恭叔的前女友 —— 露露。镖局的小伙伴们都在八卦:“你和恭叔当初是为啥分手哒?”下面"
        ,"pv": 618
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "小心!微表情泄露了你的秘密",
        "CJSJ": 1547801105000,
        "ID": "2c90652467500e680168602295500064",
        "IMAGE": "/images/rmwz16.jpg",
        "INFO": "小心!微表情泄露了你的秘密当下,随着许许多多影视资源的问世,越来越多的人将目光投向了心理学中的微表情。在众多影视剧中,微表情表现得神秘、莫测,仿佛掌握了微表情就征服了全世界。很多人慢慢开始崇拜掌握着这一技之长的人。那么,什么是微表情?你对微表情究竟了解多少?下面,就让我们一起走进"
        ,"pv": 982
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "我们为什么说脏话",
        "CJSJ": 1547800979000,
        "ID": "2c90652467500e6801686020a8020063",
        "IMAGE": "/images/rmwz17.jpg",
        "INFO": "这是一篇脏话百科全书,不谢,我也知道今天我巨他妈好看! 脏话,一种神奇的语言系统你能想象,一个没有脏话的世界,将如何生存吗?反正我不能。脏话,现在已经成为中国语言中非常发达的一项语言分支,它可以用来简化语言,规避歧义,提高语言效率。比如,“这个解释他妈的不清楚”和“这个他妈的解释"
        ,"pv": 138
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "为什么上班都是坐着,还会感觉疲惫不堪?",
        "CJSJ": 1547800887000,
        "ID": "2c90652467500e680168601f41010062",
        "IMAGE": "/images/rmwz18.jpg",
        "INFO": "有很多人上班疲惫回家之后就躺在沙发上休息看电视或者玩手机;在午后或者下午三四点之后分心注意力难以集中接着就走出去抽一口烟又或者刷刷微信放松一下,这些方式都无法解除大脑的疲劳。所以这一次跟焦糖Pan选择了这本日本畅销榜上的《最高休息法》,用正确的方式让大脑得到休息。如果大脑得到休息"
        ,"pv": 962
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "为什么你记不住别人的名字",
        "CJSJ": 1547800736000,
        "ID": "2c90652467500e680168601cf49c0061",
        "IMAGE": "/images/rmwz19.jpg",
        "INFO": "我们经常在聚会或是会议上听到别人说:“我擅长记人的脸,但是记不住人的名字。”这种常见的说法正确吗?现在,让我们开始一场关于记忆心理的旅程。我要告诉你,我们关于脸部、名字的记忆,并不像它看起来的那么简单。人类确实是识别面孔的专家。我们中的大都数人都能识别出成千上万张的脸,一切都是这"
        ,"pv": 28
    }, {
        "SOURCE": "十方智育",
        "ARTICLES_TITLE": "完美主义与自杀风险 ▎无法满足的期望与标准",
        "CJSJ": 1547800627000,
        "ID": "2c90652467500e680168601b4aba0060",
        "IMAGE": "/images/rmwz20.jpg",
        "INFO": "根据世界卫生组织(WHO)的统计,每45秒就有一个人自杀。为了防止悲剧发生,我们需要了解更多影响某些个体容易产生自杀想法以及自杀行为的因素。其中一个风险因素就是完美主义:一种强迫自己时刻达到超过自身能力标准的倾向或/和满足或超越他人过高期望的自我需要。 1995年,心理学家Sid"
        ,"pv": 118
    }	
]

4.5.2 获取所有的数据

hotArticle.wxml代码:

<!-- 引入模版 -->
<import src="/pages/template/articleTemplate/articleTemplate.wxml"></import>

<!-- 文章列表区域 -->
<view id="hotArticleView">
    <!-- 文章列表 - 使用模版 -->
    <block wx:for="{
   
   {hotArticles}}" wx:for-item="article" wx:key="*this">
        <template is="articleTemplate" data="{
   
   {...article}}"></template>
    </block>
</view>

<!-- 正在加载 -->
<view id="loadingView">
    <image src="{
   
   {baseUrl + lodingImg}}"></image>
    <text> 正在加载更多数据</text>
</view>

<!-- 最后一页 -->

hotArticle.js代码:

// pages/hotArticle/hotArticle.js
// 获取应用实例
const app = getApp()
Page({

    /**
   * 页面的初始数据
   */
    data: {
        baseUrl: "",
        hotArticles: "",
        lodingImg:""
    },

    /**
   * 生命周期函数--监听页面加载
   */
    onLoad: function (options) {
        // 获取baseUrl,赋值给当前页面的data里面的baseUrl变量
        var _this = this;
        var baseUrl = app.globalData.baseUrl;
        _this.setData({
            baseUrl: baseUrl,
            lodingImg:"/images/loading.gif"
        })

        // 获取所有文章
        wx.request({
            url: baseUrl + "hotArticles",
            method: "GET",
            header: {
                'content-type': 'application/json'
            },
            success(res) { // res是服务器响应的数据
                // 把响应过来的数据的IMAGE的路径之前拼接上baseUrl
                for (var i = 0; i < res.data.length; i++) {
                    res.data[i].IMAGE = baseUrl + res.data[i].IMAGE;
                }
                _this.setData({
                    hotArticles: res.data
                })
            }
        })

    },
})

hotArticle.wxss代码:

/* 引入模版所需样式 */
@import '/pages/template/articleTemplate/articleTemplate.wxss';


/* 文章列表区域*/
#hotArticleView{
    padding: 0 22rpx;
}

/* 正在加载样式 */

#loadingView{
    text-align: center;
    height: 88rpx;
    background: #F0EFF5;
    line-height: 88rpx;
}

#loadingView > image{
    width: 48rpx;
    height: 48rpx;
    vertical-align: middle;
}

#loadingView > text{
    font-size: 28rpx;
    vertical-align: middle;
}

4.5.3 上提加载

        1、打开精选文章页面,我们要显示一部分数据;假定打开精选文章页面,我们要先显示8条数据;无非就是向后台发送请求,获取文章的前8条数据;_page=1&_limit=8

        2、在上提加载函数里面,发送请求去获取第x页的数据(上提加载的时候,要查询的_page要动态改变),但是我们获取的数据是要累加的,而不是覆盖;怎么实现:在hotArticles的基础上进行数据的追加

// pages/hotArticle/hotArticle.js
// 获取应用实例
const app = getApp()
Page({

    /**
   * 页面的初始数据
   */
    data: {
        baseUrl: "",
        hotArticles: [],
        lodingImg:"",
        // pageNum变量: 要请求的页码
        pageNum: 1
    },

    /**
   * 生命周期函数--监听页面加载
   */
    onLoad: function (options) {
        // 获取baseUrl,赋值给当前页面的data里面的baseUrl变量
        var _this = this;
        var baseUrl = app.globalData.baseUrl;
        _this.setData({
            baseUrl: baseUrl,
            lodingImg:"/images/loading.gif"
        })

        // 肯定不能一次性获取所有文章,应该是初始显示部分数据,上提的时候再加载更多数据
        // 显示第一页的数据
        wx.request({
            url: baseUrl + "hotArticles?_page="+_this.data.pageNum+"&_limit=8",
            method: "GET",
            header: {
                'content-type': 'application/json'
            },
            success(res) { // res是服务器响应的数据
                console.log("第"+_this.data.pageNum+"页的数据:",res.data);

                // 把响应过来的数据的IMAGE的路径之前拼接上baseUrl
                for (var i = 0; i < res.data.length; i++) {
                    res.data[i].IMAGE = baseUrl + res.data[i].IMAGE;
                }
                _this.setData({
                    hotArticles: _this.data.hotArticles.concat(res.data)
                })
            }
        })

    },

    /**
   * 页面上拉触底事件的处理函数
   */
    onReachBottom: function () {
        var _this = this;
        var baseUrl = _this.data.baseUrl;

        // 每次上提,原有的页码+1,pageNum + 1
        _this.setData({
            pageNum: _this.data.pageNum + 1
        })

        wx.request({
            url: baseUrl + "hotArticles?_page="+_this.data.pageNum+"&_limit=8",
            method: "GET",
            header: {
                'content-type': 'application/json'
            },
            success(res) { // res是服务器响应的数据
                console.log("第"+_this.data.pageNum+"页的数据:",res.data);

                // 把响应过来的数据的IMAGE的路径之前拼接上baseUrl
                for (var i = 0; i < res.data.length; i++) {
                    res.data[i].IMAGE = baseUrl + res.data[i].IMAGE;
                }
                _this.setData({
                    hotArticles: _this.data.hotArticles.concat(res.data)
                })
            }
        })
    },
})

        3、代码重用性;

// 封装请求数据的代码,提高代码复用性
// getData里面需要this对象,那么我们通过that参数传递进来
function getData(that){
    // 通过参数that获取baseUrl和pageNum
    var baseUrl = that.data.baseUrl;
    var pageNum = that.data.pageNum;

    wx.request({
        url: baseUrl + "hotArticles?_page="+pageNum+"&_limit=8",
        method: "GET",
        header: {
            'content-type': 'application/json'
        },
        success(res) { // res是服务器响应的数据
            console.log("第"+pageNum+"页的数据:",res.data);

            // 把响应过来的数据的IMAGE的路径之前拼接上baseUrl
            for (var i = 0; i < res.data.length; i++) {
                res.data[i].IMAGE = baseUrl + res.data[i].IMAGE;
            }
            that.setData({
                hotArticles: that.data.hotArticles.concat(res.data)
            })
        }
    })
}

// 在onload 和 onReachBottom分别调用getData(this)

        4、最下面:友好的提示

        需求:
                1、如果服务器还没有反馈回来数据,提示:正在加载更多数据...
                2、如果没有更多数据,提示:已经是最后一页啦!

        实现:
                1、默认情况下,正在加载数据...和已经是最后一页啦!,都是隐藏起来的;

                2、上提的时候,向服务器获取数据,让正在加载数据...显示,数据返回了,让正在加载数据...隐藏;

                3、如果没有数据了,那么显示已经是最后一页啦! 先获取得到总数量,当我们每次请求的时候,判断data里面的hotArticles是否和总数量相等,如果相等,则不再发送请求获取数据,显示最后一页;

                注:在实际开发环境里面,后台会把总数量和当前页的数据都封装给你,但是在json-server里面,必须得发送请求单独获取总数量;

<!-- 正在加载 -->
<view id="loadingView" wx:if="{
   
   {isLoading}}">
    <image src="{
   
   {baseUrl + lodingImg}}"></image>
    <text> 正在加载更多数据</text>
</view>

<!-- 最后一页 -->
<view id="loadingView" wx:if="{
   
   {noData}}">
    已经是最后一页啦!
</view>
// pages/hotArticle/hotArticle.js
// 获取应用实例
const app = getApp()

// 封装请求数据的代码,提高代码复用性
// getData里面需要this对象,那么我们通过that参数传递进来
function getData(that){
    // 通过参数that获取baseUrl和pageNum
    var baseUrl = that.data.baseUrl;
    var pageNum = that.data.pageNum;
    // 获取总数量
    var count = that.data.count;

    // 判断是否到最后一页
    if(count == that.data.hotArticles.length){
        that.setData({
            isLoading: false,
            noData: true
        })
    }else{
        wx.request({
            url: baseUrl + "hotArticles?_page="+pageNum+"&_limit=8",
            method: "GET",
            header: {
                'content-type': 'application/json'
            },
            success(res) { // res是服务器响应的数据
                console.log("第"+pageNum+"页的数据:",res.data);

                // 把响应过来的数据的IMAGE的路径之前拼接上baseUrl
                for (var i = 0; i < res.data.length; i++) {
                    res.data[i].IMAGE = baseUrl + res.data[i].IMAGE;
                }
                that.setData({
                    hotArticles: that.data.hotArticles.concat(res.data),
                    isLoading: false
                })
            }
        })
    }
}

Page({

    /**
   * 页面的初始数据
   */
    data: {
        baseUrl: "",
        hotArticles: [],
        lodingImg:"",
        // pageNum变量: 要请求的页码
        pageNum: 1,
        isLoading:false,
        noData:false,
        count:""
    },

    /**
   * 生命周期函数--监听页面加载
   */
    onLoad: function (options) {
        // 获取baseUrl,赋值给当前页面的data里面的baseUrl变量
        var _this = this;
        var baseUrl = app.globalData.baseUrl;
        _this.setData({
            baseUrl: baseUrl,
            lodingImg:"/images/loading.gif"
        })

        // 肯定不能一次性获取所有文章,应该是初始显示部分数据,上提的时候再加载更多数据
        // 获取总数量: 获取所有文章,通过数组长度得到总数量;
        wx.request({
            url: baseUrl + "hotArticles",
            method: "GET",
            header: {
                'content-type': 'application/json'
            },
            success(res) { // res是服务器响应的数据
                _this.setData({
                    count: res.data.length
                })

                // 显示第一页的数据
                getData(_this);
            }
        })

    },

    /**
   * 页面上拉触底事件的处理函数
   */
    onReachBottom: function () {
        var _this = this;

        // 每次上提,原有的页码+1,pageNum + 1
        _this.setData({
            pageNum: _this.data.pageNum + 1,
            isLoading: true
        })

        getData(this);
    },
})

4.5.4 下拉刷新

        1、本页面开启下拉刷新;

{
  "usingComponents": {},
  "navigationBarTitleText": "精选文章",
  "enablePullDownRefresh":true
}

        2、每次下拉页面,都会触发onPullDownRefresh函数,在onPullDownRefresh函数进行数据重置即可;

/**
   * 页面相关事件处理函数--监听用户下拉动作
   */
onPullDownRefresh: function () {
    var _this = this;
    // 正常情况下,需要重新获取一次count,但是我们这里就不写
    _this.setData({
        hotArticles: [],
        pageNum: 1,
        isLoading:false,
        noData:false
    })

    // 获取第一页的数据
    getData(_this);
},

4.6 文章详情页

4.6.1 页面传参和数据获取

        文章详情页只有一个页面,里面的数据都是动态获取的,根据点击文章列表的id来获取对应的数据;

        1、定义文章详情页,在app.json里面定义

"pages/articleDetail/articleDetail",

        2、当我们点击文章列表的时候,跳转到文章详情页,并且把文章的id传递到文章详情页

<template name="articleTemplate">
    <navigator class="articleView" url="/pages/articleDetail/articleDetail?id={
   
   {ID}}" open-type="navigate">
        <view>
            <image src="{
   
   {IMAGE}}"></image>
        </view>
        <view class="articleContent">
            <view class="articleTitle">
                {
   
   {ARTICLES_TITLE}}
            </view>
            <view class="articleDesc">
                {
   
   {INFO}}
            </view>
        </view>
    </navigator>
</template>

        3、在文章详情页获取到传递过来的id值;

        4、根据id值去后台查询数据,查询得到的数据给data里面的articleDetail

        https://www.hnsfxlzx.com/www/article/get/获取得到的id值

onLoad: function (options) {
    var _this = this;
    // 获取文章详情
    wx.request({
        url: 'https://www.hnsfxlzx.com/www/article/get/'+options.id,
        header: {
            'content-type': 'application/json' // 默认值
        },
        success: function (res) {
            console.log(res);
            _this.setData({
                articleDetail:res.data.page
            })
        }
    })
},
<!--pages/articleDetail/articleDetail.wxml-->
<view class="articleTitle">
    {
   
   {articleDetail.articles_title}}
</view>
<view class="articleAuthor">
    来源:{
   
   {articleDetail.source}}
</view>
<view class="articleImg">
    <image src="https://www.hnsfxlzx.com/{
   
   {articleDetail.image}}"></image>
</view>
<view>
    {
   
   {articleDetail.articles_info}}
</view>
/* pages/articleDetail/articleDetail.wxss */
page{
    padding: 0 20rpx;
}

.articleTitle{
    height: 88rpx;
    line-height: 88rpx;
    font-size: 30rpx;
    font-weight: bold;
}

.articleAuthor{
    font-size: 26rpx;
    color: #A8A8A8;
    line-height: 36rpx;
}

.articleImg{
    text-align: center;
    margin: 20rpx 0;
}

4.6.2 富文本解析

        1、把富文本解析成微信小程序可以识别的代码,使用wxParse插件解析;

        参考文档:

小程序 wxParse解析后端传过来的富文本内容https://blog.csdn.net/weixin_42065713/article/details/95043631

wx.parse解析富文本html转wxml https://www.cnblogs.com/xiaoxiaoxun/p/12465053.html

        我们使用的时候,..目录结构要少写一层;

<!--pages/articleDetail/articleDetail.wxml-->
<import src="../../wxParse/wxParse.wxml"/> 

<view class="articleContent">
    <template is="wxParse" data="{
   
   {wxParseData:content.nodes}}" />
</view>
var WxParse = require('../../wxParse/wxParse.js');

success: function (res) {
    console.log(res.data.page);
    // WxParse.wxParse(bindName , type, data, target,imagePadding)
    // * 1.bindName绑定的数据名(必填),解析成功之后的内容绑定到该数据名上;
    // * 2.type可以为html或者md(必填)
    // * 3.data为传入的具体数据(必填)
    // * 4.target为Page对象,一般为this(必填)
    // * 5.imagePadding为当图片自适应是左右的单一padding(默认为0,可选)
    let result = res.data.page;
    WxParse.wxParse('content', 'html', result.articles_info, _this, 5);
    _this.setData({
        articleDetail:res.data.page
    })
}

        2、字体大小处理

@import "../../wxParse/wxParse.wxss";

.articleContent{
  width: 710rpx;
}

.wxParse-span{
  font-size: 24rpx!important;
  color: #353535!important;
}

.wxParse-p{
  line-height: 48rpx!important;
}

分集教程目录

环境搭建篇:

01_从零构建微信小程序项目_项目概述

02_从零构建微信小程序项目_项目环境搭建

静态页面篇:

03_从零构建微信小程序项目_首页静态效果实现

04_从零构建微信小程序项目_咨询页面静态效果实现

05_从零构建微信小程序项目_课程页面静态效果实现

06_从零构建微信小程序项目_我的页面静态效果实现

07_从零构建微信小程序项目_精选文章页面静态效果实现

08_从零构建微信小程序项目_关于我们页面静态效果实现

09_从零构建微信小程序项目_咨询师详情页静态效果实现

10_从零构建微信小程序项目_登录页面静态效果实现

11_从零构建微信小程序项目_注册页面静态效果实现

数据交互篇:

12_从零构建微信小程序项目_数据交互_深入理解小程序

13_从零构建微信小程序项目_数据交互_WXML语法详解

14_从零构建微信小程序项目_数据交互_json-server详解

15_从零构建微信小程序项目_数据交互_首页

16_从零构建微信小程序项目_数据交互_登录和注册

17_从零构建微信小程序项目_数据交互_精选文章列表(涵盖:上提加载和下拉刷新)

18_从零构建微信小程序项目_数据交互_文章详情页(涵盖:多页面传参和富文本解析)

b站视频直通车

2021年最新微信小程序项目实战教程,从入门到精通,零基础入门小程序开发【配置素材+源码+笔记】_哔哩哔哩_bilibili

猜你喜欢

转载自blog.csdn.net/ligonglanyuan/article/details/120669474
今日推荐