小程序常用知识-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)    收藏  举报

导航