Mock缺少与服务器交换数据的行为。
json中的最后一行的 逗号(,)不能保留。json格式下,键值都应该是双引号。
微信小程序---model弹窗:<model></model>标签
tabBar
json 的 pages 数组中排第一个的页面必须是 tabbar 的第一个标签的主页
请注意switchTab只能跳转到带有tab的页面,不能跳转到不带tab的页面!跳转不带tab的页面还是需要使用redirect或者navigate!
page.json
每一个小程序页面也可以使用.json
文件来对本页面的窗口表现进行配置。页面的配置比app.json
全局配置简单得多,只是设置 app.json 中的 window 配置项的内容,页面中配置项会覆盖 app.json 的 window 中相同的配置项。
页面的.json
只能设置window
相关的配置项,以决定本页面的窗口表现,所以无需写window
这个键
bindtap
小程序中,全用bindtap(bind+event),或者catchtap(catch+event)绑定事件,例如:
跳转其他页面,并传递一个参数:
一个超级简单的布局:....
/* pages/classify/classify.wxss */
.title {
display: flex;
justify-content: center;
height: 80rpx;
line-height: 80rpx;
}
.text {
color:#ccc;
font-size:30rpx;
padding: 0 20rpx;
}
.line {
position: relative;
top: 40rpx;
width: 30rpx;
border-top: 1px solid #ccc;
}
还有一个超级简单的布局 :多份图片文字都居中
.container {
display: flex;
justify-content: space-around;
}
.container .item {
width: 20%;
text-align: center;
border: 1px solid #ccc;
}
.container .item image{
width: 100%;
height: 80rpx;
}
.container .item view{
font-size:26rpx;
}
flex布局:
flex-direction: column; //排列方向
justify-content: space-around; //主轴对齐方向: 每个元素两侧的距离均相等
align-items:center; //交叉轴对齐方向:根据flex-direction判断
1. 基础布局
.container {
display: flex;
flex-direction: column;
justify-content: space-around;
align-items:center;
height: 400px;
background-color:blue;
}
2. wrap 换行及根据高度计算消除多余的间距
.container {
display: flex;
flex-direction: row;
justify-content: space-around;
align-items:flex-start;
flex-wrap: wrap;
height: 200px;
background-color:blue;
}
.chunk {
width: 150px;
height: 100px;
}
小程序:
1. 首页注意细节
点击到最后一期期刊时,箭头无法再点击。
通过本地缓存,读取期刊数据(而不是每次点击去请求服务端)。
2. 搜索页
头部搜索固定顶部。
点击搜索后,内容直接覆盖搜索页。
加载更多loading功能。
3. 其余
分享功能。
小程序跳转其他小程序。
<image> 标签引入图片时,需要设置高度和宽度。否则就是默认的宽高(宽320px;高240px))
小程序尺寸单位与设计原则:
rpx自适应尺寸。(当设计师以iphone6为设计稿标准时,标注的尺寸与rpx为1:1,而px则需要设置为标注的一半)。
情况:字体的大小假如不希望随机型改变。border边框。
只有很少的css样式可以被组件继承。
文字本身有空白间距。(设置和文字相同的line-height就能够消除)。
设置diaplay:inline-flex; 自适应宽度。
bind:tap(触摸事件,阻止点击冒泡)。
一般setData方法多用于点击后改变页面信息或者刷新后与后台交互获取最新的信息
注意:
- 直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致
- 单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。
组件内部的数据就直接写在data中(组件的内部数据),需要开放出来的数据写在properties属性中(组件的对外属性)。
wx.request(Object):
1. 只要服务器返回了结果(而不管结果是成功还是失败),都是执行success回调函数。需要在小程序的后台账号中添加要访问的域名。
2. 是一个异步函数,如果直接对这个赋值是取不到结果的。
3. 涉及到this的指代问题:可以直接在回调中使用箭头函数解决作用域的问题。获取异步的数据
success:(res)=>{
console.log(this.data.test)
}
ES6的新语法:模块化的导入和导出
导出:新建一个config.js文件,写入:
const config = {
api_base_url: 'http://bl.7yue.pro/v1/',
appkey: 'KOLDaSADSDLWWbF'
}
export {config}
导入:新建util/http.js,写入:
import {config} from '/config.js'
将API的调用封装成一个类:
ES5只有indexOf方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6又提供了三种新方法。
includes():返回布尔值,表示是否找到了参数字符串;
startsWith():返回布尔值,表示参数字符串是否在查找字符串的头部;
endsWith():返回布尔值,表示参数字符串是否在查找字符串的尾部。
let s = 'Hello world!'; s.indexOf('e') //1 s.startsWith('Hello') // true s.endsWith('!') // true s.includes('o') // true
同时这三个方法都支持第二个参数,表示开始搜索的位置。
在import时只能使用相对路径,而组件中是可以使用绝对路径的。
import {config} from '../config.js'
class HTTP{
// 类中的方法
request(params) {
// 如果没有指定方法,就默认是GET
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)=>{
let code = res.statusCode.toString()
// 如果是2开头则调用成功的方法,startsWith
if(code.startsWith('2')){
params.success(res.data)
}else{
}
},
fail:(err)=> {
}
})
}
}
export {HTTP}
在classify/classify.js中使用:使用自定义的类的方法
import {HTTP} from '../../util/http.js'
let http= new HTTP()
Page({
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
http.request({
url:'classic/latest',
success:(res)=>{
console.log(res)
}
})
// wx.request({
// url: 'http://bl.7yue.pro/v1/classic/latest',
// header: {
// appkey: 'KOLDaSADSDLWWbF'
// },
// success:(res)=>{
// console.log(this.data.test)
// }
// })
}
})
增加API调用时的错误异常处理:util/http.js:增加了一个私有方法去显示错误信息
import {config} from '../config.js'
const tip = {
1: '抱歉,出现一个错误了', //作为默认的错误提示
1005: 'appkey无效,申请一个咯',
3000:'期刊不存在'
}
class HTTP{
// 类中的方法
request(params) {
// 发起微信请求
wx.request({
success:(res)=>{
let code = res.statusCode.toString()
// 如果是2开头则调用成功的方法,startsWith
if(code.startsWith('2')){
params.success && params.success(res.data)
}else{
let error_code = res.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: tip[error_code],
icon:'none',
duration:2000
})
}
}
export {HTTP}
改写获取数据的方法:models/classic.js : 通过扩展HTTP这个类
import {HTTP} from '../util/http.js'
// 拓展一个类的方法,获取数据
class ClassModel extends HTTP {
// 在方法中调用回调函数
getLatest(sCallback) {
this.request({
url: 'classic/latest',
success: (res) => {
sCallback(res)
}
})
}
}
export {ClassModel}
同时获取数据的方法就可以改成:pages/classify/classify.js:在实例化的方法中使用箭头函数调用结果。
import {ClassModel} from '../../models/classic.js'
let classic= new ClassModel()
Page({
onLoad: function (options) {
classic.getLatest((res)=>{
})
}
})
通过回调函数获得调用的结果。
在组件中设置自定义事件:this.triggerEvent("like",{},{})
1. 通知页面,用户点击了这个组件
2. 并且需要附加一个状态:用户的行为
组件的自定义事件:this.triggerEvent("like",{},{}) 事件名就是like
// 激活事件
let behavior = this.properties.like ? 'like' : 'cancel'
this.triggerEvent("like", {
behavior //改变事件中detail的值
}, {})
然后在页面中通过bind:like=“like” 绑定自定义的事件。
models/like.js中写POST请求:
import { HTTP } from '../util/http.js'
// 拓展一个类的方法,获取数据
class LikeModel extends HTTP {
// 在方法中调用回调函数
like(behavior, artID, category ) {
let url = behavior == "like" ? "like" : "like/cancel"
this.request({
url: url,
method: 'POST',
data: {
art_id: artID,
type: category
}
})
}
}
export { LikeModel }
父组件中调用:
onLike: function (event) {
console.log(event)
let behavior = event.detail.behavior
likeModel.like(behavior, this.data.classicData.id, this.data.classicData.type)
},
在data中的字符串初始化应为: ''表示。数字就用:0表示。
组件的observer函数,在改变属性值之后会自动调用和这个函数:
(不能在属性properties中的observer中改变自身的值,否则会发生无限递归):利用wxs可以解决。
// components/expore/index.js
Component({
/**
* 组件的属性列表
*/
properties: {
index: {
type: String,
oberver:function(newVal,oldVal,changePath) {
let val = newVal < 10? '0'+newVal : newVal
this.setData({
_index:val
})
}
}
},
/**
* 组件的初始数据
*/
data: {
_index:''
},
})
5. input封装为内置组件
对于将 input
封装在自定义组件中、而 form
在自定义组件外的情况, form
将不能获得这个自定义组件中 input
的值。此时需要使用自定义组件的内置behavior wx://form-field
。
form表单:
<form bindsubmit="formSubmit">
表单
<!-- 自定义的input组件 只需要在这个自定义的组件中加上name属性即可,不需要在组件中的input上加name属性 -->
<my-input name="test"></my-input>
<button form-type="submit">提交</button>
</form>
自定义input组件:
<!-- 自定义input组件 -->
<view>
<!-- 这里不需要设置name属性,而是在调用组件时,添加name属性。如<my-input name="test"></my-input> -->
<input bindinput="getInputValue"></input>
</view>
提示:behaviors的功能相当于组件之间公用代码,里面有公用的属性、方法。可以把behavior当做构造函数,别的组件能使用这个behavior的方法和数据。
Component({
behaviors: ['wx://form-field'], //wx://form-field 代表一个内置 behavior ,它使得这个自定义组件有类似于表单控件的行为。
properties: {
// value:{ //其实要在自定义input组件中设置固定(默认)值,可以直接在properties中设置,不用在attached中调用setData设置
// type: String,
// value: '1' // 默认值为 1
// }
},
attached() {
// this.setData({
// value: '官网给出的例子:在attached生命周期设置的value值是固定的,所以我在input失去焦点时,设置value值'
// })
},
methods:{
getInputValue (e) {
this.setData({
value: e.detail.value // behaviors: ['wx://form-field']里面就有设置value属性,所以我们可以直接拿来设置value
})
}
}
})