新建项目:
app.json删除skyline
基础库版本
project.config.json加上sass插件
alt+点选——可以同时输入
ctrl+D——可以自动在同一单词后面点选
ctrl+shift+>——可以向右跳着选中整块内容
小程序基础
教程简介
什么是微信小程序?
轻量级,触手可及,无需安装卸载,用完即走
注册账号
去微信公众平台注册小程序账号
(设置类目时,不要选择游戏)
成员管理:项目成员和体验成员
开发管理——开发设置——
小程序ID(小程序的身份证号)和小程序密钥(开发者对小程序拥有所有权的凭证,在开发微信登录、微信支付和发送消息等高级功能时要用到)
微信开发者工具(必须联网使用)
不使用云服务,不使用模板
视图——外观——将模拟器移到右侧
设置——编辑器设置——将行距调成20
小程序文件介绍:
主体文件——作用于全局(每个页面),必须放在根目录下
app.js:小程序入口文件(必须)
app.json:全局配置文件(必须)
app.wxss:全局样式
主体文件文件名必须是app
页面文件——作用于单个页面,放在pages目录下,且是一个页面一个index文件夹
.js:页面逻辑(必须)
.json:配置
.wxml:页面结构(必须)
.wxss:页面样式
components:存放每个页面里的公共组件
注意:开始时默认有两种渲染模式,skyline和webview,
因为skyline未成熟,将其删掉——
在app.json中把renderer(渲染器)、rendereroptions(渲染器配置选项)和componentframework(组件框架)三个配置项去掉,保存即可重新编译
新建页面——
在pages下新建文件夹page1,
在page1文件夹下新建page:page1(不要加后缀)
或者直接在app.json中修改:
调试器:
wxml——结构和样式
console——js打印输出
network——调试网络请求
appdata——查看页面的数据
storage——本地存储
编译后仍报错,就试试清缓存,清缓存不行就重新打开此项目
配置文件
全局配置——app.json:
pages(页面路由)
“entryPagePath”: “pages/page1/page1”,
“pages”: [
“pages/index/index”,
“pages/page1/page1”,
“pages/page2/page2”
],
未指定entryPagePath时,默认数组的第一项为小程序首页
删除page:先手动删掉文件夹,再去配置文件里删除,再保存
window(全局窗口——导航条、下拉刷新、页面背景)
微信小程序官方文档——开发——框架——小程序配置——全局配置
没有变化的,把 “renderer”: “skyline”,这行代码删除了就可以。
“window”: {
“navigationBarTitleText”: “慕尚花坊”, //导航条标题文本
“navigationBarBackgroundColor”: “#f3514f”, //导航条背景颜色
“enablePullDownRefresh”: true, #开启全局下拉刷新功能
“backgroundColor”: “#efefef”, #页面背景颜色(下拉刷新时才会看到)
“backgroundTextStyle”:“dark” #页面背景的loading图标样式,仅支持 dark / light
},
tabBar(底部页面切换栏)
可以去阿里巴巴矢量图标寻找png图片,然后存放到assets(静态资源)文件夹下
“tabBar”: {
“color”: “#666”, //图标文字颜色,默认黑色,666颜色变淡
“selectedColor”: “#f3514f”, //被选择时图标文字颜色
“backgroundColor”: “#efefef”, //tabbar背景颜色
“borderStyle”:“black”, //tabbar上边框样式
“position”: “bottom”, //默认tabbar在底部
“list”: [ //定义tabbar的每个标签页(数组里装对象,按顺序展示,最少配置2个,最多5个)
{
“text”: “首页-编辑”, //标签的小字
“pagePath”: “pages/edit/edit”, //页面路由
“iconPath”: “/assets/tabbar/edit.png”, //图标路径
“selectedIconPath”: “/assets/tabbar/edit_act.png” //被选择时的图标路径
},
{
“text”: “记录”,
“pagePath”: “pages/record/record”,
“iconPath”: “/assets/tabbar/record.png”,
“selectedIconPath”: “/assets/tabbar/record_act.png”
}
]
页面配置——pages的.json文件
和全局配置的window属性几乎一致,只不过这里不需要额外指定window字段,
如果出现相同的配置项,局部的会覆盖全局的
开发工具配置
微信小程序官方文档——开发——工具——设置——项目配置文件
详情——本地设置——调试基础库(选择版本),将js编译成ess…
在控制面板中直接勾选,相应地project.config.json(会影响最终编译的设置)或project.private.config.json会自动发生变化
集成css的拓展语言scss——会影响最终编译,加在project.config.json里
- 改project.config.json
“setting”: {
“useCompilerPlugins”: [
“sass”
],
…
}
2. 改文件后缀
将index.wxss改成index.scss
CSS是标准的样式语言,wxss是微信小程序对CSS的定制版本;
Sass是一种CSS预处理器(一个插件,将.sass或.scss编译成.css文件),它可以提供更高级、更复杂的样式,有两种语法:Sass(缩进)和SCSS(类似CSS),这里使用SCSS。
sitemap.json——是否可以被检索
显式指明黑名单,只有index页面不可以被检索,其他页面可以被检索
也可以显式指明白名单,只有index页面可以被检索
样式
微信小程序官方文档——开发——指南——小程序框架——视图层——wxss——选择器
组件
划分页面结构——wxml
设置page样式
轮播图
层级:
view(class=“swiper”)——swiper——swiper-item——image
文本信息
布局
display的属性值:
-
block: 独占一行。
-
inline: 行内显示,不能设置宽高。
-
inline-block: 行内显示,可以设置宽高。
-
flex: 弹性布局。
-
none: 隐藏元素。
-
grid: 网格布局。
justify-content:
- flex-start 子元素靠左对齐(默认值)
- flex-end 子元素靠右对齐
- center 子元素居中对齐
- space-between 首尾子元素靠边,中间子元素均匀分布
flex-direction: column
align-items: center; //控制元素在主轴上的对齐方式
边框
box-sizing:border-box
.box {
padding: 20rpx 16rpx; /* 上下 20rpx,左右 16rpx */
}
-
padding 是内部的空白区域。
-
border 是围绕内容和 padding 的边框。
-
margin 是外部的空白区域。
补充
父选择器
注意::nth-child(n): 匹配所有子元素,因为 n 从 0 开始,但 :nth-child 的索引从 1 开始,所以 :nth-child(n) 会匹配所有子元素。
nth-child和nth-of-type区别
.scroll-x view:nth-child(2):不区分元素类型,先确定第 2 个子元素,再检查是否为 元素。
.scroll-x view:nth-of-type(2):先筛选出所有的 元素,再选择其中的第 2 个。
覆盖问题
为什么没有覆盖?
选择器优先级:text 选择器的优先级低于 .info,但 text 选择器直接作用于 text 元素,而 .info 的样式并没有直接作用于 text 元素。
字体图标
阿里巴巴图标库——选择图标添加至购物车,然后放进项目——Font class生成代码——复制到新建文件iconfont.scss里——app.scss导入该样式文件
@import “./icon-font/iconfont.scss”;
新添加一个text标签,在里面加上图标的类名(基础类名+具体类名)
注意:嵌套text要在一行里写完,不然图标和文字会分行
调样式
商品导览
跳转
- navigate 跳转到非 tabBar 页面(保留上一级页面,可以返回)
- redirect 跳转到非 tabBar 页面(关闭上一级页面,只能返回首页)
- switchTab 跳转到 tabBar 页面
url附加参数要通过 onLoad(options) {
console.log(options)
},
来接收
跳转到别的页面后,在别的页面的wxml写返回
image和text需要包含在navigator里,这样点中图片或文本时才会跳转
注意整体视图和内部视图,
调整格式的代码要放在直接父元素里,
这样才会作用于直接子元素
商品推荐
<scroll-view class="scroll-x" scroll-x="true">
<view>1</view>
<view>2</view>
<view>3</view>
</scroll-view>
<scroll-view class="scroll-y" scroll-y="true">
<view>1</view>
<view>2</view>
<view>3</view>
</scroll-view>
.scroll-x
{
width: 100%; //横向滚动:滚动区域宽度占满父容器
white-space: nowrap; //不允许子元素换行
background-color: skyblue;
view{
display: inline-block; //子元素以行内块元素显示,使其水平排列在同一行
width:300rpx;
height:80rpx;
&:first-child{
background-color:red;
}
&:last-child{
background-color: bLue;
}
}
}
.scroll-y{
height: 400rpx;//滚动区域高度
background-color: skyblue;
margin-top: 10rpx;
view{
height:400rpx;
&:first-child{
background-color:red;
}
&:last-child{
background-color: bLue;
}
}
}
//推荐商品样式
.goods-hot{ //整个商品区
background-color: #fff;
padding: 16rpx;
border-radius: 10rpx;
.scroll-x{ //商品滚动展示区域
width: 100%;
white-space: nowrap; //滚动展示的内容不允许换行
view{ //外层商品盒子(与外界scroll-x关联,便于整体排布)
display: inline-block; //商品盒子本身不换行,行内块
width: 320rpx;
height: 440rpx;
margin-right: 16rpx;
&:last-child{
margin-right: 0rpx;
}
.goods-item{ //打包商品内容(管理内层分布样式)
display: flex; //元素显示为弹性容器,商品内容(子元素)是flex项目
flex-direction: column;
justify-content: space-between;
image{
width:100%;
height:320rpx;
}
text{
font-size: 30rpx;
&:nth-of-type(1){
font-weight: bold;
}
}
}
}
}
}
display: inline-block:仅改变当前元素的显示方式,子元素布局不受影响。
display: flex:改变当前元素的显示方式,并直接影响子元素的布局行为(子元素成为 Flex 项目)。
背景图
<view class="bg-image"></view>
.bg-image{
height:400rpx;
//小程序背景图不能写本地路径
//background-image: url(/assets/swiper/flower1.jpg);
//可以使用网络图片路径
background-image: url(https://tse1-mm.cn.bing.net/th/id/OIP-C.lNTy968dNlm7avAhRhZDvwHaHa?rs=1&pid=ImgDetMain);
}
事件系统
事件绑定(bind绑定)和事件对象(输入框获取值)
点击button——tap=“…”
输入框——input=“…”
在.js中写事件处理函数
阻止事件冒泡(catch绑定)
传入自定义数据(data-)
传入自定义数据(mark:)
wxml语法
声明和绑定数据
修改数据
修改对象类型数据
data: {
num:1,
//声明一个空对象 对象名:{}
userInfo:{
name:'tom',
age:10,
test:111
}
},
updateUserInfo(){
//新增属性
// this.setData({
// //给对象新增属性值,将key写成数据路径的方式a.b.c,然后要加上引号
// 'userInfo.name':'tom',
// 'userInfo.age':10
// })
// 修改属性
// this.setData({
// 'userInfo.name':'jerry',
// 'userInfo.age':18
// })
// 如果数据量很大,新增和修改对象数据都使用数据路径则太麻烦了
// 可以使用ES6提供的展开运算符和Object.assign()
//ES6提供的展开运算符(把对象值一整个赋值给对象)
// const userInfo = {
// ...this.data.userInfo, //复制属性
// name:'jerry', //重新赋值
// age:18
// } //得到一个修改版的copy对象(这个对象先包含了 this.data.userInfo 的所有属性,接着又对 name 和 age 属性进行了覆盖)
// this.setData({
// userInfo:userInfo //覆盖原来的
// })
//Object.assign() 将多个对象合并为同一个对象,从后往前合并,可覆盖相同属性(Object.assign(target, ...sources))
// const userInfo = Object.assign(
// this.data.userInfo,
// {
// name:'jerry',
// age:18
// }
// )
// this.setData({
// userInfo:userInfo //覆盖原来的
// })
//删除单个属性
// delete this.data.userInfo.age
// console.log(this.data.userInfo)
// this.setData({
// userInfo:this.data.userInfo
// })
//删除多个属性 rest剩余参数
console.log(this.data.userInfo) //{name: "tom", age: 10, test: 111}
const{age,test,...rest}=this.data.userInfo //对象解构赋值:从 this.data.userInfo 对象里提取 age 和 test 属性,然后把剩余的属性重新组合成一个新对象,使用 const 可以保证变量的不可变性
this.setData({
userInfo:rest
})
console.log(this.data.userInfo) //{name: "tom"}
},
修改数组类型数据
data: {
list:[1,2,3],
list1:[{id:1,name:'tom'}]
},
updateList(){
console.log("被触发")
//新增数组元素
// this.data.list.push(4) 可以改变数据本身
// this.setData({
// list:this.data.list
// })
// const newList = this.data.list.concat(4) //不可以改变数据本身
// this.setData({
// list:newList
// })
// const newList = [...this.data.list,4]
// this.setData({
// list:newList
// })
//修改数组元素(使用数据路径)
// this.setData({
// 'list[1]':6,
// 'list1[0].name':'jerry'
// })
//删除数组元素
// this.data.list.splice(1,1) //索引为 1 的位置开始,删除 1 个元素
// this.setData({
// list:this.data.list
// })
const newList = this.data.list.filter(item=>item!=2) //从 this.data.list 数组里筛选出值不等于 2 的元素
this.setData({
list:newList
})
},
双向数据绑定
<!--单向绑定:数据可以影响页面,但是页面更新不会影响数据-->
<!-- <input type="text" value="{{value}}"/> -->
<!--双向绑定 model:属性-->
<!-- <input type="text" model:value="{{value}}"/> -->
<!--复选框的选中效果需要双向绑定-->
<!-- <checkbox model:checked="{{ischecked}}"/>是否同意该协议 -->
<!--注意:属性值只能是一个单一字段的绑定,即不能在属性值里加上额外的字符串等-->
<!-- <input type="text" model:value="值为{{value}}"/> -->
<!--注意:属性值不能用数据路径,即不支持对象和数组-->
<!-- <input type="text" model:value="{{obj.name}}"/> -->
<!--否则页面中的数据更新就不能同步到后台-->
列表渲染
进阶用法
添加编译模式,这样每次编译后都能打开关联的非首页页面
<!--如果要进行可迭代对象的渲染,用wx:for属性-->
<!--每项默认是item,标签索引是index,注意都需要用双大括号包裹-->
<!-- <view wx:for="{{numList}}">{{item}}-{{index}}</view>
<view wx:for="{{obj}}">{{item}}-{{index}}</view> -->
<!--双层可迭代,数组元素是一个个对象-->
<!-- <view wx:for="{{fruitList}}">{{item.id}}-{{item.name}}-{{index}}</view> -->
<view class="line"></view>
<!--wx:key 可以提高性能,有 key 高效更新,无 key 暴力重建-->
<!--wx:key 的值必须是列表项中唯一且稳定的标识符(如数据库主键 id)-->
<!--不要用 index 作为 key,可以用某个不会动态改变的属性,或者*this(数组元素本身是唯一的字符串或数字)-->
<!-- <view wx:for="{{numList}}" wx:key="*this">{{item}}-{{index}}</view>
<view wx:for="{{fruitList}}" wx:key="id">{{item.id}}-{{item.name}}-{{index}}</view> -->
<view class="line"></view>
<!--变量名item、下标变量名index重命名-->
<!-- 可能会嵌套循环,所以要用不同的名字区分,不能两个都是item或者是index -->
<!--需要和wx:for写在同一个组件上,修改后要用新的名字-->
<!--数组-->
<!-- <view wx:for="{{fruitList}}" wx:key="id" wx:for-item="fruitItem" wx:for-index="i">
{{fruitItem.name}}
</view> -->
<!--对象-->
<!-- <view wx:for="{{obj}}" ex:key="*this" wx:for-item="listItem" wx:for-index="i">
{{listItem}}-{{i}}
</view> -->
<!--block并非实际的组件,它只是一个包装元素,不会在页面中渲染出任何实际的 DOM 节点-->
<block wx:for="{{fruitList}}" wx:key="id" wx:for-item="fruitItem" wx:for-index="i">
<view>名字:{{fruitItem.name}}</view>
<view>价格:{{fruitItem.price}}</view>
</block>
条件渲染
<!-- wx:if后面加 可以返回布尔值的表达式 -->
<!--wx:elif和wx:else必须结合wx:if来使用-->
<!--只有对应的条件成立时,属性所在的组件才会进行展示-->
<view wx:if="{{num==1}}">num等于1</view>
<view wx:elif="{{num==2}}">num等于2</view>
<view wx:else>num大于2</view>
<!--注意wx:if属性组的组件不能被打断,必须要连贯-->
<button type="warn" bind:tap="updateNum">更新num</button>
<view hidden="{{!isFlag}}">如果isFlag是true,就展示结构,否则隐藏结构</view>
<!--wx:if控制结构的展示和隐藏,是通过新增和移除结构来实现的-->
<!--hidden控制结构的展示和隐藏,是通过css的display属性来实现的(display:none和display:block)-->