小程序目录结构
要弄清除小程序,先必须弄清除小程序开发工具创建项目的目录结构是什么样的
1、pages
目录用于存放所有的页面,相当于是vue中的views目录
2、index
目录相当于是一个具体的页面,它内部有4个文件
3、index.wxml
相当于vue文件中 <template></template>
部分,用于存放标签,相当于html
4、index.wxss
相当于vue文件中 <style scoped>
部分,用于存放样式代码,相当于css
5、index.js
相当于vue文件中 <script>
部分 ,用于存放脚本代码
6、index.json
用于存放相关配置信息,比如这个页面使用了哪些组件哪些插件
7、utils
目录用于存放一些第三方工具类,默认里面有创建一个日期格式化的方法
8、app.js
整个小程序的入口文件,相当于是vue当中app.vue这个文件中的脚本代码
9、app.wxss
小程序的全局样式
10、project.config.json
这个是小程序项目的配置信息
11、sitemap.json
是小程序后期做分包加载的时候使用的,因为小程序代码总体不能超过2M,如果项目过大就要考虑分包开发
12、app.json
小程序的配置信息,这里面主要配置的titleBar,tabber以及页面相关信息
小程序配置
小程序的整个配置信息都再app.json这个文件啊里面,我们来研究一下
{
"pages":[
"pages/index/index",
"pages/logs/logs"
],
"window":{
"backgroundTextStyle":"dark",
"navigationBarBackgroundColor": "#f00",
"navigationBarTitleText": "hahaha",
"navigationBarTextStyle":"white"
},
"style": "v2",
"sitemapLocation": "sitemap.json"
}
pages
相当于路由,代表当前小程序有多少个页面,如果后期有新增或者删除都要在这里做相应的操作
window
整个小程序的页面配置信息
- backgroundTextStyle 导航栏背景的文字样式设置 ,只有light和dark
- navigationBarBackgroundColor 导航栏背景颜色
- navigationBarTitleText 导航栏的文字
- navigationBarTextStyle导航栏文字的颜色,只有white和black
小程序的组件
小程序基于组件化开发 的,所以它没有DOM,更没有BOM,也就是说没有document,更没有window,它只有ES,并且也没有html标签,全都是一个组件也就是虚拟DOM
简单认识几个
组件名 | html标签 | 备注 |
---|---|---|
块元素 | ||
|
行内元素 | |
图片标签 | ||
按钮 | ||
超链接 |
其他组件可以参考开发文档
button | 微信开放文档 (qq.com)
小程序语法
小程序的框架语法主要在js上面,所以我们打开一个js文件
// pages/index/index.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
小程序框架采用MVVM的开发模式,所以这一套东西与之前的vue差不多,但是又部分区别
data
这个与之前学习的vue2语法中的data是一样的,页面上会用到的数据都在这里
onLoad
小程序页面的钩子函数,相当于vue的created
onReady
相当于vue的beforeMount
onShow
相当于vue的mounted
onHide
比较特殊,相当于vue组件的生命周期加上了keep-alive之后的deactivated
onUnload
相当于vue的destoryed
onPullDownRefresh
下拉刷新监听,如果页面配置了下拉刷新,则页面会在下拉刷新以后调用这个函数
onReachBottom
上拉加载监听,如果配置了上拉加载,则页面触底之后就会自动调用这个函数
onShareAppMessage
用户点击右上角分享后会调用这个方法
小程序支持的选择器
目前支持的选择器:
元素选择器 | tag {} | ✓ | |
---|---|---|---|
类选择器 | .class {} | ✓ | |
ID 选择器 | #id {} | ✓ | |
分组选择器 | a, b {} | ✓ | |
直接子代选择器 | a > b {} | ✓ | |
后代选择器 | a b {} | ✓ | |
伪类选择器 | :active {} | ✓ | 只支持 :first-child 和 :last-child,其它暂无计划 |
伪元素选择器 | ::before {} | ✓ | 只支持 ::before 和 ::after |
小程序数据渲染
小程序的渲染分为多种方式,可以直接和我们之前学习的vue来类比
大体来说,可以分为普通渲染,条件渲染,列表渲染
普通渲染
这里写法和vue是一样的
data: {
userName:"zhangsan"
}
在wxml文件中渲染
<view>{{userName}}</view>
<view>{{userName + "hello"}}</view>
<view>{{2+3}}</view>
<view>{{11>2?"哈哈":"呵呵"}}</view>
条件渲染
在vue中使用v-if,小程序中又类似的语法 wx:if
data: {
flag:false,
userName:"zhangsan"
}
wxml文件中
<view>
<text wx:if="{{flag}}">{{userName}}</text>
<text wx:elif="{{3 > 2}}">王五</text>
<text wx:else>李四</text>
</view>
列表渲染
列表渲染使用wx:for 使用过与vue的v-for一样
data: {
flag:false,
userName:"zhangsan",
stuList:[
"张三",
"李四",
"王五"
]
}
渲染
<view>
<text wx:for="{{stuList}}" wx:for-item="item" wx:for-index="index" wx:key="index">{{item}}----{{index}}</text>
</view>
<view>
<text wx:for="{{stuList}}" wx:key="index">{{item}}----{{index}}</text>
</view>
1、wx:for-item 代表遍历的每一项,默认叫item
2、wx:for-index 代表遍历的每一项索引,默认index
3、wx:key 跟之前vue中的key作用是一样的
小程序的事件
小程序里面的事件绑定和之前vue中dd额DOM事件绑定是有区别的
<!-- 小程序里面的事件绑定不能加小括号,只能是方法名 -->
<button bindtap="sayHello">按钮</button>
方法
// pages/index/index.js
Page({
/**
* 页面的初始数据
*/
data: {
},
sayHello(event){
//这里的事件对象不是DOM的事件对象
console.log("hello")
}
})
小程序的默认事件绑定是通过bind来进行的,事件名称与之前的DOM的事件名称不一样,在事件调用方法的时候也要注意,没有括号只有方法名
注意:
小程序在调用事件方法的时候默认会向这个方法注入一个event参数
小程序的事件传参
因为小程序的事件在绑定的时候是方法名,不能加括号,所以怎么传递参数?
<button bindtap="sayHello" data-stu-name="张三">按钮</button>
现在我们在button上面添加一个自定义属性data-stu-name 后面跟了一个我们要传递的值,而我们又知道小程序在调用事件方法的时候会像当前的方法内传递一个参数event,所以我们最终可以通过这个event来获取到参数值
sayHello(event){
console.log("hello");
console.log(event.currentTarget.dataset.stuName)
}
小程序的事件传递
在普通的DOM里面,我们的事件是可以传递的,有冒泡行为和捕获行为,小程序使用的是冒泡行为,所以当内部的元素触发事件以后会冒泡到外边来,现在要怎么阻止事件传播(取消事件冒泡)
<view class="box" bindtap="outer">
<button catchtap="inner">按钮</button>
</view>
outer(){
console.log("我是外面的盒子")
},
inner(){
console.log("我是里面的按钮")
}
这个时候我们点击里面的按钮,事件并不会冒泡到外边去,因为我们使用的是catchtap来进行事件绑定,catch进行的小程序事件绑定时没有传播行为的
小程序的数据状态
小程序执行的时单项数据绑定,但是可以重新主动渲染页面,但是并不会自动的渲染页面【这一点和react是一样的】
现在通过案例来实现
<view>
{{userName}}
</view>
<button bindtap="changeUserName">改变userName</button>
changeUserName(){
// this.data.userName = "lisi"
//上面这种写法可以修改数据,但是不能同步渲染页面
this.setData({
userName:"李四"
})
console.log(this.data.userName);
}
代码分析:
1、当我们点击按钮之后,我们发现如果采用常规的
this.data.userName = "lisi"
这个时候会赋值成功,但是页面并不会把这个值重新渲染,所以充分说明了这个值执行的单向绑定2、当我们调用this.setData() 这个方法赋值的时候,值会改变,并且页面会从新渲染,这是一种主动的渲染方式
3、当我们在调用
this.setData({userName:"李四"})
的时候,它只会对userName的值改变,而data里面其他的值不受影响
所以通过上面的情况我们可以得到一个结论,如果你只是向赋值而不想渲染页面,则使用this.data的方式来完成,如果你想赋值完成以后重新渲染页面,则使用 this.setData()
复杂情况下的数据改变
data: {
userInfo:{
userName:"张三",
age:18
},
tName:"李四"
}
changeUserName(){
// this.setData({
// userInfo:{
// userName:"哈哈"
// }
// })
//通过上面方式赋值是有问题的,我们的age会被覆盖掉
//第一种:通过Object.assgin()完成
// this.setData({
// userInfo:Object.assign(this.data.userInfo,{
// userName:"哈哈"
// })
// })
//第二种:通过ES6语法
this.setData({
userInfo:{...this.data.userInfo,userName:"哈哈"}
})
}
小程序的样式处理
微信小程序所使用的也是css,只有有一些特殊情况要注意:
1、关于选择器
2、关于单位
3、关于背景图表
小程序采用的是wxss的标准,wxss具有css大部分的特性,小程序在wxss做了一个扩展和修改
1、新增尺寸单位rpx,在写css样式的还是很,开发者需要考虑到手机设备的屏幕会有不同 的宽度和设备像素比,采用一些技巧来换算一些像素单位,wxss在底层支持新的尺寸单位rpx,开发可以免去换算的烦恼,交给小程序环境,由于换使采用的是浮点运算,所以运算结果会稍微有点偏差
rpx(responsive pixel) :可以根据屏幕宽度自适应,规定屏幕宽度750rpx,而一般ui给的设计稿他们在设计的时候创建的画布尺寸的宽度基本也都是750px,根据小程序自己换算的结果,基于750px的设计搞当中的设计元素的尺寸可以直接1 :1设置到rpx单位上
1px = 1rpx
2、关于图片,小程序不允许使用本地作为背景图片使用的,如果使用它会报错
wxss代码
.box{
width:100rpx;
height:100rpx;
background-image:url("../images/img1.jpg");
/* 微信小程序自带的webpack,是没有配置url-loader,导致无法打包背景图片这类的静态资源 */
}
- 直接使用网络图片作为背景图片,这样会节省小程序的体积
- 把图片转换成base64,然后再去使用也是可以的
- 还可以使用父相子绝的方式,把img标签引入的图片再通过z-index:-1
3、关于选择器
小程序是不支持:hover伪类的,但是每一个组件有一个hover-class的属性,你可以把它当成hover伪类使用
注意: 小程序最好不要使用后代选择器或者子代选择器,后期很容易出错,因为小程序的界面开发全是组件的虚拟标签,它并不是真正意义上的html标签,这些虚拟标签作为组件其内部自己还封装一套html结构,因为后代和子代的选择可能会导致样式侵入到组件内部的html结构上面,这样样式容易出现混乱
技巧点:
小程序想实现全局样式,则需要把样式写再app.wxss上面,或者@import导入这个文件,我们也可以通过@import导入iconfont,这样的所有的页面都可以使用字体图标
小程序的iconfont的使用
小程序是可以使用字体图标的,只是使用方式上有点不一样
开发环境
1、在小程序的目录下面新建一个文件iconfont,同时在这个文件夹下面新建一个iconfont.wxss
2、在iconfont的网站上面,开打icon class下面的链接,然后把这个链接的内容复制下来,粘贴到这个文件中
3、因为字体图标需要全局使用,所以我们在app.wxss中进行@import 导入
@import './iconfont/iconfont.wxss'
生产环境
正常情况下我们会把字体图标下载下来,再去使用,但是因为小程序的大小限制,所以这里可能有点区别
1、如果下载下来,字体文件较大,我们还是会把这个下载好的iconfont文件上传到自己的服务器,然后再使用自己的服务器地址进行引用,这样可以减少小程序的体积
2、如果下载以后,字体文件比较小,可以像以前一样,直接使用
小程序的路由栈
小程序的路由栈也叫小程序的页面栈,是对小程序的页面跳转提供了一些方法
1、wx.navigateTo
跳转到某个页面,这个页面再小程序的页面栈中直接入栈,之前的页面并没有出栈,同时这个页面会自动的再标题栏添加一个返回按钮,执行返回操作
2、wx.navigateBack
页面栈出栈,相当于返回上一个页面
3、wx.redirectTo
这个是重定向到某个页面,相当于vue路由管理对象中的replace方法
注意事项:
1、wx.navigateTo
最多只能嵌套10层,因为它的页面栈只有10层
2、上面的三个跳转页面的方法都是再普通页面栈里面进行跳转
小程序的tabBar配置
"tabBar": {
"selectedColor": "#f00",
"color": "#808080",
"list": [
{
"text": "首页",
"iconPath": "",
"selectedIconPath": "",
"pagePath": "pages/index/index"
},
{
"text": "我的",
"iconPath": "",
"selectedIconPath": "",
"pagePath": "pages/my/my"
}
]
}
当上面的配置完成之后,tabbar就会自动出现,并且已经实现了页面跳转
注意事项:
1、上面的tabBar如果从vue的原理上来讲,其实就是vue 的二级路由,所以它的页面跳转方式与上面的普通路由栈的跳转方式是不太一样的
tabBar里面的配置的页面都是默认添加了 keep-alive
它是一个特殊的页面栈,所以wx.navigateTo
wx.redirectTo
都不能跳转到tabBar里面的页面,如果要跳转到tabBar的页面,需要通过 wx.switchTab
方法,同理,wx.switchTab
也不能跳转到普通页面栈
2、tabBar再配置的时候里面的图标是不能使用base64,也不能使用字体图标,它必须是一个实实在在的图片
3、tabBar在配置list的时候,最少2个,最多5个
4、还有一个页面的跳转方法,wx.relaunch
,小程序重启的时候跳转到某一个页面,这个方法对任何页面都有效
小程序的界面交互
小程序提供了很多的用户与界面交互的方法
1、wx.showLoading
在小程序页面上显示一个加载框
2、wx.hideLoading
隐藏加载框
3、wx.showToast
显示轻消息框
4、wx.hideToast
隐藏轻消息框
5、wx.showModal
显示操作模拟框
wx.showModal({
title: '警告',
content: '你确定要删除么',
cancelText:"就不取消",
confirmText:"我很确认",
complete: (res) => {
if (res.confirm) {
console.log("取消")
}else{
}
}
})
6、wx.showActionSheet
显示底部弹出的操作选项菜单
wx.showActionSheet({
itemList: ["添加收藏","查看详情"],
success:res => {
if(res.tapIndex == 0){
console.log("你点击是收藏")
}else if(res.tapIndex == 1){
console.log("你点击的是详情")
}
},
fail:error => {
console.log("你点击了取消")
}
})
7、wx.previewImage
图片预览
小程序的组件开发
小程序本身提供了很多的组件,但是我们也可以自定义组件
1、先再小程序的项目下面新建一个components文件夹
2、再下面继续创建一个文件夹TextItem,在这个文件夹点击右键,新建Component
新建好的组件跟page的文件结构是一样的,关键在于生成的js文件
// components/TextItem/TextItem.js
Component({
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
}
})
这里我们主要看下与页面的区别
component组件的js与page页面的js区别
1、页面使用de的是Page方法,而组件使用的shishi Component方法
2、页面里面的方法直接写在对象里面,而组件里面的fafa那个发卸载methods里面
3、组件里面会多一个 properties的属性,用于接收外部传给组件的值
4、组件不是页面,所以他们之间的生命周期函数是不一样的,例如页面是有onLoad,而组件没有
组件的生命周期
1、created 在组件实例刚刚被创建的时候执行,相当于vue2里面的beforeCreate,所以这个时候是不能使用setData()
2、attached 在组件进入页面节点树的时候执行,相当于是vue2的created与beforeMount之间的阶段,这个的时候已经可以操作数据和方法了
3、ready 在组件布局完成之后,相当于vue的mounted,这个时候可以操作虚拟DOM
4、moved 组件在被移动到节点树的另外一个位置时执行
5、detached 组件被从页面节点树种移除的时候
组件内部的方法和属性
1、data 组件的属性列表,组件上面使用的数据都来源这里
2、properties 组件外部接收的数据列表
3、methods 组件内部的方法
4、observers 这个相当于vue中的watch和computed
组件的引用
一个页面如果要调用组件,或者另一个组件要使用组件都需要提前进行配置,在当前页面或组件下面找到json文件,如index.json
{
"usingComponents": {
"text-item":"/components/TextItem/TextItem"
}
}
index.wxml
<text-item></text-item>
父级组件传值
这里跟vue一样,都是通过属性传值
index.wxml
<text-item user-name="{{tName}}"></text-item>
TextItem.js
properties: {
userName:{
type:String,
value:"张三"
}
}
在组件的方法里面调用外部传递的数据,直接使用 this.data.userName
就可以正常取值
组件的observers
这个就相当于是vue 的监听器watch
observers:{
age(newVal){
console.log(newVal)
}
}
组件的插槽
小程序组件的插件跟vue的插槽使用基本一致,但是它默认情况下只能使用默认插槽,不能使用具名插槽,如下
在组件的wxml中
<text>我是组件</text>
<slot></slot>
在页面或其他组件中调用的时候
<text-item>
今天天气不错
</text-item>
上面的代码就是使用默认插槽
但是多数情况下我们还是会使用到具名插槽,这个时候小程序的组件是可以允许的,需要在组件里面去配置开启
Component({
/**
* 组件的属性列表
*/
options:({
//开启多插槽模式,也就是开启了具名插槽模式
multipleSlots:true
}),
//......
})
组件数据流的单向性
当我们查实去改变外部传递给组件内部的数据的时候,我们发现组件内部的数据是可以改变,但是外部的数据没有变,怎么办?
这个过程其实看下我们之前的vue就知道,可以使用自定义事件去完成
TextItem.js
methods: {
haha(event){
//我们尝试去改变父级传递过来的值
//通过父级去改变的
//vue里面使用 this.$emit()
//小程序里面使用triggerEvent 来触发一个自定义事件
this.triggerEvent("changeusername","我是你儿子")
}
}
在上面的代码当中,当我们触发haha方法的时候,它会调用 this.triggerEvent 来触发一个自定义事件,然后向外传值
index.js
callFather(event){
console.log(event);
console.log("我儿子在叫爸爸");
this.setData({
tName:event.detail
})
}
所传递过来的值在event. detail 里面
父级使用子级组件的方法
在vue中,我们可以直接通过this.$refs 选中某一个组件然后调用方法即可,在小程序里面差不多
TextItem.js中
methods: {
callSon(){
console.log("爸爸在叫儿子")
},
//......
}
index.wxml
在当前使用的组件上添加一个 id=“mySon” 我们就可以调组件内的方法
sayHello(){
this.selectComponent("#mySon").callSon();
}
小程序的数据交互
小程序的开发也是一种前后端分离的开发模式,所以它也需要后端提供接口才能开发【云开发模式】,小程序内部提供了获取数据的方法(可以理解成ajax请求)
1、wx.request
发起一个http或者https请求,相当于ajax
2、wx.downloadFile
下载文件
3、wx.uploadFile
上传文件
4、websocket
双工通信
小程序在发送请求之前需要做一些配置,它只允许在特定的配置项里面发起请求,并且只能是https协议的请求,如果不设置会报错说你的请求不在合法域名列表种
针对上面的情况2种解决方法
第一种方式:在开发环境下不检测域名的合法性
点击右上角的详情 ----》 本地设置 ----》 勾选,不校验合法域名…
第二种方式:直接在小程序的账号后台去配置
登录测试号在请求域名中配置
…
getData(){
wx.showLoading({
title:"正在请求数据"
});
wx.request({
method:"GET",
url: 'http://www.softeem.xin:9544/foodInfo/getListByPage?pageIndex=1',
data:{
},
success: res => {
//请求成功
console.log(res)
},
fail: error => {
//请求失败
console.log(error);
},
complete: () => {
//关闭加载动画
wx.hideLoading()
}
})
},
一般来说,我们不会直接使用request发送请求,而是做一个二次封装,与我们之前学习的axios一样的
封装过程
1、在小程序的utils文件夹下面新建一个api.js
2、根据自己的业务需求编写接口请求代码
export default {
ele:{
getData({pageIndex}){
return new Promise((resolve,reject) => {
wx.request({
method:"GET",
url: 'http://www.softeem.xin:9544/foodInfo/getListByPage',
data:{
pageIndex
},
success: res => {
resolve(res.data)
},
fail: error => {
reject(error)
}
})
})
}
}
}
3、编写完成之后就可以正常去调用这个接口了,你可以async/await来完成
async getData(){
wx.showLoading({
title: '正在加载数据.....',
})
try{
let results = await Api.ele.getData({pageIndex:1})
}catch(error){
console.log(error)
}finally{
wx.hideLoading()
}
}
小程序页面传值
小程序的跨页面传值,使用的也是search模式,所以写法一样
toDetail(){
wx.navigateTo({
url: 'pages/index/index?id=1&userName=李四',
})
}
在目标页面中调取search值文章来源:https://www.toymoban.com/news/detail-825829.html
onLoad(options) {
console.log(options.id);
console.log(options.userName);
},
在目标页面的生命周期函数onLoad里面,它会有一个参数options,这个参数包含了之前的页面传递过来的search值文章来源地址https://www.toymoban.com/news/detail-825829.html
到了这里,关于【学习前端第七十一课】小程序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!