小程序常用知识-12-12-00:00
小程序常用知识
1.课程亮点
# 1.全新课程模式: 告别模拟数据,提供在线 RESTFul API # 2.提供全套设计图原稿 (PSD) 与切图 # 3.全新小程序开发模式: 组件开发 # 4.良好的小程序结构 # 5.项目看起来简单,但细节及其之多 # 6.flex 布局与 ES6
2.准备工作
# 1.进入微信公众平台官网 # http://mp.weixin.qq.com # 2.注册微信小程序(个人、企业) # 小程序、服务号、订阅号、企业号(企业微信) # 3.下载微信开发者工具 # 4.登录小程序账号后台获取 appid
3.常用快捷键
# 1.格式化代码 Shift+Alt+F # 2.跳转文件 Ctrl+P # 3.最近文件 Ctrl+E
4.小程序的 4 种文件类型
# 1.样式 --> wxss --> css # 2.骨架 --> wxml --> html # 3.业务 --> js --> js # 4.配置 --> json
5.小程序的基本结构
5.1.基本结构

5.2.良好的结构(组件式编程)

6.初始化
///////////////////////////////////////////////////////////////////////////////////////////
// 步骤1:除了项目下的文件 project.config.json、sitemap.json 和 pages 目录,其它全部删除
///////////////////////////////////////////////////////////////////////////////////////////
// 步骤2:在项目下新建文件 app.js 和 app.json
///////////////////////////////////////////////////////////////////////////////////////////
// 步骤3:app.js 添加上代码
App({
onLauch:function() {
}
})
///////////////////////////////////////////////////////////////////////////////////////////
// 步骤4:app.json 添加上代码
{}
//////////////////////////////////////////////////////////////////////////////////////////
// 步骤5:在 pages 目录下新建目录 classic,在目录 classic 新建 Page,名字为 classic,会自动生成4个文件
// 1.classic.js
// 2.classic.json
// 3.classic.wxml
// 4.classic.wxss
///////////////////////////////////////////////////////////////////////////////////////////
// 步骤6:在项目下文件 app.json 自动新增代码
{
"pages": [
"pages/classic/classic"
]
}
7.小程序配置
///////////////////////////////////////////////////////////////////////////////////////////
// 全局配置(前三个重点)
// pages String Array 是 设置页面路径
// window Object 否 设置默认页面的窗口表现
// tabBar Object 否 设置底部tab的表现
// networkTime Ojbect 否 设置网络超时时间
// debug Boolean 否 设置是否开启debug模式
{
"pages": [
"pages/index/index",
"pages/logs/index"
],
"window": {
"navigationBarTitleText": "Demo"
},
"tabBar": {
"list": [{
"pagePath": "pages/index/index",
"text": "首页"
}, {
"pagePath": "pages/logs/index",
"text": "日志"
}]
},
"networkTimeout": {
"request": 10000,
"downloadFile": 10000
},
"debug": true,
"navigateToMiniProgramAppIdList": [
"wxe5f52902cf4de896"
]
}
///////////////////////////////////////////////////////////////////////////////////////////
// window
// 用于设置小程序的状态栏、导航条、标题、窗口背景色。
//
// 常用属性
// navigationBarBackgroundColor 导航栏背景颜色,如 #000000
// navigationBarTitleText 导航栏标题文字内容
// navigationBarTextStyle 导航栏标题颜色,仅支持black/white
// navigationStyle 导航栏样式,仅支持以下值:
// default 默认样式
// custom 自定义导航栏,只保留右上角胶囊按钮。
// backgroundColorTop 顶部窗口的背景色,仅 iOS 支持
// backgroundColorBottom 底部窗口的背景色,仅 iOS 支持
///////////////////////////////////////////////////////////////////////////////////////////
// background 区域
// 1.一般在开发工具无法看到,手指下拉滑动刷新时显示
// 2.一般分两部分,一部分是上面,一部分是下面,只能在真机中才能看到
// 3.上部分可开启enablePullDownRefresh查看
// 4.开发时需要保持页面和background区域颜色一致
//
// 常用属性
// backgroundColor 窗口的背景色
// enablePullDownRefresh 是否开启全局的下拉刷新
///////////////////////////////////////////////////////////////////////////////////////////
// 实例
{
"pages": [
"pages/classic/classic"
],
"window":{
"navigationBarBackgroundColor":"#FFFF00",
"navigationBarTitleText":"林间有风",
"navigationBarTextStyle":"black",
"navigationStyle":"default",
"backgroundColor":"#ffffff",
"enablePullDownRefresh":false
}
}
8.flex布局
///////////////////////////////////////////////////////////////////////////////////////////
// flex 布局
//
// Flex是Flexible Box的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。
// 任何一个容器都可以指定为Flex布局。
// 注意,设为Flex布局以后,子元素的float、clear和vertical-align属性将失效
.box{
display: flex;
}
// 行内元素也可以使用Flex布局。
.box{
display: inline-flex;
}
// Webkit内核的浏览器,必须加上-webkit前缀。
.box{
display: -webkit-flex; /* Safari */
display: flex;
}
//////////////////////////////////////////////////////////////////////////////////////////
// 采用 Flex 布局的元素,称为 Flex 容器(flex container),
// 简称"容器"。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目"。
// 容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。
// 主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;
// 交叉轴的开始位置叫做cross start,结束位置叫做cross end。
// 项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size。
///////////////////////////////////////////////////////////////////////////////////////////
// 容器的6个属性
//////////////////////////////////////////
// 1.flex-direction
//
// flex-direction属性决定主轴的方向(即项目的排列方向)
.box {
flex-direction: row | row-reverse | column | column-reverse;
}
// 它可能有4个值
// 1)row(默认值):主轴为水平方向,起点在左端。
// 2)row-reverse:主轴为水平方向,起点在右端。
// 3)column:主轴为垂直方向,起点在上沿。
// 4)column-reverse:主轴为垂直方向,起点在下沿。
//////////////////////////////////////////
// 2.flex-wrap
//
// 默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap属性定义,如果一条轴线排不下,如何换行。
.box{
flex-wrap: nowrap | wrap | wrap-reverse;
}
// 它可能取三个值。
// 1)nowrap(默认):不换行。
// 2)wrap:换行,第一行在上方。
// 3)wrap-reverse:换行,第一行在下方。
//////////////////////////////////////////
// 3.flex-flow
//
// flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap
.box {
flex-flow: <flex-direction> || <flex-wrap>;
}
//////////////////////////////////////////
// 4.justify-content
//
// justify-content属性定义了项目在主轴上的对齐方式。
.box {
justify-content: flex-start | flex-end | center | space-between | space-around;
}
// 它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右。
// 1)flex-start(默认值):左对齐
// 2)flex-end:右对齐
// 3)center:居中
// 4)space-between:两端对齐,项目之间的间隔都相等。
// 5)space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
//////////////////////////////////////////
// 5.align-items
//
// align-items属性定义项目在交叉轴上如何对齐。
.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}
// 它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。
// 1)flex-start:交叉轴的起点对齐。
// 2)flex-end:交叉轴的终点对齐。
// 3)center:交叉轴的中点对齐。
// 4)baseline:项目的第一行文字的基线对齐。
// 5)stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。
//////////////////////////////////////////
// 6.align-content
//
// align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
.box {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
// 该属性可能取6个值。
// 1)flex-start:与交叉轴的起点对齐。
// 2)flex-end:与交叉轴的终点对齐。
// 3)center:与交叉轴的中点对齐。
// 4)space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
// 5)space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
// 6)stretch(默认值):轴线占满整个交叉轴。
///////////////////////////////////////////////////////////////////////////////////////////
// 项目的6个属性
//////////////////////////////////////////
// 1.order
//
// order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。
.item {
order: <integer>;
}
//////////////////////////////////////////
// 2.flex-grow
//
// flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。
// 如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。
// 如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。
.item {
flex-grow: <number>; /* default 0 */
}
//////////////////////////////////////////
// 3.flex-shrink
//
// flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
// 如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。
// 如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。
// 负值对该属性无效。
.item {
flex-shrink: <number>; /* default 1 */
}
//////////////////////////////////////////
// 4.flex-basis
//
// flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。
// 浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
// 它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间。
.item {
flex-basis: <length> | auto; /* default auto */
}
//////////////////////////////////////////
// 5.flex
//
// flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
// 该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
// 建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
//////////////////////////////////////////
// 6.align-self
//
// align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,
// 表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。
// 该属性可能取6个值,除了auto,其他都与align-items属性完全一致。
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
9.实例,新建like组件
###########################################################################################
# 定义引用与使用组件
#
# 新增组件like
###########################################
# 1.项目下新建目录components
###########################################
# 2.项目下目录components下,新建目录like
###########################################
# 3.项目下目录components/like下,鼠标新建Component,名字为index,新增了4个文件(注意目录名跟文件名不一定一样)
###########################################
# 4.项目下目录pages/classic/下,修改文件 classic.json,添加要使用的组件路径
{
"usingComponents":{
"v-like":"/components/like/index"
}
}
###########################################
# 5.项目下目录pages/classic/下,修改文件classic.wxml,添加要引用的组件
<v-like />
###########################################
# 6.项目下新建目录images,这是放页面图片
###########################################
# 7.项目下新建目录components/like/images,这是放like组件图片
###########################################
# 8.项目下目录components/like/images下,拷贝图片like.png、like@dis.png
###########################################
# 9.项目下目录components/like下,修改文件index.wxml,添加图片
<!--components/like/index.wxml-->
<!-- 默认是宽度300px,高度225px -->
<image class="container" src="images/like.png" />
###########################################
# 10.项目下目录components/like下,修改文件index.wxss,修改图片样式
/* components/like/index.wxss */
/*
只有按iphone6设计(750*1334),1px=2rpx,推荐用iPhone6来设计
rpx和px的区别,rpx是自适应的,px是固定的
*/
.container {
width:32rpx;
height:28rpx;
}
###########################################
# 11.项目下目录components/like下,修改文件index.wxml,添加文字
<!--components/like/index.wxml-->
<!-- 默认是宽度300px,高度225px -->
<view class="container">
<image src="images/like.png" />
<text>9</text>
</view>
###########################################
# 12.项目下目录components/like下,修改文件index.wxss,调整添加样式
/* components/like/index.wxss */
.container {
}
#
.container image {
width: 32rpx;
height: 28rpx;
}
#
.container text {
/* 苹方 思源 */
/* 苹果手机才有用 */
/* font-family: "PingFnagSC-Thin"; */
font-size: 48rpx;
color: #bbbbbb;
}
###########################################
# 13.项目下添加文件 app.wxss, 添加全局字体
page {
font-family: "PingFangSC-Thin";
font-size: 32rpx;
}
###########################################
# 这里讨论几个问题:
######################
# 1) 为什么在这里可以通过page设置全局字体,原因是小程序会在每个页面(wxml文件)外部包裹一个page
<page>
<v-like is="components/like/index">
# shadow-root
<view class="container">
<image src="images/like.png" role="img"></image>
<text>
9
</text>
</view>
</v-like>
</page>
######################
# 2) 为什么在全局中修改了字体大小,查看like页面时字体大小没有改变呢?
# 原因在like组件的里面也定义了字体的大小,导致组件里面的字体大小覆盖了全局的字体大小
# 所以如果定义了全局的样式,如果要改变自己组件的样式时,可以在组件中添加自己的样式来覆盖全局的样式
######################
# 3) 组件只能继承极少数全局样式(只是组件,pages是大多数都能继承)
# 组件继承样式,如font,color,会从组件外继承到组件内。
###########################################
# 14.项目下目录components/like下,修改文件index.wxss,调整图片和文字的样式
/* components/like/index.wxss */
.container {
display: flex;
flex-direction: row;
padding: 10rpx;
}
.container image {
width: 32rpx;
height: 28rpx;
}
.container text {
/* 苹方 思源 */
/* 苹果手机才有用 */
/* font-family: "PingFnagSC-Thin"; */
font-size: 24rpx;
color: #bbbbbb;
position: relative;
bottom: 10rpx;
left: 6rpx;
}
######################
# 注意: 组件最好不要留有空白间距,文字一般都会有空白间距
# 最好加上line-height
.container text {
/* 苹方 思源 */
/* 苹果手机才有用 */
/* font-family: "PingFnagSC-Thin"; */
font-size: 24rpx;
line-height: 24rpx;
color: #bbbbbb;
position: relative;
bottom: 10rpx;
left: 6rpx;
}
###########################################
# 15.项目下目录components/like下,修改文件index.wxss,container的宽度,目前container是充满整行的
.container {
display: flex;
flex-direction: row;
padding: 10rpx;
width: 80rpx;
}
###########################################
# 16.项目下目录components/like下,修改文件container的宽度,但是又由于文本数字是一个变化的
# container的宽度不能设置一个定死的数字,应该设置成自适应的
# 但是这样设置会产生跳动的状态,例如9变成10的时候,这里的修改没有完美的,只能看自己项目的环境而定
# 如果你一定要设置一个宽度,可以考虑使用一个文本简略显示的方式,例如本来是9000的数字,改成9k这样表示
.container {
display: inline-flex;
flex-direction: row;
padding: 10rpx;
}
###########################################
# 16.项目下目录components/like下
# 修改的文件列表
# 1.修改文件index.wxml,添加bind:tap点击事件
# 2.修改文件index.js,添加bind:tap函数
# 修改步骤
# 1.确定触发区域,这里把图片和文字都确定为触发区域
# 2.使用bind:tap点击事件
<view bind:tap="onLike" class="container">
<image src="images/like.png" />
<text>9</text>
</view>
# 3.使用javascript处理函数
methods: {
onLike:function(event) {
console.log(event)
}
}
#######################
# 这里要讨论的是点击有两个点击事件
# 1.bind:tap
# 2.catch:tap
# 有什么区别?
# 与 bind 不同,catch 会阻止事件向上冒泡。
#
# 事件分为冒泡事件和非冒泡事件:
# 1.冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递。
# 2.非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递
###########################################
# 数据来源的三种途径
# 1.WXML
<image src="images/like.png" />
# 2.JS -> WXML
# 1.数据绑定
# 1.项目下目录components/like下,修改文件index.js
data: {
count:9
},
# 2.项目下目录components/like下,修改文件index.wxml
<view bind:tap="onLike" class="container">
<image src="images/like.png" />
<text>{{count}}</text>
</view>
# 2.三元表达式
# 1.项目下目录components/like下,修改文件index.js
data: {
count: 99,
like: true,
yesSrc: 'images/like.png',
noSrc: 'images/like@dis.png
},
# 2.项目下目录components/like下,修改文件index.wxml
<view bind:tap="onLike" class="container">
<image src="{{like?yesSrc:noSrc}}" />
<text>{{count}}</text>
</view>
# 3.服务器 -> JS -> WXML
###########################################
# 组件的封闭性,开放性及粒度
# 1.yesSrc 和 noSrc 不需要开放出来
# 2.count 和 like 需要开放出来
# 3.可通过properties属性处理
###########################################
# 组件的properties属性详解
#
# 1.properties属性如下
properties: {
prop: {
type: Boolean, // type 包含 Boolean、Number、String,是必填
value: false, // 非必填
observer: function() { // 非必填
}
}
},
# 2.项目下目录components/like下,修改文件index.js
/**
* 组件的属性列表
*/
properties: {
like: {
type: Boolean,
},
count: {
type: Number,
value: 0
}
},
/**
* 组件的初始数据
*/
data: {
yesSrc: 'images/like.png',
noSrc: 'images/like@dis.png'
},
###########################################
# let,var与组件事件应用
# 1.let与var的区别
# let允许你声明一个作用域被限制在块级中的变量、语句或者表达式,与var关键字不同的是,
# 它声明的变量只能是全局或者整个函数块的
if (true) {
let a = 1;
var b = 2;
}
console.log(b); // 2
console.log(a); // 报错
# 2.项目下目录components/like下,修改文件index.js,点击切换图片和关注数
/**
* 组件的方法列表
*/
methods: {
onLike:function(event) {
let like = this.properties.like;
let count = this.properties.count;
count = like?count-1:count+1;
this.setData({
count: count,
like: !like
});
}
}
10.访问API数据与ES6在小程序中的应用
###########################################################################################
# 看待组件的两种观点(这是小程序教程中说明)
# 开发者可以将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用;
# 也可以将复杂的页面拆分成多个低耦合的模块,有助于代码维护。自定义组件在使用时与基础组件非常相似。
###########################################################################################
# Blink API介绍与测试API
###########################################################################################
# 生命周期函数
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
###########################################################################################
# wx.request-4xx状态码并不会执行fail
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
wx.request({
// 开发者服务器接口地址
url: '',
// 请求的参数
data: '',
// 设置请求的header,header中不能设置Referer
header: '',
// (需大写)有效值:OPTIONS,GET,HEAD,POST,PUT,DELETE,TRACE,CONNECT
method: '',
// 如果设置为json,会尝试对返回的数据做一次JSON.parse
dataType: '',
// 设置响应的数据类型。合法值:text,arraybuffer
responseType: '',
// 收到开发者服务成功返回的回调函数
success: '',
// 接口调用失败的回调函数
fail: '',
// 接口调用结束的回调函数(调用成功失败都会执行)
complete: '',
})
},
###########################################################################################
# 访问API获取数据
# 1.在微信小程序管理后台更新域名配置,刷新项目配置后重新编译项目,具体路径 "详情-域名信息"
或者在开发工具中选择 "设置"->"项目设置"->"本地设置"->选择"不检验合法域名、web-view...."
###############################################
# 2.调用API
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
wx.request({
url: 'http://bl.7yue.pro/v1/classic/latest',
header: {
appkey: "KOLDaSADSDLWWbF"
}
})
},
###########################################################################################
# 同步,异步与回调函数
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
wx.request({
url: 'http://bl.7yue.pro/v1/classic/latest',
header: {
appkey: "KOLDaSADSDLWWbF"
},
success:function(res) {
console.log(re)
}
})
},
###########################################################################################
# ES6箭头函数与this指代
############################################
# 1.this的问题
########################
# 1.首先在data加一个属性
/**
* 页面的初始数据
*/
data: {
test:1
},
# 2.然后在onload最外面调用,这是没有问题的
onLoad: function (options) {
// 没有问题
console.log(this.data.test)
wx.request({
url: 'http://bl.7yue.pro/v1/classic/latest',
header: {
appkey: "KOLDaSADSDLWWbF"
},
success:function(res) {
console.log(res)
}
})
},
# 3.然后在onload的回调函数中调用,报错了
onLoad: function (options) {
// 没有问题
console.log(this.data.test)
wx.request({
url: 'http://bl.7yue.pro/v1/classic/latest',
header: {
appkey: "KOLDaSADSDLWWbF"
},
success:function(res) {
console.log(res)
// 报错了
console.log(this.data.test)
}
})
},
########################
# 2.ES5的解决方法
onLoad: function (options) {
// 没有问题
console.log(this.data.test)
// 保存this
let that = this
wx.request({
url: 'http://bl.7yue.pro/v1/classic/latest',
header: {
appkey: "KOLDaSADSDLWWbF"
},
success:function(res) {
console.log(res)
// 没有问题了
console.log(that.data.test)
}
})
},
########################
# 3.ES6的解决方法
onLoad: function (options) {
// 没有问题
console.log(this.data.test)
wx.request({
url: 'http://bl.7yue.pro/v1/classic/latest',
header: {
appkey: "KOLDaSADSDLWWbF"
},
success:(res)=>{
console.log(res)
// 没有问题了
console.log(this.data.test)
}
})
},
###########################################################################################
# 正确理解Promise,不要滥用Promise
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
// 使用 promise
let promise = new Promise((resolve, reject) => {
wx.request({
url: 'http://bl.7yue.pro/v1/classic/latest',
header: {
appkey: "KOLDaSADSDLWWbF"
},
success: (res) => {
resolve(res)
}
});
});
promise.then((res) => {
console.log(res)
});
}
##############################################
# promise主要解决两个问题
########################
# 1.异步嵌套
onLoad: function (options) {
console.log(this.data.test)
wx.request({
url: 'http://bl.7yue.pro/v1/classic/latest',
header: {
appkey: "KOLDaSADSDLWWbF"
},
success:(res)=>{
console.log(res)
console.log(this.data.test)
// 嵌套1
wx.request({
success:(res) => {
// 嵌套2
wx.request({
success:(res) => {
// 不断嵌套
....
}
})
}
})
}
})
},
########################
# 2.处理异步操作的时候,使用的是回调函数,它会剥夺了可以在函数里进行return的能力
###########################################################################################
# ES6
###########################################
# 1.const常量(固定不变的常量)
# 1.1.在项目下新建文件config.js,不固定不变的常量加入这个文件
const config = {
api_base_url: 'http://bl.8yue.pro/v1/',
appkey: "KOLDaSADSDLWWbF"
}
# 2.Module export与import
# 2.1.在项目下新建目录util
# 2.2.在项目下目录util,新建文件http.js,文件把wx.request请求进行二次封装
class HTTP {
request(params) {
// params 包括 url, data, method,
wx.request({
url:params.url
})
}
}
# 2.3.在项目下目录util,修改文件http.js, 需要读取项目下文件config.js
# 2.3.1.在项目下修改文件config.js,在文件config.js中使用export,让config.js文件可以被其文件使用
export const config = {
api_base_url: 'http://bl.8yue.pro/v1/',
appkey: "KOLDaSADSDLWWbF"
}
2.3.2.在项目下目录util,修改文件http.js,使用import,文件http.js可以使用项目下文件config.js
import { config } from '/config.js'
class HTTP {
request(params) {
// params 包括 url, data, method,
wx.request({
url:params.url
})
}
}
# 2.4.如果要使用多个方法
# 2.4.1.在项目下修改文件config.js
# 2.4.1.1.方法1
export const config = {
api_base_url: 'http://bl.8yue.pro/v1/',
appkey: "KOLDaSADSDLWWbF"
}
export let fun1 = function() {
}
# 2.4.1.2.方法2(推荐)
const config = {
api_base_url: 'http://bl.8yue.pro/v1/',
appkey: "KOLDaSADSDLWWbF"
}
let fun1 = function() {
}
export { config as config1, fun1 as fun2 }
# 2.4.2.在项目下目录util,修改文件http.js
import { config, fun1 } from '/config.js'
// import { config as config1 } from '/config.js'
class HTTP {
request(params) {
// params 包括 url, data, method,
wx.request({
url:params.url
})
}
}
# 2.5.最终代码如下
# 2.5.1.在项目下修改文件config.js
const config = {
api_base_url: 'http://bl.8yue.pro/v1/',
appkey: "KOLDaSADSDLWWbF"
}
export { config }
# 2.5.2.在项目下目录util,修改文件http.js
import { config } from '/config.js'
class HTTP {
request(params) {
// params 包括 url, data, method,
wx.request({
url:params.url
})
}
}
###########################################
# 3.HTTP类的封装与ES6 startsWith
# 3.1.在项目下目录util,修改文件http.js,封装HTTP类,使用startWith判断回调返回状态码是否2开头
import { config } from '/config.js'
class HTTP {
request(params) {
// params 包括 url, data, method,
if (!params.method) {
params.method = "GET"
}
wx.request({
url:config.api_base_url + params.url,
method:params.method,
data:params.data,
header: {
'content-type':'application/json',
'appkey':config.appkey
},
success:(res) => {
// startsWith
// endsWith
let code = res.statusCode
if (statusCode.startsWith('2')) {
} else {
}
},
fail:(err) => {
}
})
}
}
export {HTTP}
###########################################################################################
# 分析问题的思维培养与练习
# 1.在项目下目录pages/classic,修改文件classic.js,导入http类
import {HTTP} from '/util/http.js'
let http = new HTTP()
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
http.request({
url: 'classic/latest',
success: (res) => {
console.log(res)
}
})
},
# 2.提示几个错误
2.1.在项目下目录pages/classic,修改文件classic.js,在import时只能使用相对路径
import {HTTP} from '../../util/http.js'
2.2.在项目下目录util,修改文件http.js,在import时只能使用相对路径
import { config } from '../config.js'
2.3.在项目下目录util,修改文件http.js,由于res.statusCode 返回的是一个数字不是字符串
success:(res) => {
let code = res.statusCode.toString()
if (statusCode.startsWith('2')) {
} else {
}
},
###########################################################################################
# 回调函数传递
# 1.在项目下目录util,修改文件http.js,把数据返回调用方
success:(res) => {
// startsWith
// endsWith
// res.statusCode 返回的是一个数字不是字符串
let code = res.statusCode.toString()
if (statusCode.startsWith('2')) {
params.success(res.data)
} else {
}
},
###########################################################################################
# 通用错误异常处理
# 1.在项目下目录util,修改文件http.js,添加错误异常处理
import { config } from '../config.js'
const tips = {
1: '抱歉,出现了一个错误',
1005: 'appkey无效,请前往www.7yue.pro申请',
3000: '期刊不存在'
}
class HTTP {
request(params) {
// params 包括 url, data, method,
if (!params.method) {
params.method = "GET"
}
wx.request({
url:config.api_base_url + params.url,
method:params.method,
data:params.data,
header: {
'content-type':'application/json',
'appkey':config.appkey
},
success:(res) => {
// startsWith
// endsWith
// res.statusCode 返回的是一个数字不是字符串
let code = res.statusCode.toString()
if (statusCode.startsWith('2')) {
params.success(res.data)
} else {
let error_code = res.data.error_code
this._show_error(error_code)
}
},
fail:(err) => {
this._show_error(1)
}
})
}
// 用_开头表示私有方法
_show_error(error_code) {
if (!error_code) {
error_code = 1
}
wx.showToast({
title: tips[error_code],
icon: 'none',
duration: 2000
})
}
}
export {HTTP}
11.流行页面编码与组件的细节知识
###########################################################################################
# 1.剥夺函数return的能力
######################
# 1.1.在项目下新建目录 models
######################
# 1.2.在项目下目录 models,新建文件 classic.js
import {HTTP} from '../util/http.js'
class ClassicModel extends HTTP {
getLatest(sCallback) {
this.request({
url: 'classic/latest',
success: (res) => {
sCallback(res)
}
})
}
}
export {ClassicModel}
######################
# 1.3.在项目下目录pages/classic,修改文件classic.js
// pages/classic.js
import {ClassicModel} from '../../models/classic.js'
let classic = new ClassicModel()
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
classic.getLatest((res) => {
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
##########################################
# 2.组件属性赋值与页面渲染流程解析
######################
# 2.1.在项目下目录pages/classic,修改文件classic.js,绑定数据
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
// 更新数据
classic.getLatest((res) => {
this.setData({
classic:res
})
})
},
######################
# 2.2.在项目下目录pages/classic,修改文件classic.wxml,传递数据
<v-like like="{{classic.like_status}}" count="{{classic.fav_nums}}" />
##########################################
# 3.setData的误区
######################
# 3.1.在wxml文件显示数据不一定需要setData,setData是用来更新数据的
# 3.1.1.在项目下目录pages/classic,修改文件classic.js
data: {
test: 1
},
onLoad: function (options) {
// 更新数据
classic.getLatest((res) => {
this.setData({
classic:res
})
})
},
# 3.1.2.在项目下目录pages/classic,修改文件classic.wxml
<v-like like="{{classic.like_status}}" count="{{classic.fav_nums}}" />
<text>{{test}}</text>
# 3.1.3.查看模拟器,数据能显示
######################
# 3.2.更新数据必须用setData,例如想修改test的数据从1变成2,不能这样写 this.data.test = 2,这是错误的
# 3.2.1.在项目下目录pages/classic,修改文件classic.js
data: {
test: 1
},
onLoad: function (options) {
// 更新数据
classic.getLatest((res) => {
this.setData({
classic:res,
test:2
})
})
console.log(this.data)
},
# 3.2.2.查看模拟器,数据修改了
######################
# 3.3.为什么classic没有存在data下,也能数据更新?
原因是setData可以把classic加入到data中,然后再设置成res,可以通过console.log(this.data)查看
######################
# 3.4.建议在data添加classic默认值
data: {
classic:null,
test: 1
},
############################################
# 4.movie组件的实现
######################
# 4.1.在项目下目录components,新建目录classic
######################
# 4.2.在项目下目录components/classic,新建目录movie
######################
# 4.3.在项目下目录components/classic/movie,新建Component,文件名index
######################
# 4.4.在项目下目录components/classic/movie,新建目录images,并拷贝图片到目录中
######################
# 4.5.在项目下目录components/classic/movie,修改文件index.wxml
<view>
<image src="{{img}}" />
<image src="images/music@tag.png"/>
<text>{{content}}</text>
</view>
######################
# 4.6.在项目目录components/classic/movie下,修改文件index.js
/**
* 组件的属性列表
*/
properties: {
img:String,
content:String
},
######################
# 4.7.在项目目录pages/classic下,修改文件classic.json
{
"usingComponents": {
"v-like":"/components/like/index",
"v-movie":"/components/classic/movie/index"
}
}
######################
# 4.8.在项目下目录pages/classic,修改文件classic.wxml
<v-like like="{{classic.like_status}}" count="{{classic.fav_nums}}" />
<v-movie img="{{classic.image}}" content="{{classic.content}}" />
######################
# 4.9.在项目下目录pages/classic,修改文件classic.wxss
.classic-container {
display: flex;
flex-direction: column;
align-items: center;
}
.classic-image {
width: 750rpx;
height: 500rpx;
}
.tag {
width: 46rpx;
height: 142rpx;
position: relative;
right: 310rpx;
bottom: 58rpx;
}
.content {
font-size: 36rpx;
max-width: 550rpx;
}
############################################
# 5.自定义事件的激活与监听
# 5.1.在项目下目录components/like,修改文件 index.js,激活和坚挺自定义函数
# triggerEvent的第三个参数,包括三个触发事件的选项
# 选项名 类型 是否必填 默认值 描述
# 1.bubbles Boolean 否 false 事件是否冒泡
# 2.composed Boolean 否 false 事件是否可以穿越组件边界,为false时,事件将只能在引用组件的节点树上触发,不进入其它任何组件内部
# 1.bubbles Boolean 否 false 事件是否拥有捕获阶段
/**
* 组件的方法列表
*/
methods: {
onLike: function(event) {
let like = this.properties.like
let count = this.properties.count
count = like?count-1:count+1
this.setData({
count:count,
like:!like
})
// 激活
let behavior = this.properties.like?'like':'cancel'
this.triggerEvent('like', {
behavior:behavior
}, {})
}
}
######################
# 5.2.在项目下目录pages/classic,修改文件 classic.wxml,添加自定义监听事件
<v-like bind:like="onLike" like="{{classic.like_status}}" count="{{classic.fav_nums}}" />
######################
# 5.3.在项目下目录pages/classic,修改文件 classic.js,添加自定义函数
// 自定义函数
onLike: function(event) {
console.log(evnet)
},
############################################
# 6.喜欢还是不喜欢
######################
# 6.1.在项目下目录models,新建文件like.js
import { HTTP } from '../utils/http.js'
class LikeModel extends HTTP {
like(behavior, artID, categroy) {
let url = behavior == 'like'?'like':'like/cancel'
this.request({
url: url,
method: 'POST',
data: {
art_id: artID,
type: categroy
}
})
}
}
export { LikeModel }
######################
# 6.2.在项目下目录pages/classic,修改文件 classic.js
import { ClassicModel } from '../../models/classic.js'
import { LikeModel } from '../../models/like.js'
let classicModel = new ClassicModel()
let likeModel = new LikeModel()
Page({
/**
* 页面的初始数据
*/
data: {
classic:null
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
classicModel.getLatest((res) => {
this.setData({
classic:res
})
})
},
// 自定义函数
onLike: function(event) {
console.log(event)
let behavior = event.detail.behavior
likeModel.like(behavior, this.data.classic.id, this.data.classic.type)
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
######################
# 6.3.在项目下目录utils,修改文件 http.js,判断如果没有返回success信息,params.success && params.success(res.data)
import { config } from '../config.js'
const tips = {
1: '抱歉,出现了一个错误',
1005: 'appkey无效,请前往www.7yue.pro申请',
3000: '期刊不存在'
}
class HTTP {
request(params) {
// params 包括 url, data, method,
if (!params.method) {
params.method = "GET"
}
wx.request({
url:config.api_base_url + params.url,
method:params.method,
data:params.data,
header: {
'content-type':'application/json',
'appkey':config.appkey
},
success:(res) => {
// startsWith
// endsWith
// res.statusCode 返回的是一个数字不是字符串
let code = res.statusCode.toString()
if (statusCode.startsWith('2')) {
params.success && params.success(res.data)
} else {
let error_code = res.data.error_code
this._show_error(error_code)
}
},
fail:(err) => {
this._show_error(1)
}
})
}
// 用_开头表示私有方法
_show_error(error_code) {
if (!error_code) {
error_code = 1
}
wx.showToast({
title: tips[error_code],
icon: 'none',
duration: 2000
})
}
}
export { HTTP }
############################################
# 7.组件的生命周期函数
######################
# 7.1.在项目下目录components,新建目录epsoide
######################
# 7.2.在项目下目录components/epsoide,新建component,名字为index
######################
# 7.3.在项目下目录components/epsoide,修改文件 index.js
Component({
/**
* 组件的属性列表
*/
properties: {
index: Number
},
/**
* 组件的初始数据
*/
data: {
year: Number,
month: String
},
/**
* 组件的方法列表
*/
methods: {
}
})
######################
# 7.4.在项目下目录components/epsoide,修改文件 index.wxml
<view class="container">
<text>No.</text>
<text>{{index}}</text>
<text>|</text>
<text>{{month}}</text>
<text>{{year}}</text>
</view>
######################
# 7.5.在项目下目录pages/classic/,修改文件classic.json,引入组件 epsoide
{
"usingComponents": {
"v-like":"/components/like/index",
"v-movie":"/components/classic/movie/index",
"v-epsoide":"/components/epsoide/index"
}
}
######################
# 7.6.在项目下目录pages/classic/,修改文件classic.wxml,添加组件 epsoide
<v-epsoide />
<v-like bind:like="onLike" like="{{classic.like_status}}" count="{{classic.fav_nums}}" />
<v-movie img="{{classic.image}}" content="{{classic.content}}" />
######################
# 7.7.查看data里面的year和month为什么没有显示出来?另外为什么打印properties和data,打印出来的结果都是一样的?
Component({
/**
* 组件的属性列表
*/
properties: {
// 这里有默认值0,这里为什么可以有默认值,原因是经过小程序特殊处理
index: Number
},
/**
* 组件的初始数据
*/
data: {
// year和month没有默认值,打印出来的结果表示是内置函数,一个是String,一个是Number
// year: Number,
// month: String
// 如果需要默认值只能如下设置
year: 0,
month: ''
},
// 通过生命周期函数测试一下
attached:function() {
// 通过这里打印出
// 结果
// {year: ƒ, month: ƒ, index: 0}
// {year: ƒ, month: ƒ, index: 0}
console.log(this.properties)
console.log(this.data)
// 结果
// function
// ƒ Number() { [native code] }
console.log(typeof(Number))
console.log(Number)
},
/**
* 组件的方法列表
*/
methods: {
}
})
############################################
# 8.业务逻辑到底写组件里还是页面里
#####################
# 8.1.在项目下目录pages/classic/,修改文件classic.wxml,在组件epsoide添加属性index
<v-epsoide index="{{classic.index}}" />
<v-like bind:like="onLike" like="{{classic.like_status}}" count="{{classic.fav_nums}}" />
<v-movie img="{{classic.image}}" content="{{classic.content}}" />
#####################
# 8.2.出现问题,月份1-9是需要在前面补零,应该如何处理,是写在组件中还是页面,由于这是组件的,所以需要写在组件中
############################################
# 9.observer函数的应用
#####################
# 9.1.在项目下目录components/epsoide,修改文件 index.js,通过添加observer可以确定newVal可以拿到改变的数值
properties: {
// 这里有默认值0,这里为什么可以有默认值,原因是经过小程序特殊处理
index: {
type: Number,
observer: function(newVal, oldVal, changedPath) {
// 确定newVal可以拿到改变的数值
// console.log(newVal)
// console.log(oldVal)
// console.log(changedPath)
let val = newVal < 10 ? '0' + newVal : newVal
this.setData({
index: val
})
}
}
},
# 9.2.但是又出现问题,页面月份数字前面如果少于9还是无法在前面加多一个0,原因是什么?
############################################
# 10.注意防范内存泄漏
#####################
# 10.1.猜测是否val变量不正确,但是通过console.log(val)发现是对的
properties: {
index: {
type: Number,
observer: function(newVal, oldVal, changedPath) {
let val = newVal < 10 ? '0' + newVal : newVal
console.log(val)
this.setData({
index: val
})
}
}
},
#####################
# 10.2.如果把index写死成一个值,例如:index:'1111111',发现页面是可以显示的,如果改成index:'08'发现页面只显示8
properties: {
index: {
type: Number,
observer: function(newVal, oldVal, changedPath) {
let val = newVal < 10 ? '0' + newVal : newVal
this.setData({
index: '08'
})
}
}
},
#####################
# 10.3.如果把index的类型改成String,index依然写死成index:'08',页面上可以显示了
properties: {
index: {
type: String,
observer: function(newVal, oldVal, changedPath) {
let val = newVal < 10 ? '0' + newVal : newVal
this.setData({
index: '08'
})
}
}
},
#####################
# 10.4.index改使用变量,页面出现很多0,调试器疯狂的报错,出现这个问题的原因是出现了无限递归,内存泄露
properties: {
index: {
type: String,
observer: function(newVal, oldVal, changedPath) {
let val = newVal < 10 ? '0' + newVal : newVal
this.setData({
index: val
})
}
}
},
############################################
# 11.千万不要在observer中修改自身属性
######################
# 11.1.产生问题的原因是,修改的地方本来就是更新index属性,现在又在监听中调用setData更新属性,所以产生无限递归调用
######################
# 11.2.无法改变的原因是,type这个变量的值是8,setData改变为08之后,小程序会自动把08变回8,因为数值没有改变就无法再次调用observer
######################
# 11.3.如何解决这个问题呢?通过data,因为最终properties和data会合并,所以data中index名字不能和properties一样
######################
# 11.4.在项目下目录components/epsoide,修改文件index.js
/**
* 组件的属性列表
*/
properties: {
index: {
type: String,
observer: function(newVal, oldVal, changedPath) {
let val = newVal < 10 ? '0' + newVal : newVal
this.setData({
_index: val
})
}
}
},
/**
* 组件的初始数据
*/
data: {
year: 0,
month: '',
_index: ''
},
######################
# 11.5.在项目下目录components/epsoide,修改文件index.wxml
<view class="container">
<text>No.</text>
<text>{{_index}}</text>
<text>|</text>
<text>{{month}}</text>
<text>{{year}}</text>
</view>
######################
# 11.6.其实这不是最佳方案,wxs才是最好的解决方案
############################################
# 12.epsoide组件与流行页面样式
# 12.1.注意
# 1.小程序css中只能使用class不能使用id
# 2.组件里的样式container的高度取决于index的文字高度
# 3.组件里的样式index里使用line-height来限制行高度
# 4.组件里为什么竖线不用文字而用view,原因是flex的baseline的底线对齐对文字是无效的
# 5.classic里的显示需要垂直居中(align-items:center)
# 6.classic里的显示两端对齐,项目之间的间隔都相等(justify-content: space-between)
######################
# 12.2.在项目下目录components/epsoide,修改文件index.js
Component({
/**
* 组件的属性列表
*/
properties: {
index: {
type: String,
observer: function(newVal, oldVal, changedPath) {
let val = newVal < 10 ? '0' + newVal : newVal
this.setData({
_index: val
})
}
}
},
/**
* 组件的初始数据
*/
data: {
months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
year: 0,
month: '',
_index: ''
},
// 通过生命周期函数测试一下
attached: function() {
let date = new Date()
let year = date.getFullYear()
let month = date.getMonth()
this.setData({
year: year,
month: this.data.months[month]
})
},
/**
* 组件的方法列表
*/
methods: {
}
})
######################
# 12.3.在项目下目录components/epsoide,修改文件index.wxml
<view class="container">
<view class="index-container">
<text class="plain">No.</text>
<text class="index">{{_index}}</text>
<view class="line"></view>
</view>
<view class="date-container">
<text class="month">{{month}}</text>
<text class="year">{{year}}</text>
</view>
</view>
######################
# 12.4.在项目下目录components/epsoide,修改文件index.wxss
.container {
height: 60rpx;
display: inline-flex;
flex-direction: row;
}
.index-container {
display: flex;
flex-direction: row;
align-items: baseline;
}
.plain {
font-size: 32rpx;
}
.index {
font-size: 60rpx;
line-height: 60rpx;
font-weight: 800;
margin-right: 14rpx;
}
.line {
height: 44rpx;
margin-right: 14rpx;
border-left: 1px solid black;
}
.date-container {
display: flex;
flex-direction: column;
margin-top: 6rpx;
}
.month {
font-size: 24rpx;
line-height: 24rpx;
}
.year {
font-size: 20rpx;
}
######################
# 12.5.在项目下目录pages/classic/,修改文件classic.wxml
<view class="header">
<v-epsoide class="epsoide" index="{{classic.index}}" />
<v-like class="like" bind:like="onLike" like="{{classic.like_status}}" count="{{classic.fav_nums}}" />
</view>
<v-movie img="{{classic.image}}" content="{{classic.content}}" />
######################
# 12.6.在项目下目录pages/classic/,修改文件classic.wxss
.header {
display: flex;
flex-direction: row;
height: 100rpx;
align-items: center;
justify-content: space-between;
border-top: 1px solid #f5f5f5;
border-bottom: 1px solid #f5f5f5;
}
.epsoide {
margin-left: 20rpx;
margin-top: 4rpx;
}
.like {
margin-top: 6rpx;
}
12.Behavior行为与加入缓存系统优化流行页面
###########################################################################################
# 1.navi组件与移动端触碰区域讨论
###############################################
# 1.1.在项目下目录components,新建目录navi
###############################################
# 1.2.在项目下目录components/navi,新建component,名字为navi
###############################################
# 1.3.在项目下目录components/navi,新建目录images
###############################################
# 1.4.在项目下目录components/navi,修改文件index.wxml
<view>
<image src="{{latest?disLeftSrc:leftSrc}}" />
<text>{{title}}</text>
<image src="{{first?disRightSrc:rightSrc}}" />
</view>
###############################################
# 1.5.在项目下目录components/navi,修改文件index.js
Component({
/**
* 组件的属性列表
*/
properties: {
title: String,
first: Boolean,
latest: Boolean
},
/**
* 组件的初始数据
*/
data: {
disLeftSrc: 'images/triangle.dis@left.png',
leftSrc: 'images/triangle@left.png',
disRightSrc: 'images/triangle.dis@right.png',
rightSrc: 'images/triangle@right.png'
},
/**
* 组件的方法列表
*/
methods: {
}
})
###############################################
# 1.6.在项目下目录pages/classic,修改文件classic.json
{
"usingComponents": {
"v-like":"/components/like/index",
"v-movie":"/components/classic/movie/index",
"v-epsoide":"/components/epsoide/index",
"v-navi": "/components/navi/index"
}
}
###############################################
# 1.7.在项目下目录pages/classic,修改文件classic.wxml
<view class="header">
<v-epsoide class="epsoide" index="{{classic.index}}" />
<v-like class="like" bind:like="onLike" like="{{classic.like_status}}" count="{{classic.fav_nums}}" />
</view>
<v-movie img="{{classic.image}}" content="{{classic.content}}" />
<v-navi />
###############################################
# 1.8.在项目下目录components/navi,修改文件index.wxml
<view class="container">
<image class="icon" src="{{latest?disLeftSrc:leftSrc}}" />
<text class="title">{{title}}</text>
<image class="icon" src="{{first?disRightSrc:rightSrc}}" />
</view>
###############################################
# 1.9.在项目下目录components/navi,修改文件index.wxss
.container {
width: 600rpx;
height: 80rpx;
background-color: #f7f7f7;
border-radius: 2px;
display: inline-flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.icon {
height: 80rpx;
width: 80rpx;
}
.title {
font-size: 28rpx;
}
###############################################
# 1.10.可触碰区域,这点对于用户体验非常重要
1.设计师可以把按钮的图片白色区域切大一些,留出一部分空间给用户点击
2.如果设计师切片范围刚刚好,程序员就需要通过写代码扩大可触碰范围
###########################################################################################
# 2.navi组件与flex宽度陷阱
###############################################
# 2.1.在项目下目录pages/classic,修改文件classic.wxml
<view class="container">
<view class="header">
<v-epsoide class="epsoide" index="{{classic.index}}" />
<v-like class="like" bind:like="onLike" like="{{classic.like_status}}" count="{{classic.fav_nums}}" />
</view>
<v-movie img="{{classic.image}}" content="{{classic.content}}" />
<v-navi class="navi" />
</view>
###############################################
# 2.2.在项目下目录pages/classic,修改文件classic.wxss
1.解决组件v-navi居中的问题,
2.如果最外面的view,可以确定width=100%,最好写上,可以提早解决很多奇怪的问题,这里主要是container和header
.container {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.header {
width: 100%;
display: flex;
flex-direction: row;
height: 100rpx;
align-items: center;
justify-content: space-between;
border-top: 1px solid #f5f5f5;
border-bottom: 1px solid #f5f5f5;
}
.epsoide {
margin-left: 20rpx;
margin-top: 4rpx;
}
.like {
margin-top: 6rpx;
}
.navi {
position: absolute;
bottom: 40rpx;
}
###############################################
# 2.3.在项目下目录pages/classic,修改文件classic.wxml,first和latest的值如何获取呢?
<view class="container">
<view class="header">
<v-epsoide class="epsoide" index="{{classic.index}}" />
<v-like class="like" bind:like="onLike" like="{{classic.like_status}}" count="{{classic.fav_nums}}" />
</view>
<v-movie img="{{classic.image}}" content="{{classic.content}}" />
<v-navi title="{{classic.title}}" first="{{first}}" latest="{{latest}}" class="navi" />
</view>
###############################################
# 2.4.在项目下目录pages/classic,修改文件classic.js,可通过getLatest
import {
ClassicModel
} from '../../models/classic.js'
import {
LikeModel
} from '../../models/like.js'
let classicModel = new ClassicModel()
let likeModel = new LikeModel()
Page({
/**
* 页面的初始数据
*/
data: {
classic: null,
latest: true,
first: false
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
classicModel.getLatest((res) => {
this.setData({
classic: res
})
})
},
// 自定义函数
onLike: function(event) {
console.log(event)
let behavior = event.detail.behavior
likeModel.like(behavior, this.data.classic.id, this.data.classic.type)
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function() {
}
})
###########################################################################################
# 3.禁用事件的技巧
###############################################
# 3.1.小程序接口必须是https协议,测试可以用http
###############################################
# 3.2.问题1,如何知道用户点击了navi主件?采用事件监听
###############################################
# 3.3.问题2,如何知道用户点击了是左箭头还是右箭头?采用事件监听
###############################################
# 3.4.问题3,如果左箭头是最左的,往下再也没有更多的页面,或者如果右箭头已经是最右的,下面再也没有更多的页面,此时不应该产生事件如何解决?在组件事件中加判断
###############################################
# 3.5.在项目下目录components/navi,修改文件index.wxml,解决第一、二个问题
<view class="container">
<image bind:tap="onLeft" class="icon" src="{{latest?disLeftSrc:leftSrc}}" />
<text class="title">{{title}}</text>
<image bind:tap="onRight" class="icon" src="{{first?disRightSrc:rightSrc}}" />
</view>
###############################################
# 3.6.在项目下目录components/navi,修改文件index.js,解决第一、二个问题
Component({
/**
* 组件的属性列表
*/
properties: {
title: String,
first: Boolean,
latest: Boolean
},
/**
* 组件的初始数据
*/
data: {
disLeftSrc: 'images/triangle.dis@left.png',
leftSrc: 'images/triangle@left.png',
disRightSrc: 'images/triangle.dis@right.png',
rightSrc: 'images/triangle@right.png'
},
/**
* 组件的方法列表
*/
methods: {
onLeft:function() {
this.triggerEvent('left', {}, {})
},
onRight:function() {
this.triggerEvent('right', {}, {})
}
}
})
###############################################
# 3.7.在项目下目录pages/classic,修改文件classic.wxml,解决第一、二个问题
<view class="container">
<view class="header">
<v-epsoide class="epsoide" index="{{classic.index}}" />
<v-like class="like" bind:like="onLike" like="{{classic.like_status}}" count="{{classic.fav_nums}}" />
</view>
<v-movie img="{{classic.image}}" content="{{classic.content}}" />
<v-navi bind:left="onNext" bind:right="onPrevious" title="{{classic.title}}" first="{{first}}" latest="{{latest}}" class="navi" />
</view>
###############################################
# 3.8.在项目下目录components/navi,修改文件index.js,加判断解决第三个问题
Component({
/**
* 组件的属性列表
*/
properties: {
title: String,
first: Boolean,
latest: Boolean
},
/**
* 组件的初始数据
*/
data: {
disLeftSrc: 'images/triangle.dis@left.png',
leftSrc: 'images/triangle@left.png',
disRightSrc: 'images/triangle.dis@right.png',
rightSrc: 'images/triangle@right.png'
},
/**
* 组件的方法列表
*/
methods: {
onLeft:function() {
if (!this.properties.latest) {
this.triggerEvent('left', {}, {})
}
},
onRight:function() {
if (!this.properties.first) {
this.triggerEvent('right', {}, {})
}
}
}
})
###########################################################################################
# 4.music组件初步实现
###############################################
# 4.1.在项目下目录pages/classic,修改文件classic.js,添加两个事件
onNext: function(event) {
},
onPrevious: function(event) {
},
###############################################
# 4.2.在项目下目录components/classic,新建目录music
###############################################
# 4.3.在项目下目录components/classic,新建component,名字为music
###############################################
# 4.4.在项目下目录components/classic/music,新建目录images
###############################################
# 4.5.在项目下目录components/classic/music/images拷贝图片3张
###############################################
# 4.6.在项目下目录components/classic/music,修改文件index.wxml
<view>
<image src="{{img}}" />
<image src="{{playSrc}}" />
<image src="images/music@tag.png"/>
<text>{{content}}</text>
</view>
###############################################
# 4.7.在项目下目录components/classic/music,修改文件index.js
Component({
/**
* 组件的属性列表
*/
properties: {
img: String,
content: String
},
/**
* 组件的初始数据
*/
data: {
pauseSrc: 'images/player@waitting.png',
playSrc: 'images/player@playing.png'
},
/**
* 组件的方法列表
*/
methods: {
}
})
###########################################################################################
# 5.初识组件的behavior行为
###############################################
# 5.1.在项目下目录components/classic,新建目录essay
###############################################
# 5.2.在项目下目录components/classic,新建component,名字为index
###############################################
# 5.3.在项目下目录components/classic/essay,新建目录images
###############################################
# 5.4.在项目下目录components/classic/essay/images拷贝图片1张
###############################################
# 4.5.在项目下目录components/classic/essay,修改文件index.js
Component({
/**
* 组件的属性列表
*/
properties: {
img: String,
content: String
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
}
})
###############################################
# 5.3.在项目下目录components/classic/,新建文件classic-beh.js,使用behavior定义公用组件
let classicBeh = Behavior({
properties: {
img: String,
content: String
},
})
export {
classicBeh
}
###############################################
# 5.4.在项目下目录components/classic/essay,修改文件index.js,导入behavior公用组件
import {
classicBeh
} from '../classic-beh.js'
Component({
/**
* 组件的属性列表
*/
behaviors: [classicBeh],
properties: {},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
}
})
###############################################
# 5.5.在项目下目录components/classic/music,修改文件index.js,导入behavior公用组件
import {
classicBeh
} from '../classic-beh.js'
Component({
/**
* 组件的属性列表
*/
behaviors: [classicBeh],
properties: {},
/**
* 组件的初始数据
*/
data: {
pauseSrc: 'images/player@waitting.png',
playSrc: 'images/player@playing.png'
},
/**
* 组件的方法列表
*/
methods: {
}
})
###############################################
# 5.6.在项目下目录components/classic/movie,修改文件index.js,导入behavior公用组件
import {
classicBeh
} from '../classic-beh.js'
Component({
/**
* 组件的属性列表
*/
behaviors: [classicBeh],
properties: {},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
}
})
###########################################################################################
# 6.behavior继承与多继承的覆盖规则
# 1.子类会覆盖父类
# 2.如果多个继承,多个父类有同名属性,子类会继承最后一个,例如: behaviors:[beh1, beh2, beh3],会继承beh3
# 3.有特例,生命周期函数不会覆盖,会依次从每一个父类调用生命周期函数,最后还调用子类生命周期函数
###########################################################################################
# 7.初步实现期刊切换
###############################################
# 7.1.在项目下目录components/classic/essay,修改文件index.wxml
<view class="classic-container">
<image class="class-image" src="{{img}}" />
<image class="tag" src="images/essay@tag.png"/>
<text class="content">{{content}}</text>
</view>
###############################################
# 7.2.在项目下目录models,修改文件classic.js,添加方法 getPrevious
import {HTTP} from '../utils/http.js'
class ClassicModel extends HTTP {
getLatest(sCallback) {
this.request({
url: 'classic/latest',
success: (res) => {
sCallback(res)
}
})
}
getPrevious(index, sCallback) {
this.request({
url: 'classic/' + index + '/previous',
success: (res) => {
sCallback(res)
}
})
}
}
export {ClassicModel}
###############################################
# 7.3.在项目下目录pages/classic,修改文件classic.js,实现方法 getPrevious
onPrevious: function(event) {
let index = this.data.classic.index
classicModel.getPrevious(index, (res) => {
// console.log(res)
this.setData({
classic: res
})
})
},
###########################################################################################
# 8.是否是最新期刊的逻辑判断
###############################################
# 8.1.在项目下目录models,修改文件classic.js,添加方法 isFirst 和 isLatest
import {HTTP} from '../utils/http.js'
class ClassicModel extends HTTP {
getLatest(sCallback) {
this.request({
url: 'classic/latest',
success: (res) => {
sCallback(res)
}
})
}
getPrevious(index, sCallback) {
this.request({
url: 'classic/' + index + '/previous',
success: (res) => {
sCallback(res)
}
})
}
isFirst(index) {
return index == 1 ? true : false
}
isLatest(index) {
return index == 8 ? true : false
}
}
export {ClassicModel}
###########################################################################################
# 9.使用Storage保存最新期刊号
###############################################
# 9.1.在项目下目录models,修改文件classic.js,添加方法 _setLatestIndex 和 _getLatesIndex,修改方法 getLatest 和 isLatest
import {HTTP} from '../utils/http.js'
class ClassicModel extends HTTP {
getLatest(sCallback) {
this.request({
url: 'classic/latest',
success: (res) => {
sCallback(res)
this._setLatestIndex(res.index)
}
})
}
getPrevious(index, sCallback) {
this.request({
url: 'classic/' + index + '/previous',
success: (res) => {
sCallback(res)
}
})
}
isFirst(index) {
return index == 1 ? true : false
}
isLatest(index) {
let latestIndex = this._getLatesIndex()
return latestIndex == index ? true : false
}
_setLatestIndex(index) {
wx.setStorageSync('latest', index)
}
_getLatesIndex() {
let index = wx.getStorageSync('latest')
return index
}
}
export {ClassicModel}
###############################################
# 9.2.测试前清空缓存以保证不会出现由于曾写入缓存数据导致的异常
###########################################################################################
# 10.onNext与函数重构技巧
###############################################
# 10.1.由于next和prevous的代码很多都相同,对两个方法进行合并
###############################################
# 10.2.在项目下目录models,修改文件classic.js,方法 getPrevious 改名为 getClassic,方法添加多一个参数,修改代码内容
import {HTTP} from '../utils/http.js'
class ClassicModel extends HTTP {
getLatest(sCallback) {
this.request({
url: 'classic/latest',
success: (res) => {
sCallback(res)
this._setLatestIndex(res.index)
}
})
}
getClassic(index, nextOrPrevious, sCallback) {
this.request({
url: 'classic/' + index + '/' + nextOrPrevious,
success: (res) => {
sCallback(res)
}
})
}
isFirst(index) {
return index == 1 ? true : false
}
isLatest(index) {
let latestIndex = this._getLatesIndex()
return latestIndex == index ? true : false
}
_setLatestIndex(index) {
wx.setStorageSync('latest', index)
}
_getLatesIndex() {
let index = wx.getStorageSync('latest')
return index
}
}
export {ClassicModel}
###############################################
# 10.3.在项目下目录pages/classic,修改文件classic.js,添加方法 _updateClassic,修改方法 onNext 和 onPrevious
import {
ClassicModel
} from '../../models/classic.js'
import {
LikeModel
} from '../../models/like.js'
let classicModel = new ClassicModel()
let likeModel = new LikeModel()
Page({
/**
* 页面的初始数据
*/
data: {
classic: null,
latest: true,
first: false
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
classicModel.getLatest((res) => {
this.setData({
classic: res
})
console.log(this.data)
// latestClassic latestIndex
// currentClassic currentIndex
})
},
// 自定义函数
onLike: function(event) {
console.log(event)
let behavior = event.detail.behavior
likeModel.like(behavior, this.data.classic.id, this.data.classic.type)
},
onNext: function(event) {
this._updateClassic('next')
},
onPrevious: function(event) {
this._updateClassic('previous')
},
_updateClassic: function (nextOrPrevious) {
let index = this.data.classic.index
classicModel.getClassic(index, nextOrPrevious, (res) => {
// console.log(res)
this.setData({
classic: res,
latest: classicModel.isLatest(res.index),
first: classicModel.isFirst(res.index)
})
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function() {
}
})
###############################################
# 10.4.每一次点击都会向服务器发送请求,这样的请求很多情况下是不需要的,用户体验差,需要加入缓存机制
posted on 2020-04-21 09:39 herisson_pan 阅读(9) 评论(0) 收藏 举报
浙公网安备 33010602011771号