微信小程序入门(一)
项目结构解读
我们发现,页面页面一般有4个文件组成
每个文件的功能
xxx.js(index.js)文件
该文件完成业务逻辑的书写。
xxx.json(index.json)
该文件用来进行一些页面的配置。有些时候我们不需要书写样式等代码,而是在json文件里面进行一定的配置,就可以达到我们想要的效果。比如:我们修改一下顶部导航栏的颜色,就可以在JSON文件里面配置。这种配置机制在我们前端的开发中不常见。
xxx.wxml(index.wxml)
该文件用来书写页面的骨架。类似于html。
xxx.wxss(index.wxss)
该文件用来书写页面的样式。类似于css。
总结
其实,这四个文件并不都是必须都要存在的,比如我们的页面每页样式,那么wxss文件就不是必须的。所以说,除了页面的骨架wxml,其他文件都不是必须的。
文件约定
如果我们这个页面的四个文件的名称相同(后缀不同),都是index.后缀的文件,那么我们文件之间的相互调用是不需要进行导入的。而是可以直接使用其他文件的内容。
综上所述:我们建立一个新的页面最好也采用这种约定速成的方式。
文档结构解读
文件app.js,app.json,app.wxss这三个文件的名称是不能修改的。作用和上面相同文件类型的作用一样。但是这三个文件可以控制整个微信小程序(也就是应用程序级别的)的样式和业务逻辑等。而上面介绍的文件只能控制所属的页面。
虽然这三个文件配置的样式等是全局的,但是如果配置的全局样式和局部样式有冲突,以页面的局部样式为主。
文件project.config.json是用来记录当前项目的配置,设置的。
sitemap.json是来做微信小程序搜索的。暂时不做了解。
小程序入门
删除项目结构
首先我们删除项目中的其他文件,只保留 project.config.json,sitemap.json这两个文件
小程序页面的搭建技巧和规则
当我们删除项目结构,只保留这两个文件以后,发现在调试区域会报错。提醒我们没有app.json文件。
上面我们说过,app.json文件是在微信小程序开发项目中,必须存在的文件。
新建app.json
- 新建json文件以后,会提醒我们json文件不能为空
- 写一个空的花括号以后,会报错提醒我们,必须有pages属性,且pages属性必须为数组。(页面肯定不止一个,注意:json文件里面不可写注释。小程序的页面只有在app.json里面注册以后才能被访问。)
-
有该属性后,一样报错。很明显,找不到页面。
-
新建页面,新建pages文件夹,在下面再建index文件夹。我们知道了每个页面都有四个文件,但是我们需要一个个新建吗?不需要的。只需要邮件单击index文件夹,然后点新建page,填写文件名称即可,不需要写后缀,自动帮我们建好四个文件。且在app.json文件的pages属性里面完成了页面的注册。
**注意:页面文件只需要写index,小程序会默认帮我们找到名称为index的四个文件。**且小程序的默认首页就是第一个注册的页面。
例如,我们在新建一个welcome页面,并将其第一个注册,放在index页面前面,发现默认页面就是welcome了
小程序必备语法
1. 如何显示一张图片
**我们指知道,在html中,可以使用img标签来显示图片,在小程序中,我们使用的是<image></image>**标签。使用src属性引用图片。
2. 文本
使用<text></text>标签包裹我们想要显示的文字。
3. 按钮
和html一样,都是使用<button></button>标签
我们发现:这个头像是椭圆形的,而实际上我们的头像图片是圆形的。为什么默认情况变成的椭圆形?思考一下
单位rpx
我们在微信小程序里面,设置样式的时候,推荐使用rpx单位,而不是px单位。
因为:单位:rpx 会自适应屏幕的尺寸等,给我们一种很舒服的视觉体验,换了机型会自适应大小。而使用px为单位,就会固定死大小,即使切换了机型,分辨率发生了改变,大小也不会改变。
<!-- 1. 显示图片的标签 -->
<!-- 可以使用相对路径,也可以使用绝对路径 -->
<!-- 单位:rpx 会自适应屏幕的尺寸等,给我们一种很舒服的视觉体验,换了机型会自适应大小 -->
<image src="/images/avatar/1.webp" style="width:220rpx;height:220rpx"></image>
<!-- 2. 显示文本的标签 -->
<text>你好:听雨少年!</text>
<!-- 直接书写文本,也可以正常显示,但是我们建议还是使用text标签进行包裹,遵守规范,而且没有标签包裹,我们也难以设置样式 -->
<!-- 我也直接显示了! -->
<!-- 按钮标签 -->
<button>我是按钮</button>
当然,你也可以选择使用px为单位,但是我们需要在设置大小的时候,将数值设置为图片实际大小的1/2。这是建立在以iPhone6机型为原型图的基础上。
回到开始的问题:头像在默认情况下为什么变成椭圆形或者不是我们图片默认的形状?
因为:image标签(组件)有默认样式
图片建议使用png格式!!!
完成第一个页面布局
配置小程序导航头部样式
我们觉得这种默认的样式很难看,可以在app.json文件里面配置这个头部的样式
"window": {
"navigationBarBackgroundColor": "#b3d4db"
},
页面样式
页面样式代码
<!--pages/welcome/welcome.wxml-->
<!-- 使用view标签,作为最外层容器,包裹所有标签,view不是有具体含义的标签 -->
<view class="container">
<!-- 1. 显示图片的标签 -->
<!-- 可以使用相对路径,也可以使用绝对路径 -->
<image class="user-avatar" src="/images/avatar/avatar.png"></image>
<!-- 2. 显示文本的标签 -->
<text class="motto">听雨少年</text>
<!-- 直接书写文本,也可以正常显示,但是我们建议还是使用text标签进行包裹,遵守规范,而且没有标签包裹,我们也难以设置样式 -->
<!-- 我也直接显示了! -->
<!-- 按钮标签 -->
<!-- 官方的提供的按钮我们一般不推荐使用,因为样式等问题很难修正 -->
<!-- <button>我是按钮</button> -->
<!-- 这里使用view模拟一个button组件 -->
<view class="btn-journey-container">
<!-- 设置样式模拟出我们喜欢的按钮样式 -->
<text class="journey">开启小程序之旅</text>
</view>
</view>
/* pages/welcome/welcome.wxss */
/* 单位:rpx 会自适应屏幕的尺寸等,给我们一种很舒服的视觉体验,换了机型 会自适应大小 */
/* 顶层容器page,设置背景色 */
page {
background-color: #b3d4db;
}
/* 外层容器 */
.container {
/* 开启弹性布局 */
display: flex;
/* 排列方向,垂直排列 */
flex-direction: column;
/* 在排列方向的侧轴上居中 */
align-items: center;
}
/* 设置头像样式 */
.user-avatar {
width: 220rpx;
height: 220rpx;
border-radius: 50% 50%;
margin-top: 160rpx;
}
/* 昵称 */
.motto {
/* color:#666; */
margin-top: 100px;
font-size: 36rpx;
font-weight: bold;
}
/* 设置模拟的按钮外边框 */
.btn-journey-container {
margin-top: 150rpx;
border: 1rpx solid #405f80;
width: 200rpx;
height: 80rpx;
border-radius: 10px;
/* 文字居中 */
text-align: center;
}
/* 按钮文字 */
.journey {
font-size: 24rpx;
color: #405f80;
line-height: 80rpx;
font-weight: bold;
}
/* app.wxss */
text{
color:#666;
}
微信小程序入门(二)
安装组件库
在微信小程序里面,现在也可以使用第三方的组件库。
这里使用的是lin-ui组件库。有需要的可以去百度官网了解一下。
-
在项目根目录下初始化npm
npm init -y -
安装 lin-ui组件库
npm install lin-ui -
在微信小程序的 工具选项下选择构建npm
-
构建完成够,项目下就又多出一个文件夹。我们使用组件的时候都是使用这个文件夹下的。
-
在每个页面使用自定义组件的时候,我们需要在页面的json配置文件中,进行配置,指定我们使用的组件名称,以及组件所在的位置。
组件库的使用
头像组件库
这里简单使用一下头像组件库。
<!-- 使用组件库 动态绑定用户的头像,昵称(绑定的语法后面再说) -->
<!-- 使用size属性可以指定大小 -->
<!-- shape属性可以指定头像的样式,圆的还是方的 -->
<!-- 使用placement 可以指定头像和昵称的排列位置,这里上下排列 -->
<m-avatar placement="bottom" size="190" shape="circle" open-data="{{['userAvatarUrl','userNickName']}}"/>
pages页面的开发
指定主页
每次开发新的页面,总是需要在注册页面的地方频繁切换第一个文件,来达到预览的效果。比较麻烦。
方式一:
在现在的小程序中,增加了新的功能,可以在app.json中,直接指定主页。
方式二:指定编译模式
将页面指定为我们当前开发的页面即可。
制作轮播图
使用swipe
<!-- 使用官方提供的swiper组件 来做轮播图 -->
<!-- swiper 滑块视图容器,这个容器不仅仅是用来滑动图片,可以做很多事情 -->
<swiper>
<!-- 一般为了让图片撑满容器,需要设置容器的大小,和图片的大小,swipe-item 可以不设置 -->
<swiper-item>
<image src="/images/img1.jpg"></image>
</swiper-item>
<swiper-item>
<image src="/images/img2.webp"></image>
</swiper-item>
<swiper-item>
<image src="/images/img3.webp"></image>
</swiper-item>
</swiper>
/* 设置轮播图的大小 */
swiper {
width: 100%;
height: 460rpx;
}
image {
width: 100%;
height: 100%;
}
这样就完成了轮播图最开始的状态。
轮播图的指示点和自动轮播
我们使用swiper的某些属性就可以完成这两个功能。
indicator-dots="true" 显示轮播图的指示点
但是,即使我们设置 indicator-dots="false" 也就是设置属性值为false
我们的轮播图小指示点 也不会消失,除非我们不设置这个属性,或者
我们设置属性值为 indicator-dots="{{false}}"
那么问题来了:为什么我们设置属性值为 {{false}} 才能表示否定的概念呢?
原因是,不加双花括号,我们小程序会把这个属性值当做普通的字符串,普通的字符串在js中我们知道会转为true,这里也是一样。
双花括号里面写false 才能表示false
注意:关于双花括号的使用我们在后面会在说,实际上双花括号里面的数据会被当做js中的变量或者表达式进行运算。
只写属性值也会默认表示设置这个属性值为true。
布尔属性赋值建议
所以,我们在给布尔类型的属性赋值的时候,不管是true还是false,建议都使用双花括号进行包裹。
其他的swiper常用属性
这些属性在微信小程序的官网都是有说明的。想了解更多可以去官网自行阅读。
单篇文章的制作
我们要完成这样的一篇文章。我们分析一下整体的结构。
- 上面的轮播图我们已经制作完成了,那么就剩下文章的制作
- 这个文章从上到下,我们可以分为五个部分
- 头像+日期部分
- 文章标题部分
- 文章图片
- 文章内容
- 浏览和收藏人数
- 分为了五个部分,我们在开始制作这个文章模块。
先分析好我们制作页面的模块结构,在书写代码效率更高。
文章结构
!-- 第一篇文章 -->
<view class="post-container">
<!-- 第一部分 作者 日期 -->
<view class="post-author-date">
<!-- 头像 -->
<image class="post-author" src="/images/avatar/1.png"></image>
<text class="post-date">2021 08 26</text>
</view>
<!-- 第二部分 文章标题 -->
<text class="post-title">2021 哈哈哈哈哈哈哈啊哈哈哈哈哈</text>
<!-- 第三部分 -->
<image class="post-image" src="/images/post/cat.png"></image>
<!-- 第四部分 文章内容 -->
<text class="post-content">滑块视图容器,这个容器不仅仅是用来滑动图片,可以做很多事情,滑块视图容器,这个容器不仅仅是用来滑动图片,可以做很多事情,滑块视图容器,这个容器不仅仅是用来滑动图片,可以做很多事情,滑块视图容器,这个容器不仅仅是用来滑动图片,可以做很多事情</text>
<!-- 第五部分 -->
<view class="post-like">
<image class="post-like-image" src="/images/icon/chat.png"></image>
<text class="post-like-font">92</text>
<image class="post-like-image" src="/images/icon/view.png" />
<text class="post-like-font">102</text>
</view>
</view>
文章样式
/* 文章样式 */
.post-container {
/* 弹性布局 */
display: flex;
flex-direction: column;
margin-top: 20rpx;
margin-bottom: 40rpx;
background-color: #fff;
/* 上下边框线 */
border-top: 1rpx solid #ededed;
border-bottom: 1rpx solid #ededed;
padding-bottom: 10rpx;
}
/* 作者 日期样式 */
.post-author-date {
margin: 10rpx 0 20rpx 10rpx;
display: flex;
flex-direction: row;
/* flex 布局居中方案 */
align-items: center;
}
.post-author {
width: 60rpx;
height: 60rpx;
/* 头像和文字居中 */
/* vertical-align: middle; */
}
.post-date {
margin-left: 20rpx;
font-size:26rpx;
/* vertical-align: middle; */
}
/* 文章标题 */
.post-title{
font-size:34rpx;
font-weight: 700;
margin-bottom: 20rpx;
margin-left: 20rpx;
color:#333;
}
/* 文章主图 */
.post-image{
width: 100%;
height: 340rpx;
margin-bottom: 30rpx;
}
/* 文章内容 */
.post-content{
color:#666;
font-size: 28rpx;
margin-bottom: 20rpx;
margin-left: 20rpx;
line-height: 40rpx;
letter-spacing: 2rpx;
text-indent: 2em;
}
/* 文章模拟阅读量 */
.post-like{
display: flex;
flex-direction: row;
margin-left: 26rpx;
align-items: center;
}
.post-like-image{
height: 32rpx;
width: 32rpx;
margin-right: 16rpx;
}
.post-like-font{
margin-right: 40rpx;
font-size: 26rpx;
}
整体代码
页面结构
<!--pages/posts/posts.wxml-->
<view>
<!-- 使用官方提供的swiper组件 来做轮播图 -->
<!-- swiper 滑块视图容器,这个容器不仅仅是用来滑动图片,可以做很多事情 -->
<!--
indicator-dots="true" 显示轮播图的指示点
但是,即使我们设置 indicator-dots="false" 也就是设置属性值为false
我们的轮播图小指示点 也不会消失,除非我们不设置这个属性,或者
我们设置属性值为 indicator-dots="{{false}}"
那么问题来了:为什么我们设置属性值为 {{false}} 才能表示否定的概念呢?
原因是,不加双花括号,我们小程序会把这个属性值当做普通的字符串,普通的字符串在js中我们知道会转为true,这里也是一样。
双花括号里面写false 才能表示false
注意:关于双花括号的使用我们在后面会在说,实际上双花括号里面的数据会被当做js中的变量或者表达式进行运算。
-->
<!-- autoplay="true" 自动轮播 -->
<!-- indicator-active-color="#fff" 指示点激活的颜色 -->
<!-- circular="true"循环播放图片 -->
<!-- interval="2000" 图片切换间隔时长 字符串的数字内部会被转型 -->
<swiper indicator-dots="{{true}}" autoplay="true" indicator-active-color="#fff" circular="true" interval="2000">
<!-- 一般为了让图片撑满容器,需要设置容器的大小,和图片的大小,swipe-item 可以不设置 -->
<swiper-item>
<image src="/images/img1.jpg"></image>
</swiper-item>
<swiper-item>
<image src="/images/img2.webp"></image>
</swiper-item>
<swiper-item>
<image src="/images/img3.webp"></image>
</swiper-item>
</swiper>
<!-- pages -->
<!-- 第一篇文章 -->
<view class="post-container">
<!-- 第一部分 作者 日期 -->
<view class="post-author-date">
<!-- 头像 -->
<image class="post-author" src="/images/avatar/1.png"></image>
<text class="post-date">2021 08 26</text>
</view>
<!-- 第二部分 文章标题 -->
<text class="post-title">2021 哈哈哈哈哈哈哈啊哈哈哈哈哈</text>
<!-- 第三部分 -->
<image class="post-image" src="/images/post/cat.png"></image>
<!-- 第四部分 文章内容 -->
<text class="post-content">滑块视图容器,这个容器不仅仅是用来滑动图片,可以做很多事情,滑块视图容器,这个容器不仅仅是用来滑动图片,可以做很多事情,滑块视图容器,这个容器不仅仅是用来滑动图片,可以做很多事情,滑块视图容器,这个容器不仅仅是用来滑动图片,可以做很多事情</text>
<!-- 第五部分 -->
<view class="post-like">
<image class="post-like-image" src="/images/icon/chat.png"></image>
<text class="post-like-font">92</text>
<image class="post-like-image" src="/images/icon/view.png" />
<text class="post-like-font">102</text>
</view>
</view>
</view>
页面样式
/* pages/posts/posts.wxss */
/* 设置轮播图的大小 */
swiper {
width: 100%;
height: 460rpx;
}
swiper image {
width: 100%;
height: 100%;
}
/* 文章样式 */
.post-container {
/* 弹性布局 */
display: flex;
flex-direction: column;
margin-top: 20rpx;
margin-bottom: 40rpx;
background-color: #fff;
/* 上下边框线 */
border-top: 1rpx solid #ededed;
border-bottom: 1rpx solid #ededed;
padding-bottom: 10rpx;
}
/* 作者 日期样式 */
.post-author-date {
margin: 10rpx 0 20rpx 10rpx;
display: flex;
flex-direction: row;
/* flex 布局居中方案 */
align-items: center;
}
.post-author {
width: 60rpx;
height: 60rpx;
/* 头像和文字居中 */
/* vertical-align: middle; */
}
.post-date {
margin-left: 20rpx;
font-size:26rpx;
/* vertical-align: middle; */
}
/* 文章标题 */
.post-title{
font-size:34rpx;
font-weight: 700;
margin-bottom: 20rpx;
margin-left: 20rpx;
color:#333;
}
/* 文章主图 */
.post-image{
width: 100%;
height: 340rpx;
margin-bottom: 30rpx;
}
/* 文章内容 */
.post-content{
color:#666;
font-size: 28rpx;
margin-bottom: 20rpx;
margin-left: 20rpx;
line-height: 40rpx;
letter-spacing: 2rpx;
text-indent: 2em;
}
/* 文章模拟阅读量 */
.post-like{
display: flex;
flex-direction: row;
margin-left: 26rpx;
align-items: center;
}
.post-like-image{
height: 32rpx;
width: 32rpx;
margin-right: 16rpx;
}
.post-like-font{
margin-right: 40rpx;
font-size: 26rpx;
}
微信小程序入门(三)
前面我们制作了文章板块。
我们当时制作的模拟用户收藏文章和浏览次数,使用的是png格式的图片。但是图片有一个非常不好的地方,就是放大会失贞,使用我们打算将其换为字体图标。
字体图标的使用
在原生的微信小程序组件中,使用字体图标还是比较麻烦的。所以我们这里使用 lin-ui组件库的字体图标组件。
-
在pages.json文件里面注册组件以后就可以直接使用
<l-icon name="research"/> -
还可以修改图标的颜色,大小等
<l-icon color="#ccc" size="128" name="research"/>
所以这里我们就把上次的png做的图标替换为字体图标了。更加好看也方便。
<view class="post-like">
<l-icon color="#666" size="28" name="favor" class="post-like-image" />
<!-- <image class="post-like-image" src="/images/icon/chat.png"></image> -->
<text class="post-like-font">92</text>
<!-- <image class="post-like-image" src="/images/icon/view.png" /> -->
<l-icon color="#666" size="32" name="eye" class="post-like-image" />
<text class="post-like-font">102</text>
</view>
生成多篇文章
前面,我们完成了一篇文章的制作,这里我们多复制几次,假设有五篇文章,换一下内容和图片,日期头像等。(我们这里只是为了学习小程序的语法,暂时使用的都是假数据,死数据。实际上数据肯定不是这样写死在页面上的。)
数据来源
实际上我们页面展示的数据,都是从服务器请求过来的。那么就涉及到数据的单向数据绑定和双向数据绑定了。
单向数据绑定
单向数据绑定,就是通过js发起请求从服务器端获取的数据,我们通过某些手段将数据展示在view(页面,视图)上,让用户看见,而不允许修改。这也是开发中最常见的。
双向数据绑定
说白了,就是js向服务器请求的数据,在页面上展示的同时,用户也可以进行某些更改,然后同步修改了js里请求到的原生数据,二者可以相互影响。现在的小程序已经有(简易的)双向数据绑定的机制了。
小程序的双向数据绑定和前端三大框架比起来,应该算是很简单的了。当然在vue/react等框架中,如果对响应式原理不是很了解的话,出现了bug有时候也会很难受的。
实现数据单向绑定
小程序的生命周期放在后面再说。暂时先简单了解
onLoad生命周期
/**
* 生命周期函数--监听页面加载
* 也可以叫做 钩子函数 hook function
*/
onLoad: function (options) {
// onLoad函数,在小程序页面加载的时候,会自动进行回调这个函数。
console.log(1);
}
可以发现页面加载的时候,输出了1.
数据绑定方式一
那么我们如何实现数据绑定呢?
在js文件中,还有一个data属性,data属性是一个对象,在这个里面定义的变量,函数等,在view上是可以直接使用的。这里我们假设第一篇文章的标签是从服务器获取到的。
/**
* 页面的初始数据
*/
data: {
titles:["1-我是服务器请求到的标题!"]
},
在页面上进行使用该数据。语法就是前面说过的双花括号语法
<text class="post-title" user-select="true">2021 {{titles[0]}}</text>
数据绑定方式二setData
我们也可以通过setData函数,隐式的定义数据
onLoad: function (options) {
// onLoad函数,在小程序页面加载的时候,会自动进行回调这个函数。
// console.log(1);
// 使用setData函数定义的数据,会隐式的放到data属性上,
// 也就是说 最终数据都会在data属性上
this.setData({
dates:['2021 08 26']
})
console.log(this.data);
}
根据输出,可以看出最终数据是全都在data上定义了
数据定义
实现数据绑定的方式有显示和隐式两种,那么我们实际开发需要将数据都显示的定义吗?
答案是 有必要的都显示定义。如果这个变量,数据会被view页面直接引用,那么就建议,显示的定义在data里面。
data里面定义的变量是有初始值的。更多的情况下,我们可以把setData的作用理解为更新数据,而不是纯粹的为了定义数据。都在data里面显示的定义,也更加方便我们的阅读。
小程序的生命周期
生命周期就是页面的加载到卸载(消亡)。小程序的生命周期函数其实就是这个页面从加载到卸载的过程中,进行到某个阶段自动进行回调的函数。
onLoad: function (options) {
console.log("onLoad");
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
console.log("onReady");
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
console.log("onShow");
},
可以发现实际的加载顺序是: onLoad -> onShow -> onReady
onShow是在onReady前面的,因为页面显示不代表数据渲染也完成了。
其中onLoad生命周期函数是最重要的,也是用的最多的。
而 onHide和onUnload两个生命周期函数,是条件触发,并不是说页面必须隐藏,必须卸载。
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
console.log("onHide");
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
console.log("onUnload");
},
页面的卸载我们暂时不好模拟。但是可以模拟隐藏。
点击这个小圆点
就可以触发隐藏页面
再次切回小程序,又会触发onShow事件。
简单的数据绑定练习
模拟请求的数据
onLoad: function (options) {
/**
* 模拟从服务器请求到了数据
*/
const content = {
date: "Sep 18 2021",
title: "正是虾肥蟹壮时",
imgSrc: "/images/post/sls.jpg",
avatar: "/images/avatar/2.png",
content: "菊黄蟹正肥,品尝秋之味。徐志摩把,“看初花的荻芦”和“到楼外楼吃蟹”,并列为秋天来杭州不能错过的风雅之事;用林妹妹的话讲是“螯封嫩玉双双满,...",
reading: "112",
collection: "96",
author: "林白衣"
}
this.setData(content);
},
数据绑定到view
<view class="post-container">
<!-- 第一部分 作者 日期 -->
<view class="post-author-date">
<!-- 头像 -->
<image class="post-author" src="{{avatar}}"></image>
<text class="post-date">{{date}}</text>
</view>
<!-- 第二部分 文章标题 -->
<text class="post-title" user-select="true">{{title}}</text>
<!-- 第三部分 -->
<image class="post-image" src="{{imgSrc}}"></image>
<!-- 第四部分 文章内容 -->
<!-- user-select 方便用户复制 -->
<text class="post-content" >{{content}}</text>
<!-- 第五部分 -->
<view class="post-like">
<l-icon color="#666" size="28" name="favor" class="post-like-image" />
<text class="post-like-font">{{collection}}</text>
<l-icon color="#666" size="32" name="eye" class="post-like-image" />
<text class="post-like-font">{{reading}}</text>
</view>
</view>
条件渲染
有些元素我们需要在某些条件先才进行显示或者不显示,这时候就用到了条件渲染。
进行条件显示的语法:
<标签名 wx:if="条件"/>
<!--单个if条件判断-->
<text wx:if="true"></text>
<!--if-else条件判断-->
<text wx:if="{{flag}}"></text>
<text wx:else></text>
<!--if-else-if条件判断-->
<text wx:if="{{score>90}}">1</text>
<text wx:elif="{{score>80}}">2</text>
<text wx:else>3</text>
列表渲染
这里模拟一个数组,作为文章的数据。
onLoad: function (options) {
/**
* 模拟从服务器请求到了数据
*/
const content = [{
date: "Sep 18 2021",
title: "正是虾肥蟹壮时",
imgSrc: "/images/post/sls.jpg",
avatar: "/images/avatar/2.png",
content: "菊黄蟹正肥,品尝秋之味。徐志摩把,“看初花的荻芦”和“到楼外楼吃蟹”,并列为秋天来杭州不能错过的风雅之事;用林妹妹的话讲是“螯封嫩玉双双满,...",
reading: "112",
collection: "96",
author: "林白衣"
},
{
title: "从视觉到触觉 这款VR手套能给你真实触感",
content: "8月29日消息,据国外媒体VentureBeat报道,一家名为Dexta Robotics的公司最近发布了一款有望变革虚拟现实手部追踪与交互方式的新产品",
imgSrc: "/images/post/vr.png",
reading: 102,
collection: 26,
author: "深白色",
date: "Nov 20 2016",
avatar: "/images/avatar/4.png",
}]
this.setData({
posts: content
});
},
关于列表循环的更多语法在官网都有说明
我们这里只是简单的演示,列表循环可以循环数组,也可以循环对象。这里只演示数组循环。
<!-- 使用列表渲染来完成文章的制作 -->
<!-- 列表渲染的语法: wx:for -->
<!-- block 一般我们进行列表渲染的时候,都会在block标签上-->
<!-- block 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。 -->
<!-- block 标签没什么特别的含义,就是相当于一个括号,将多个需要循环的标签包裹起来 -->
<!-- 循环取posts数组里面的每一项元素遍历 -->
<!-- 如果没有指定每一项循环元素的名称,那么默认就是 item -->
<!-- 如果需要修改循环元素的名称,那么我们可以通过 wx:for-item 属性指定,还可以指定数组当前下标的变量名:wx:for-index="index" -->
<!-- 默认数组的当前项的下标变量名默认为 index -->
<block wx:for="{{posts}}" wx:for-item="item">
<!-- 第二篇文章 -->
<view class="post-container">
<!-- 第一部分 作者 日期 -->
<view class="post-author-date">
<!-- 头像 -->
<image class="post-author" src="{{item.avatar}}"></image>
<text class="post-date">{{item.date}}</text>
</view>
<!-- 第二部分 文章标题 -->
<text class="post-title" user-select="true">{{item.title}}</text>
<!-- 第三部分 -->
<image class="post-image" src="{{item.imgSrc}}"></image>
<!-- 第四部分 文章内容 -->
<!-- user-select 方便用户复制 -->
<text class="post-content">{{item.content}}</text>
<!-- 第五部分 -->
<view class="post-like">
<l-icon color="#666" size="28" name="favor" class="post-like-image" />
<text class="post-like-font">{{item.collection}}</text>
<l-icon color="#666" size="32" name="eye" class="post-like-image" />
<text class="post-like-font">{{item.reading}}</text>
</view>
</view>
</block>
关于block标签也不需要想太多。进行列表循环的时候,不管那么多直接使用就可以了。
列表循环最重要的作用就是用来展示一组数据。
页面的跳转
我们两个页面都基本开发完毕了。接下来回到welcome页面,完成点击按钮实现跳转到pages页面的功能。
什么是事件
都是学过js的兄弟,也就不多赘述了。
- 事件是视图层到逻辑层的通讯方式。
- 事件可以将用户的行为反馈到逻辑层进行处理。
- 事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。
- 事件对象可以携带额外信息,如 id, dataset, touches。
捕捉事件
事件发生了,不进行捕获是没有任何意义的。当我们捕捉到事件以后,可以进行一系列我们需要的操作。
我们这里就要实现点击按钮了触发页面跳转的功能。
在移动端,也就是触摸设备上,点击按钮这种操作实际上就是tap(指触摸后马上离开,实际上就是点击后马上离开)事件,所以我们需要捕获的就是tap事件。
捕获事件的语法:
<!-- 捕获事件: bind:事件名称="函数名称" -->
<view class="btn-journey-container" bind:tap="onTap">
<!-- 设置样式模拟出我们喜欢的按钮样式 -->
<text class="journey">开启小程序之旅</text>
</view>
事件回调函数的定义和onLoad等生命周期函数同级。
// 定义捕获Tap事件后的回调函数
onTap(params){
// 捕获事件 并跳转页面
// 1. 捕获事件 在页面上通过bind进行捕获
// 2. 完成页面的跳转
console.log('页面跳转!');
}
当我们单击了按钮以后,就会触发tap事件,进而执行相应的回调函数。
实际的页面跳转我们在下面说。
事件捕获语法糖
实际上,我们事件捕获不一定非要写成 bind:事件,也可以省略中间的 :,但是,我们建议还是不要省略。
<text bindtap="onTap"></text>
不过还是看个人习惯了。后面我们还会看见捕获事件还可以使用catch
路由系统
如果我们想要进行页面的跳转,那么必然离不开小程序的路由系统。
navigateTo方法
使用 wx.navigateTo({url: 'url'}) 方法完成页面直接的跳转
-
该方法接收的参数是一个对象,url属性是跳转的路径
-
navigateTo方法的特点:
- 该方法跳转的页面,实际上是当前页面的子页面,我们可以从子页面返回当前页面。当然,有子页面,肯定还可以有子子页面,但是页面不能无限的多下去,页面栈最多只能开辟10个,所以最多可以有十个子页面。
wx.navigateTo({
// 进行页面跳转的时候,填写的页面文件相对整个项目的绝对路径
url: '/pages/posts/posts',
// 也可以使用相对路径(可以看我们在app.json中配置的页面路径)
// url: '../posts/posts',
})
redirectTo方法
我们这里不希望从欢迎页面跳转到pages页面,还可以返回。也就是说欢迎页面我们只想作为一个过渡的页面,不让其和其他页面有什么必然的联系。
那么这里就可以使用redirectTo方法。使用方式和上面的一样。
wx.redirectTo({
// 进行页面跳转的时候,填写的页面文件相对整个项目的绝对路径
url: '/pages/posts/posts',
// 也可以使用相对路径(可以看我们在app.json中配置的页面路径)
// url: '../posts/posts',
})
页面跳转后,并没有可以返回父页面的小箭头了。但是这里有一个小房子一样的按钮。
点击这个小房子的按钮也会回到上个欢迎页面。是不是怀疑这个也能回到上个页面呢?
实际上,这个功能是现在新的小程序加进来的功能。这个小房子的按钮是回到首页用的,你的首页设置的是什么,就会回到那个页面。并不是所谓的一定回到上个页面。
redirectTo和navigateTo方法的区别
navigateTo方法会保留当前页面,也就是即使跳转到新的页面,当前页面也保留在页面栈中。
而 redirectTo方法会直接销毁当前页面,然后跳转到新的页面。
验证
这里我们可以通过前面提到的小程序的生命周期来进行验证。
我们在welcome页面的监听页面卸载的生命周期函数中写上输出语句进行验证。
wx.redirectTo({
// 进行页面跳转的时候,填写的页面文件相对整个项目的绝对路径
url: '/pages/posts/posts',
// 也可以使用相对路径(可以看我们在app.json中配置的页面路径)
// url: '../posts/posts',
})
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
console.log("welcome 页面被卸载!");
},
如果是redirectTo方法,我们可以发现,会调用onUnload方法。
而navigateTo方法则不会触发这个函数。说明页面被保留下来的。只是页面被隐藏了。
catch和bind事件的区别
bind捕获的就是实实在在在自己身上发生的事件,而catch可以捕获子元素发生的事件,其实就是事件的冒泡。
使用bind来捕获事件,这个事件是可以向上冒泡的。但是一旦使用了catch来进行事件的捕获,这个事件捕获到以后就终止了,不会继续向外传递。
这里使用三层的事件绑定进行测试
先使用 catch-bind-bind
-
当我们点击按钮上的文字时
-
点击按钮(不点文字)
测试二:catch-catch-bind
-
点击按钮上的文字
-
点击按钮 不点文字
测试三:catch-catch-catch
-
点击按钮上的文字
-
点击按钮 不点击文字
综上:使用catch和bind都可以捕获事件,但是catch会阻止冒泡,导致父元素无法进行事件的捕获。
js模块的导入导出
现在我们把模拟的文章请求数据从posts.js文件中抽离出去。这里简单模拟几篇数据,需要更多的数据可以自己随意书写。
在ES6中,一个js文件我们就可以视作为一个模块。
导入导出的语法就不多说了。这玩意都是js基础。
文章跳转
从列表文章跳转到文章详情页
很明显,我们实际上也不可能知道具体有多多少文章,所以实际上的文章详情页也只会有一个。具体显示什么内容肯定是根据实际的文字内容自动填充的。而我们要做的就是做好文章详情内容模板。
很明显,这里肯定还是需要用到事件。我们需要监听用户的点击事件。
这个事件应该作用域这篇文章的所有部分,只有点击到了文章上,就进行跳转。实际上这里的跳转不应该这么简单,比如我们点击头像了,可以进行头像图片的放大,或者说跳转到用户详情页,等等。
这里就不考虑那么多了。
随意单击文章的任何地方都能够进行跳转
因为这里我们去往的是文章详情页,所以应该使用navigateTo方法。
关于列表渲染警告
前面我们发现,使用了列表渲染,一直提示警告。
这里建议我们使用 wx:key属性,可以提高列表渲染的性能。
我这里的postId是在模拟的数据中添加的属性。key绑定的值只要是唯一的就可以了。当然我们也不建议绑定文章数据在数组中的索引。那样其实也并不是合法的。
然后就是新的小程序这里绑定是不需要使用双花括号语法的,也不需要item.postId来绑定。因为这是在循环的那层标签上。
以前是可以使用双花括号语法进行绑定的,现在新版的小程序进行了修改。