Psychological counseling_WeChat mini program project actual combat, including: annotation diagram, effect diagram, video, source code

1. Project overview

1.1 Tutorial Guide

        This set of tutorials is project-oriented, and builds a complete set of WeChat applet projects from scratch, from static page implementation, to background data mock service construction, and finally front-back and back-end data interaction.

        This set of tutorials is a simulation of the online WeChat applet application: Realization of Shifang Zhiyu.

        If you need materials, codes, and videos related to this set of tutorials, you can private message me or leave an email in the comment area.

1.2 Suitable for the crowd

        There is a certain HTML/CSS/JavaScript foundation, no need to be proficient.

       Students with a certain foundation can follow the tutorial documents to gradually realize the project; this set of tutorials is also suitable for students with zero foundation. In the supporting video, the explanation is given in a zero-basic way.

1.3 Project renderings

front page

 consultation page

course page

my page

 Article List Page

 Consultant details page 

log in page

registration page

1.4 Supporting information

renderings

Annotated map

cutout material

Video explanation

2. Project environment construction

2.1 Download and installation of development tools

        1. Download the WeChat developer tools:
                https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html
        2. Download the tool corresponding to the operating system version;

        3. Installation precautions:
                During the learning process, you will install various tools;
                3.1 Try to avoid Chinese directories, but domestic development tools can actually appear in Chinese directories;
                3.2 Try to avoid spaces, special symbols (_not Summarized into special symbols);
                3.3 Try to avoid installing on the C drive. If there are many disks, you can use a disk to install the software. If there are few disks, then define a folder and install the software specially; 4. Installation steps 4.1 Double-click
    
        wechat_devtools_1
                . 05.2108130_x64.exe to install
                4.2 Enter the installation wizard interface, directly click Next
                4.3 Enter the license agreement interface, click I accept
                4.4 Select the installation directory (refer to 3), my installation directory: D:\Tools\WeChat web developer tools , click Install
                4.5 Wait for the installation to complete, click Finish

2.2 Account registration

        1. You must have a WeChat account. You need to log in through WeChat to use the WeChat developer tools;

        2. You must have a Mini Program account, and finally the Mini Program account must be bound to the WeChat user; after binding, your WeChat account is the administrator of the Mini Program;

        3. One WeChat account can bind many WeChat Mini Programs;

        4. Application address: https://mp.weixin.qq.com/cgi-bin/wx?token=&lang=zh_CN
                4.1 Click the Go to Registration button at the bottom of the page
                4.2 You need an email address as a login account, you can use QQ, 126, 163, Yahoo, etc.;
                    apply for a 126 mailbox;
                4.3 Account information: fill in the account number, password, verification code and other information, and an activation link will be sent to the mailbox;
                4.4 Email activation: go to the mailbox to activate;
                4.5 Information registration:
                        registration country/ Region: Mainland China
                        Subject type: Personal
                        subject information registration: ID card name, ID card number, administrator mobile phone number, etc.
                4.6 After the submission is completed, click to go to the applet in the pop-up;

2.3 Project Construction

        1. Double-click the WeChat developer tool icon on the desktop. For the first use, you need to scan the code to log in through your WeChat account;

        2. On the left: select Mini Program Item -> Mini Program

        3. On the right side: click the + sign to create a WeChat applet;

        4. Options for creating applets:
                Project name: sfzy
                directory: D:\WeChatProjects\sfzy
                AppID: Paste the AppID we just registered;
                        Left menu: Development Management -> Development Settings -> Find the AppID
                development mode: Small program
                backend service: Cloud service
                language: JavaScript
    
        5. Click OK to create a WeChat small program project. After all WeChat applets are created, they will come with some demo codes;

2.4 Developer Tool Interface Introduction

2.4.1 Three major regions

        Simulator area: Simulate the real machine environment, the basic effect of our code on different mobile phones; you can select the model, percentage, font size, etc. in the upper left corner; model:
                mainly depends on the resolution; rather than having to find the corresponding Manufacturer's brand; if you are really tangled, you can customize it;
                display ratio: it allows us to see the effect more completely;
                font size: don't change it, 16 is enough;
                note: when developing WeChat applets, the model recommendation is to choose iphone6 /7/8

        Editor area: project structure directory and edit code;
                contains two parts: resource manager and editor;
                resource manager: project directory structure

        Debugger area: code debugging;

2.4.2 Menu bar

        1. Avatar: used to switch the login user;

        2. Simulator, editor, debugger: three buttons, used to open or close the three major areas

        3. Compilation mode: You can switch the compilation mode.
                Normally compile the project home page that is opened by default;
                click the compile drop-down menu and select Add Compilation Mode.
                        Mode name: custom, Chinese can appear;
                        start page: select the page corresponding to the mode;
                        click OK;

        4. Compile button: Manual compilation;

        5. Preview button: A QR code appears, scan the code through WeChat, and you can view the effect on the mobile phone;

        6. Real machine debugging: preview on the mobile phone, and check the real feedback through the debugging platform;

        7. Clear cache: clear cache data

        8. Upload: upload the code to the WeChat applet server

        9. Details: Contains the basic information settings of the applet

3. Implementation of static pages

3.1 Home page

3.1.1 Navigation bar and tabBar

Introduction to global configuration

        The implementation of the navigation bar and tabBar in the WeChat applet is realized through configuration; this is different from the development of the mobile terminal;

        Reference document: https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
        
        The configuration of the mini program is divided into three parts:
                Global configuration: Global configuration of the WeChat mini program, it is the whole Viewport (visual window) setting;
                page configuration: configure the window performance of this page.
                sitemap configuration: configuration of indexing rules for WeChat applets.

        The app.json file in the root directory of the Mini Program is used to configure the WeChat Mini Program globally. The file content is a JSON object with the following properties:

entryPagePath

        Specify the default startup path (homepage) of the applet. The common scenario is to start from the WeChat chat list page, start the applet list, and so on. If left blank, it will default to  pages the first item in the list. Parameters with page path are not supported.

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

pages

        It is used to specify which pages the applet consists of, and each item corresponds to the path (including file name) information of a page. The file name does not need to write the file suffix, the framework will automatically find the four files of  .json.js.wxml,  corresponding to the location .wxss for processing.

        When not specified  entryPagePath , the first item of the array represents the initial page (home page) of the applet.

        Adding/removing pages in the applet requires modifying the pages array.

        Define four tabBar pages:

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

window

        It is used to set the status bar, navigation bar, title, and window background color of the applet.

Attributes type Defaults describe minimum version
navigationBarBackgroundColor HexColor #000000 Navigation bar background color, such as #000000
navigationBarTextStyle string white Navigation bar title color, only supports  black / white
navigationBarTitleText string Navigation bar title text content
navigationStyle string default Navigation bar style, only supports the following values:
default default style
custom custom navigation bar, only the capsule button in the upper right corner is reserved. See note 2.
iOS/Android WeChat client 6.6.0, Windows WeChat client does not support
backgroundColor HexColor #ffffff background color of the window
backgroundTextStyle string dark The style of drop-down loading, only supports  dark / light
backgroundColorTop string #ffffff The background color of the top window, only supported by iOS WeChat client 6.5.16
backgroundColorBottom string #ffffff The background color of the bottom window, only supported by iOS WeChat client 6.5.16
enablePullDownRefresh boolean false Whether to enable global pull-down refresh.
onReachBottomDistance number 50 The distance from the bottom of the page when the page pull bottom event is triggered, in px.
pageOrientation string portrait Screen rotation settings,   support  auto // portraitlandscape
  • Note 1: HexColor (hexadecimal color value), such as "#ff00ff"
  • Note 2: AboutnavigationStyle
    • iOS/Android client versions below 7.0.0 are navigationStyle only  app.json valid in .
    • Starting from iOS/Android client version 6.7.2, navigationStyle: custom it is invalid for web-view components
    • After enabling custom, low-version clients need to be compatible. The version of the developer tool base library is switched to 1.7.0 (does not represent the minimum version, it is only for debugging) to easily switch to the old visual
    • For Windows client 3.0 and above, in order to provide users with a more desktop software experience, the navigation bar of the applet window is unified and navigationStyle: custom no longer takes effect

        The global window configuration is as follows:

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

tabBar

        If the applet is a multi-tab application (there is a tab bar at the bottom or top of the client window to switch pages), you can specify the performance of the tab bar and the corresponding page displayed when the tab is switched through the tabBar configuration item.

Attributes type required Defaults describe minimum version
color HexColor yes The default color of the text on the tab, only supports hexadecimal color
selectedColor HexColor yes The color when the text on the tab is selected, only supports hexadecimal color
backgroundColor HexColor yes The background color of the tab, only supports hexadecimal color
borderStyle string no black The color of the upper border of the tabbar, only supports  black / white
list Array yes The list of tabs, see  list the property description for details, at least 2 and at most 5 tabs
position string no bottom The position of the tabBar, only supports  bottom / top
custom boolean no false Customize tabBar, see details

Among them, list accepts an array, and only a minimum of 2 tabs and a maximum of 5 tabs can be configured . The tabs are sorted in the order of the array, each item is an object, and its property values ​​are as follows:

Attributes type required illustrate
pagePath string yes Page path, must be defined first in pages
text string yes button text on the tab
iconPath string no Image path, the icon size is limited to 40kb, the recommended size is 81px * 81px, network images are not supported.
When  position is top , the icon is not displayed.
selectedIconPath string no The image path when selected, the icon size is limited to 40kb, the recommended size is 81px * 81px, and network images are not supported.
When  position is top , the icon is not displayed.

TabBar is configured as follows:

{
  "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"
      }
    ]
  }
}

full configuration

{
  "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"
}

Delete the built-in logs page

        1. Delete the logs path configuration in pages in the app.json file under the root directory of the applet;
        2. Delete the logs directory;

3.1.2 Search box

        Combining the effect diagram and the annotation diagram, we can analyze and draw a conclusion: the search box area is composed of two containers; an
                outer container and an inner container;
                the outer container wraps the inner container; and the inner container is just in the center of the outer container (horizontal vertical center) position

        A page of the WeChat applet corresponds to four files, js file, json file, wxml file, wxss file wxml file ->
                html file
                wxss file -> css file
                js file -> js file
                json file -> configuration file
                        app.json Global configuration file
                        index/my/course/..json file Page configuration file

page structure

        1. Delete the demo code in index.wxml;

        2. Define two nested views in the index.wxml file. The characteristics of the layout container: the width occupies 100% of the viewport, but the height follows the content;
                in the WeChat applet, the view is used to define the layout container; The content is defined in the view;

        3. Introduce pictures and text in the internal view;
                in the WeChat applet, define the picture using the image component; import pictures through the src attribute of the image component;
                in the WeChat applet, define some text, you can use the text component;
    
        4. After having the structure, the effect does not meet our expectations, then we need to add decoration; to add decoration, we need to distinguish different elements, then we can add the id attribute to the component.

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

style implementation

        The style of the WeChat applet is written in the corresponding wxss file;
        
        1. Delete the demo style code in index.wxss;

        2. The search image is too large, so we can set the size of the image;
                find the image through searchInnerView
                #searchInnerView > image -> select the id as the image component in the searchInnerView component
                and mark the pt in the image, and the unit used in the WeChat applet is rpx;
                1pt = 1px = 2rpx;
    
        3. Set the size and color of the search text;
                add a space before the search text to make a little space between the picture and the text;

        4. The picture and text are centered, and the content is centered for searchInnerView;

        5. Set the width, height, background color, border, and rounded corners for searchInnerView;
    
        6. The picture and text are vertically and horizontally centered and aligned;    
                6.1 Set the line height for the text in searchInnerView
                6.2 Set the vertical alignment for the picture and text respectively

        7. Set
                the inner margin for searchOuterView Inner margin: the distance between the border and the content;

/* 顶部搜索框样式 */
#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 Carousel image

page structure

        The carousel map of the WeChat applet is particularly simple to implement, because WeChat provides us with a carousel map component;
        swiper component documentation: https://developers.weixin.qq.com/miniprogram/dev/component/swiper.html
    
        1 , Copy the relevant code of the swiper component from the wxml at the bottom of the swiper component document;

        2. Copy the data data from JavaScript at the bottom of the swiper component document and put it in the data of index.js;
                delete the original data data in index.js;

        3. Change the view in swiper-item to image, because each slider displays a picture;

        4. The swiper-item is defined in the syntax of the block wx:for. wx:for is the data in the referenced js. If there are several corresponding array values ​​in the data, several swiper-items will be generated; 4.1
                wx : The value of the for reference is changed to imgUrls, which is to see the name and meaning
                4.2 Write the path of the image to be used in the imgUrls array
                4.3 Introduce the corresponding image path in the image component
    
        5. Set the automatic carousel through swiper related attributes, Carousel interval, carousel direction, etc.;
                indicator-dots whether to display panel indicator
                indicator-active-color indicator-active-color currently selected indicator point color
                autoplay whether to automatically switch
                interval automatic switch time interval duration
                sliding animation duration
                circular whether to use joint sliding

<!-- 轮播图 -->
<!-- 
  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
  },

style implementation

        1. The annotation map defines the height of the carousel image area as 160pt, but in actual development, in order to show better results, we adjusted it higher, so we use 200pt for the height; set the height for the swiper; 2. Set the width for the
    
        picture ,high;

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

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

3.1.4 Navigation menu

page structure

        By analyzing the annotation map, we concluded that a large view contains 6 small views, and each small view contains a picture and text;

        1. Define a view to carry all navigation menus, and define id for it: navView

        2. Define 6 sub-views in navView, and define class for them: navItemView

        3. Define image and text in each navItemView;

<!-- 导航菜单 -->
<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>

style implementation

        In the WeChat applet, all images are given the specified width and height by default;

        1. Set width and height for all pictures in navItemView;

        2. Set the width for navItemView, the width
                is the same as the width of the picture, and set the text to be centered; the feature of the view component is that it occupies a single line, and the width and height are set in time;
    
        3. There are many ways to make navItemView not occupy a single line, but on the mobile side More is to use flex layout;
        flex layout tutorial: http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
                3.1 Apply flex layout to navView, after adopting flex layout, all child elements They will be arranged in one line;
                3.2 Set the wrapping display for navView;
                3.3 Set the left and right spacing for navItemView, which we call outer margin;
                3.4 Set the height for navView.
                3.5 Set the alignment of multiple axes for 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 Online customer service

        Philosophy: Do not add meaningless components or labels;

        Add an overall gray background color to the page, then add a white background to the necessary components;

page structure

        1. Define a view to carry online customer service related content, and define id for it: onlineView
    
        2. Define pictures and text in onlineView;

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

style implementation

        1. Set the width and height of the pictures in onlineView;

        2. Set the height, background color, upper and lower outer margins, left and right inner margins, and set line height for onlineView;

        3. Set the font size and bold font for the onlineView text;
                24pt on the design drawing is a bit problematic, we only need 26rpx;
                remember to change the font in the navigation menu to 26rpx bold;

        4. Alignment of pictures and text;

right arrow implemented

        Realization of the right arrow: a square, define the upper border and the right border, rotate 45 degrees, and then place it in the specified position by positioning;

        Set position: absolute for the arrow element; Use absolute positioning, which is relative to the parent element, provided that the parent element must have a positioning attribute.
        Set position: relative for #onlineView; Let the parent element have a positioning attribute;

/* 在线客服样式 */
#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 Featured Articles

page structure

        1. Define the view, which is used to carry the title of the article, list of all articles, and view more; add id to it: hotArticleView

        2. Define the view, which is used to carry the general title of the article, and add id to it: hotArticleTitleView

        3. Define three views to carry three selected article lists. These three views have the same effect, the difference is that the pictures and text are different; add class to these three views: articleView 4. In
    
        articleView Divided into left and right parts
                4.1 Define two sub-views in articleView; the left side carries pictures, and the right side carries text; add class: articleContent to the view on the right;
                4.2 Divide articleContent into upper and lower parts, define two sub-views, and add class: articleTitle respectively , articleDesc;

        5. Define the view, which is used to indicate viewing more, and add id to it: moreView
                defines the text and right arrow in this 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>

 style implementation

        1. Add left and right inner margins and background colors to hotArticleView;

        2. Set the height, font size and font thickness for hotArticleTitleView; lower border and line height;

        3. Set the size of the picture in articleView;

        4. Apply flex layout, upper and lower inner margins, and lower borders to articleView;

        5. Set the right margin for the pictures in the articleView;

        6. Set the text size, color, and line height for the article title and description on the right;
                set the article title to 28rpx;

        7. Set height, line height and relative positioning for moreView;

        8. Set the size and color of the text in moreView;

        9. Add a lower margin to 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 Request for Answer

page structure

        Define a view, add id to it: askView, and define a picture in it;

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

style implementation

        1. Set the size of the picture

        2. Add fixed positioning to askView (no matter how the content of the page is scrolled, the elements are consistent in the specified position of the window), and set the corresponding position;

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

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

3.2 Consultation page

3.2.1 Page title

        We have made a global configuration in app.json before, and set the title to Shifang Zhiyu;

        Now the title of the consultation appointment page is not Shifang Zhiyu, so we can override the global configuration through page configuration;
    
        page configuration: https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/page.html

        Each applet page can also use the .json file to configure the window performance of this page. The configuration items in the page will overwrite the same configuration items in the window of app.json in the current page. The file content is a JSON object with the following properties:

        We have told you about all the configuration items in the page configuration in the global configuration.

        Note: In order to facilitate viewing the effect of the written page, we can add a compilation mode;

        Configure the page title in consult.json;

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

3.2.2 Filter box

page structure

        1. Define a view and add id: filterView to it;

        2. Define pictures and text in filterView;

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

style implementation

        1. Set the size of the picture in filterView;

        2. Set the size and font color of the text in filterView;

        3. Set the text centering, height, background color, and row height for filterView;

        4. Set the vertical alignment for the pictures and text in 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 List of consultants

page structure

        1. Define a view and give it an id: consultListView, which is used to host all consultants;

        2. Define a view in consultListView, and define class: consultView for it;

        3. Define two views in consultView, the left view is used to carry pictures, and the right view is used to carry consultant information, define class: consultInfoView for it, we put consultant information in three sub-views;
                The structure of a consultant is realized, and the rest can be copied and pasted;
                when combining data in the future, in fact, only one view structure is needed, because the view is used in the loop, and as many views as there are data;

    
        Selector: used to select page elements and add styles to them;
                #xx selects elements according to id;
                .yy selects elements according to class;
                zz selects elements according to component name
                parent element > child element selects all child elements of the parent element parent element
                child element selection All descendant elements of the parent element
                parent element > child element:nth-child(num) select the numth child element of the parent element

<!-- 咨询师列表 -->
<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>

style implementation

        1. Set left and right inner margins for consultListView;
    
        2. Set upper and lower inner margins, lower borders, and flex layout for consultView;
    
        3. Set size and right outer margin for pictures in consultView;
    
        4. Set three sub-elements in consultInfoView, Set text size, thickness, color, line height respectively;

/* 咨询师列表样式 */
#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 Loading

page structure

        1. Define the view and add id to it: loadingView
    
        2. Just define the picture and text in loadingView;
    
        Note: The loading area should be used in combination with dynamic data. When we get data from the background, but the data has not yet been obtained , display loadingView, if you get the data, so loadingView;

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

style implementation

        1. Set the size of the picture in loadingView;

        2. Set the size of the text in loadingView;

        3. Set text centering, height, background color, line height for loadingView;

        4. Set the vertical alignment for the pictures and text in the 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 Course page

3.3.1 Page Title and Search Box

        The page title is also implemented through page configuration;
    
        if the search box does not consider code reuse, then directly copy and paste the relevant structure and style from the code on the homepage;

3.3.2 Mini Navigation

page structure

        1. Define a view and give it an id: smallNavView;

        2. Define three sub-views in smallNavView

        3. The sub-views can carry the corresponding pictures and texts respectively;

<!-- 小导航 -->
<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>

style implementation

        1. Set the size of all the pictures in smallNavView;
    
        2. Set the font size and color of the text in smallNavView;

        3. Set the background color, height, and row height for the view in smallNavView;

        4. Set the vertical alignment for the text and pictures in the smallNavView;

        5. Set a flex layout for smallNavView; scale up the subview of smallNavView by 1;

        6. Set the text center for the subview of smallNavView

        7. For the second subview of smallNavView, set the left and right borders;

/* 小导航样式实现 */
/* 应用了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 Carousel image

        Just copy and paste the relevant structure and style from the home page, and then modify the image resources;

<!-- 轮播图 -->
<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 Popular courses

page structure

        1. Define a view and add id to it: hotCourseView
    
        2. Define hotCourseTitleView in hotCourseView to carry the general title
    
        3. Define courseListView in hotCourseView to carry four courses, each course is a view, add class to it : courseView
    
        4. Just define pictures and text in 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>

style implementation

        1. Set the left and right inner margins for hotCourseView;

        2. Set the height, text size, bold, text center, line height for hotCourseTitleView;

        3. Set the size of all pictures in courseListView;

        4. Set the width of courseView to be consistent with the picture;

        5. Set the flex layout, line break, and alignment of items on the main axis for courseListView;

        6. Set the lower margin and center the text for 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 My Page

3.4.1 User Information Display

page structure

        1. Define a view and give it an id: userInfoView;

        2. Define three sub-views in userInfoView, which are used to carry nicknames, where they come from, and points respectively;

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

style implementation

        1. Set the background color, top and bottom padding, and text centering for userInfoView; the
                representation of different values ​​of padding:
                * Up, down, left, and right padding
                ** Up, down, left and right padding
                *** Top, left, right, and bottom padding Distance
                **** Top, right, bottom, left padding (clockwise)
                Note: The style set for the content of the parent element can be inherited by the child elements; for example: font color, font size, text centering;

        2. Set the size and color of the text of the three sub-views;

        3. Set the upper and lower margins or inner margins for the second subview;

/* 用户信息展示样式 */
#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 Personal center list items

page structure

         1. Define a view and add class: userItemListView to it;

        2. Define the corresponding number of sub-views in userItemListView;

        3. Define the corresponding text and arrows in each subview;

<!-- 用户列表选项 -->
<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>

style implementation

        1. Set the overall background color for the page;

        2. Set the background color, left and right inner margins, and upper and lower outer margins for userItemListView;

        3. Set the height, row height, bottom border, and relative positioning for the subviews in userItemListView;

        4. Set the size and thickness of the text;

        5. Set the arrow style;

        Note: Merge of vertical outer margins; when two outer margins are stacked vertically, it is not accumulated, but the larger of the two is the main one;

/* 用户列表选项样式 */
.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 Featured Articles Page

3.5.1 Preface

        At present, we have realized 4 pages, which are the home page, consultation page, course page, and my page; we can jump to these four pages through the tabBar, and these four pages are what we call the tabBar page ;
    
        For non-tabBar pages, how to jump? For example: the featured article page we are going to write now is redirected by clicking View More in the featured article area on the homepage; how to realize the jump is the focus of our discussion in this section;

        The featured article page is no longer difficult for everyone;

3.5.2 Article list

page structure

          1. Define pages/hotArticle/hotArticle in the pages configuration of app.json;

        2. Add compilation mode to the hotArticle page, otherwise the effect cannot be viewed;

        3. Define a view and add id to it: hotArticleView;

        4. Add 6 sub-views to hotArticleView, the structure is similar to the selected articles on the homepage; add class: articleView to the 6 ziviews; and then take responsibility for the relevant structure of the homepage; Note: Although we can copy the structure from the homepage
        ,
                but Obviously there is a lot of redundancy in the code; we will explain the template to you later;
                you don’t need to worry too much about the text content in it, because we will cover it with real data in the future;

<!-- 文章列表区域 -->
<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>

style implementation

        1. Set the left and right inner margins for hotArticleView;

        2. Assign the relevant styles of articleView and its sub-elements from index.css;

/* 文章列表区域*/
#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 Loading

        Similar to the consultation appointment page, just copy the corresponding code;

3.5.4 Page Jump

        When we click on the home page - wonderful articles - view more, jump to the featured article page;

Component jump method

        Component jump mode, similar to hyperlinks in html;

        The component mode depends on the navigator component, and the navigator component is a page link.
    
        Component documentation: https://developers.weixin.qq.com/miniprogram/dev/component/navigator.html

        This component has a lot of data, but we only need to use a few commonly used ones, and you can refer to the documentation for others;

        When we click on each area of ​​the page to achieve jumps, we generally use component jumps;

Attributes type Defaults required illustrate
target string self no On which target to jump, the default is the current applet
url string no The jump link in the current applet
open-type string navigate no jump side

 Legal values ​​for target

value illustrate
self current applet
miniprogram other applets

Legal values ​​for open-type

value illustrate
navigate Corresponding to the function of wx.navigateTo or wx.navigateToMiniProgram , keep the current page and jump to a certain page in the application. But can not jump to the tabbar page.
redirect Corresponding to the function of wx.redirectTo , close the current page and jump to a page in the application. But jumping to the tabbar page is not allowed.
switchTab Corresponding to the function of wx.switchTab , jump to the tabBar page and close all other non-tabBar pages
reLaunch Function corresponding to 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插件解析;

        参考文档:

The small program wxParse parses the rich text content from the backend https://blog.csdn.net/weixin_42065713/article/details/95043631

wx.parse parses rich text html to wxml  https://www.cnblogs.com/xiaoxiaoxun/p/12465053.html

        When we use it, the directory structure needs to be written one less layer;

<!--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. Font size processing

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

.articleContent{
  width: 710rpx;
}

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

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

Diversity tutorial directory

Environment construction articles:

01_Building a WeChat Mini Program Project from Scratch_Project Overview

02_Building WeChat Mini Program Project from Scratch_Project Environment Construction

Static page articles:

03_Building a WeChat Mini Program Project from Scratch_Homepage static effect realization

04_Building a WeChat Mini Program Project from Scratch_Realization of Static Effects on Consulting Pages

05_Building a WeChat Mini Program Project from Scratch_Realization of Static Effects on Course Pages

06_Building a WeChat Mini Program Project from Scratch_Static effect realization of my page

07_Building a WeChat Mini Program Project from Scratch_Implementation of Static Effects on Featured Article Pages

08_Building a WeChat applet project from scratch_About us page static effect realization

09_Building a WeChat Mini Program Project from Scratch_Realization of Static Effects on Consultant Details Page

10_Building a WeChat Mini Program Project from Scratch_Implementation of Static Effects on the Login Page

11_Building a WeChat Mini Program Project from Scratch_Implementation of Static Effects on the Registration Page

Data interaction articles:

12_Building a WeChat Mini Program Project from Scratch_Data Interaction_In-depth Understanding of Mini Programs

13_Building a WeChat Mini Program Project from Scratch_Data Interaction_WXML Syntax Detailed Explanation

14_Building WeChat applet project from scratch_data interaction_json-server detailed explanation

15_Building a WeChat Mini Program Project from Scratch_Data Interaction_Home

16_Building a WeChat Mini Program Project from Scratch_Data Interaction_Login and Registration

17_Building a WeChat Mini Program Project from Scratch_Data Interaction_List of Selected Articles (covering: Uplift Loading and Pulldown Refresh)

18_Building WeChat Mini Program Project from Scratch_Data Interaction_Article Details Page (covering: multi-page parameter passing and rich text analysis)

B station video train

The latest WeChat mini-program project practical tutorial in 2021, from entry to proficiency, zero-based entry mini-program development [configuration material + source code + notes]_哔哩哔哩_bilibili

Guess you like

Origin blog.csdn.net/ligonglanyuan/article/details/120669474