zoukankan      html  css  js  c++  java
  • 微信小程序基础

    1.介绍及安装

    1.1介绍

    小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验。它的主要开发语言是 JavaScrip。

    1.2安装及使用

    小程序进行开发时,需要先安装开发者工具,申请账号等操作,具体详见https://developers.weixin.qq.com/miniprogram/dev/framework/quickstart/getstart.html

    2.小程序入门

    2.1创建并预览

    在安装完成微信开发者工具后,新建项目选择小程序项目,选择代码存放的硬盘路径,填入刚刚申请到的小程序的 AppID,点击顶部菜单编译在微信开发者工具中预览第一个小程序,预览图如左图,目录结构如右图:

                        

    除了可以在开发者工具中预览之外,还可以在手机上进行预览。点击菜单的真机调试,微信扫描二维码后即可查看。另外,在开发过程中,如果涉及到修改配置文件等信息时,推荐使用微信开发工具(有提示),而对于页面的开发推荐使用其他的开发工具。比如需要新建一个页面时,可在微信开发者工具中编辑app.json,在里面添加页面路径,那么就会自动创建页面相关的文件;再例如配置tarbar时都会出现提示。

    2.2JSON 配置

    JSON 是一种数据格式,并不是编程语言,在小程序中,JSON扮演的静态配置的角色。在小程序运行之前就决定了小程序一些表现,需要注意的是小程序是无法在运行过程中去动态更新JSON 配置文件从而发生对应的变化的。相比于XML ,JSON格式最大的优点是易于人的阅读和编写,通常不需要特殊的工具,就能读懂和修改,是一种轻量级的数据交换格式。

    2.2.1 小程序配置app.json

    app.json 是当前小程序的全局配置,包括了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等。其部分内容如下:

    {
      "pages":[
        "pages/index/index",
        "pages/logs/logs"
      ],
      "window":{
        "backgroundTextStyle":"light",
        "navigationBarBackgroundColor": "#fff",
        "navigationBarTitleText": "Weixin",
        "navigationBarTextStyle":"black"
      }
    }

    除了以上属性外,还要其他的属性,说明如下:

    属性 类型 必填 说明
    pages String[] 描述当前小程序所有页面路径,也就是指定小程序页面在哪个目录
    window Object 定义小程序所有页面的顶部背景颜色,文字颜色定义等
     tarBar Object  底部tab栏的设计
    entryPagePath
    String 小程序的默认启动路径,如果不填,将默认使用pages中的第一个页面
    useExtendedLib
    Object 引入第三方的插件

    (1)window常用的设置

    1)backgroundTextStyle:下拉 loading 的样式,仅支持 dark / light。需要和enablePullDownRefresh共同使用才能生效

     "window":{
        "backgroundTextStyle":"dark",
        "enablePullDownRefresh": true
     }

    2)navigationBarBackgroundColor:导航栏背景颜色,仅支持rgb(如#fff),不支持颜色变量(如red)

    "navigationBarBackgroundColor": "#00BFFF",

    效果图如下:

     3)navigationBarTextStyle:导航栏标题颜色,仅支持 black / white,默认是black

    "navigationBarTextStyle":"white"

    4)navigationBarTitleText:导航栏的标题文字

    "navigationBarTitleText": "我的微信小程序"

    (2)tarBar常用设置

    一般情况下,这个导航栏放在底部。tarBar的有一个list,其中 list 接受一个数组,只能配置最少 2 个、最多 5 个 tab。tab 按数组的顺序排序,每个项都是一个对象

    "tabBar": {
        "list": [
          {
            "pagePath": "pages/index/index",
            "text": "首页",
            "iconPath":"img/icon/index.png",
            "selectedIconPath": "img/icon/index-active.png"
          },
          {
            "pagePath": "pages/my/my",
            "text": "我的",
            "iconPath":"img/icon/my.png",
            "selectedIconPath": "img/icon/my-active.png"
          }
        ]
      }

    效果图如下:

     

    pagePath:指定页面的路径;text:显示的文字;iconPath:未激活时的图标,需自定义图片。图片存放路径img文件夹与pages文件夹必须同级;selectedIconPath:激活时的图标。

    除了list属性外,还有其他的属性,如需要则可自行设置,列举如下:

    属性 说明
    color tab 上的文字默认颜色,仅支持十六进制颜色
    selectedColor tab 上的文字选中时的颜色,仅支持十六进制颜色
    backgroundColor tab 的背景色,仅支持十六进制颜色
    borderStyle tabbar 上边框的颜色, 仅支持black/white,默认是black
    position tabBar 的位置,仅支持bottom/top,默认是bottom

    2.2.2工具配置 project.config.json

    小程序开发者工具在每个项目的根目录都会生成一个 project.config.json,在工具上做的任何配置都会写入到这个文件,当重新安装工具或者换电脑工作时,只要载入同一个项目的代码包,开发者工具就自动会帮你恢复到当时开发项目时的个性化配置。

    2.2.3页面配置 page.json

    2.3WXML 模板

    WXML 全称是 WeiXin Markup Language,是小程序框架设计的一套标签语言,结合小程序的基础组件、事件系统,可以构建出页面的结构。WXML就相当于html页面,但是它里面只能写标签,不能包含js和css。WXML 要求标签必须是严格闭合的,没有闭合将会导致编译错误,其属性是大小写敏感的。打开pages/index/index.wxml,其内容如下:

    <view class="container">
      <view class="userinfo">
        <button wx:if="{{!hasUserInfo && canIUse}}"> 获取头像昵称 </button>
        <block wx:else>
          <image src="{{userInfo.avatarUrl}}" background-size="cover"></image>
          <text class="userinfo-nickname">{{userInfo.nickName}}</text>
        </block>
      </view>
      <view class="usermotto">
        <text class="user-motto">{{motto}}</text>
      </view>
    </view>

    对比html页面可以看出,这里的标签是不一样的,小程序采用的标签是view、button等,这些都是已经包装过的。

    2.4WXSS 样式

    WXSS 具有 CSS 大部分的特性,但也有扩充。新增了尺寸单位rpx,提供了全局的样式和局部样式。可以写一个 app.wxss 作为全局样式,会作用于当前小程序的所有页面,局部页面样式 page.wxss 仅对当前页面生效,此外 WXSS 仅支持部分 CSS 选择器。

    2.5JS 逻辑交互

     编写 JS 脚本文件来处理用户的操作,请看下面的代码:

    <view>{{ msg }}</view>
    <button bindtap="clickMe">点击我</button>

    点击 button 按钮的时候,我们希望把界面上 msg 显示成 "Hello World",于是我们在 button 上声明一个属性: bindtap ,在 JS 文件里边声明了 clickMe 方法来响应这次点击操作:

    Page({
      clickMe: function() {
        this.setData({ msg: "Hello World" })
      }
    })

    以上先简单介绍,具体的语法见下章节。

    2.6小程序宿主环境

    微信客户端给小程序所提供的环境为宿主环境。小程序的运行环境分成渲染层和逻辑层,其中 WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。小程序的渲染层和逻辑层分别由2个线程管理:渲染层的界面使用了WebView 进行渲染;逻辑层采用JsCore线程运行JS脚本。一个小程序存在多个界面,所以渲染层存在多个WebView线程。

    3.WXML详解

    3.1数据绑定

    1)数据的呈现通过两个大括号包裹起来,数据的值在js的data中定义。下面是一个简单的例子:

    pages/index/index.wxml的内容替换如下:

    <text>当前时间:{{time}}</text>

    pages/index/index.js的内容替换如下:

    const app = getApp()
    
    Page({
      data: {
          time: (new Date()).toString()
      }
    })

    在js中定义的变量直接在wxml中显示。

    2)除了直接使用data中的对象外,在大括号中还可以进行简单的逻辑运算,且看例子:

    <text>{{ a === 10? "变量 a 等于10": "变量 a 不等于10"}}</text>

    这是一个三元运算符,结果可想而知。

    3)字符串拼接

    <view>{{"hello " + name}}</view>

    4)放置数字、字符串或者是数组

    <text>{{[1,2,3]}}</text>
    
    <!-- 输出 1,2,3 -->
    
    
    
    <text>{{"hello world"}}</text>
    
    <!-- 输出 hello world -->

    3.2属性绑定

    属性值也可以动态的去改变,但属性值必须被包裹在双引号中。

    <text data-test="{{test}}"> hello world</text>

    需要注意,没有被定义的变量的或者是被设置为 undefined 的变量不会被同步到 wxml 中,即不会显示在页面上。

    3.3条件逻辑

    WXML 中,使用 wx:if="{{condition}}" 来判断是否需要渲染该代码块,使用wx:elif 和 wx:else 来添加一个 else 块

    1)只用if

    wxml内容

    <view wx:if="{{sex==0}}">男生</view>

    js内容

    Page({
        data: {
            sex:0
        },
    })

    当把sex的值改为1时页面就不会显示任何的内容。

    2)if和else都使用

    计算逻辑是先判断是否符合if的条件,若不符合就else,或者继续判断是否符合elif的条件,若还不符合就直接进入else。

    wxml内容else

    <view wx:if="{{age<20}}">年龄小于20岁</view>
    <view wx:else>年龄不小于20岁</view>

    wxml内容elif

    <view wx:if="{{age<20}}">年龄小于20岁</view>
    <view wx:elif="{{age>20}}">年龄大于20岁</view>
    <view wx:else>年龄是20岁</view>

    js内容

    Page({
        data: {
            age:20
        },
    })

    3)block的使用

    因为 wx:if 是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 <block/> 标签将多个组件包装起来,并在上边使用 wx:if 控制属性。

    <block wx:if="{{id==1}}">
      <view> view1 </view>
      <view> view2 </view>
    </block>

    3.4列表渲染

    在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item。index和item均可省略。

    wxml内容

    <view wx:for="{{user}}" wx:key="key">
        <text>用户名:{{item.name}}</text>
        <text>年龄:{{item.age}}</text>
    </view>

    js内容

    Page({
        data: {
            user: [{
                    name: '张三',
                    age: 20
                },
                {
                    name: '李四',
                    age: 30
                },
                {
                    name: '王五',
                    age: 22
                },
                {
                    name: '赵柳',
                    age: 20
                },
                {
                    name: '李琦',
                    age: 18
                },
            ]
        },
    })

    输入内容如下:

    当然,如果不使用默认的item,也可自定义。使用 wx:for-item 指定数组当前元素的变量名,使用 wx:for-index 指定数组当前下标的变量名,把上述的wxml内容修改如下:

    <view wx:for="{{user}}" wx:for-item="myuser" wx:for-index="i" wx:key="key">
        <text>{{i+':'}}用户名:{{myuser.name}}</text>
        <text>年龄:{{myuser.age}}</text>
    </view>

    如果需要指定数据的唯一标识,可以使用wx:key,但值必须是列表中唯一的字符串或数字,且不能动态改变。

    3.5模板

    WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用。使用 name 属性,作为模板的名字。然后在 <template/> 内定义代码片段。

     wxml内容

    <template name="msgItem">
      <view>
        <text> 消息内容: {{msg}} </text>
        <text> 时间: {{time}} </text>
      </view>
    </template>
    
    <!-- 引用模板 -->
    <template is="msgItem" data="{{...item}}"/>

    js内容

    Page({
        data: {
            item: {
                msg: '你吃饭了吗',
                time: '2020-11-18'
            }
        },
    })

    上述就是使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入。

    对应is属性,还可以动态决定具体需要渲染哪个模板,wxml内容如下:

    <template name="odd">
      <view> odd </view>
    </template>
    
    
    <template name="even">
      <view> even </view>
    </template>
    
    
    <block wx:for="{{[1, 2, 3, 4, 5]}}">
      <template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
    </block>

    输出结果如图:

    .

    3.6引用

    WXML 提供两种文件引用方式import和include。

    3.6.1import引用

    import 可以在该文件中使用目标文件定义的 template。

    1)在 item.wxml 中定义了一个叫 item的 template

    <template name="item">
      <text>{{text}}</text>
    </template>

    2)在 index.wxml 中引用item.wxml并使用模板

    <import src="item.wxml"/>
    
    <template is="item" data="{{text: 'forbar'}}"/>

    需要注意的是 import 有作用域的概念,即只会 import 目标文件中定义的 template,而不会 import 目标文件中 import 的 template,简言之就是 import 不具有递归的特性。且看下面的例子:

    若C 引用 B,B 引用A,在C中可以使用B定义的 template,在B中可以使用A定义的 template ,但是C不能使用A定义的template,代码如下:

    A.wxml

    <!-- A.wxml -->
    <template name="A">
      <text> A template </text>
    </template>

    B.wxml

    <!-- B.wxml -->
    <import src="a.wxml"/>
    
    <template name="B">
      <text> B template </text>
    </template>

    C.wxml

    <!-- C.wxml -->
    <import src="b.wxml"/>
    
    <template is="A"/>  <!-- -->
    
    <template is="B"/>

    引用A模板时会触发一个警告,因为 b 中并没有定义模板 A。

    3.6.2include引用

    include 可以将目标文件中除了 <template/>外的整个代码引入,相当于是拷贝到 include 位置。

    test.wxml

    <view> header </view>

     index.wxml

    <!-- index.wxml -->
    <include src="test.wxml"/>
    
    <view> body </view>

    输出结果如下:

    3.7共同的属性和事件绑定

    1)hidden

    组件是否显示,默认是false,如果不显示设置为true即可。

    <view hidden="{{false}}">我是显示的</view>
    <view hidden="{{true}}">我是隐藏的</view>

    2)data-*

    自定义的组件属性,组件上触发的事件时,会把此属性的值发送给事件处理函数,事件处理函数通过e.target.dataset.name获取。

    <view data-name="张三"></view>

    需要注意的是,data-name不是固定的,可以自定义,如果是data-data,那么就通过e.target.dataset.data来获取,也就是通过data-后指定的名字来获取属性的值。具体的介绍见后面章节介绍。

    3)bind*/catch*

    组件的事件绑定,具体看下章节。

    3.8组件-图片 cover-image

    覆盖在原生组件之上的图片视图,类似于image,只不过它是绝对定位的,会悬浮在原生组件之上。

    <cover-image src="/img/images/xy1.jpg"></cover-image>

    3.9组件-视图 view

    它是原生的视图,类似于div标签,但在小程序中就使用view,不建议使用div。

    <view>
        <view>123</view>
        <view>456</view>
    </view>

    3.10组件-图标 icon

    图标有几种类型,使用时需指定type,而size默认值是23,可调整;color也是可设置。text是文本标签。

    <view class="icon-box">
        <view class="inline">
            <icon type="success"></icon>
        </view>
        <view class="title">成功
            <text class="title-info">success</text>
        </view>
    </view>
    <view class="icon-box">
        <view class="inline">
            <icon type="download"></icon>
        </view>
        <view class="title">下载
            <text class="title-info">download</text>
        </view>
    </view>
    <view class="icon-box">
        <view class="inline">
            <icon type="info"></icon>
        </view>
        <view class="title">提示
            <text class="title-info">info</text>
        </view>
    </view>
    <view class="icon-box">
        <view class="inline">
            <icon type="warn" color="#C9C9C9"></icon>
        </view>
        <view class="title">普通警告
            <text class="title-info">warn</text>
        </view>
    </view>
    <view class="icon-box">
        <view class="inline">
            <icon type="warn"></icon>
        </view>
        <view class="title">强烈警告
            <text class="title-info">warn</text>
        </view>
    </view>
    <view class="icon-box">
        <view class="inline">
            <icon type="waiting"></icon>
        </view>
        <view class="title">等待
            <text class="title-info">waiting</text>
        </view>
    </view>
    <view class="icon-box">
        <view class="inline">
            <icon type="success_no_circle" size="33"></icon>
        </view>
        <view class="title">已选择
            <text class="title-info">success_no_circle</text>
        </view>
    </view>
    <view class="icon-box">
        <view class="inline">
            <icon type="circle"></icon>
        </view>
        <view class="title">未选择
            <text class="title-info">circle</text>
        </view>
    </view>
    <view class="icon-box">
        <view class="inline">
            <icon type="info_circle"></icon>
        </view>
        <view class="title">表单提示
            <text class="title-info">info_circle</text>
        </view>
    </view>
    <view class="icon-box">
        <view class="inline">
            <icon type="cancel"></icon>
        </view>
        <view class="title">停止或关闭
            <text class="title-info">cancel</text>
        </view>
    </view>
    <view class="icon-box">
        <view class="inline">
            <icon type="search"></icon>
        </view>
        <view class="title">搜索
            <text class="title-info">search</text>
        </view>
    </view>

    样式:

    .icon-box {
        text-align: center;
        margin-top: 20px;
    }
    
    .inline {
        margin-left: 50px;
        float: left;
    }
    
    .title-info {
        color: #9C9C9C;
    }

    效果图:

     

    3.11组件-按钮 button

    按钮属性如下表:

    属性 默认值 说明
    type default 按钮类型,default白色、primary绿色、warn红色
    size default 按钮尺寸大小,default默认,mini小尺寸
    plain false 按钮是否透明,设置true即可透明
    disabled false 是否禁用,true是禁用
    loading false 名称前是否带 loading 图标
     form-type    用于 form 组件,点击分别会触发 form 组件的 submit/reset 事件

     代码:

    <view>
        <view class="my-button" >
            <button type="primary" disabled="{{disabled}}">按钮</button>
        </view>
        <view class="my-button" >
            <button type="primary" plain="{{plain}}" >透明按钮</button>
        </view>
        <view class="my-button" >
            <button size="mini" loading="{{loading}}">小按钮</button>
        </view>
    </view>

    效果图:

    3.12组件-多选框 checkbox

    多选框分为默认样式和推荐样式:

    1)默认样式

    页面:

    <view>
        <view class="page-section-title">默认样式</view>
        <label class="checkbox" wx:for="{{hobby}}" wx:key="key">
            <checkbox value="{{item.value}}" checked="{{item.checked}}">{{item.label}}</checkbox>
        </label>
    </view>

    js:

    Page({
        data: {
            hobby:[
                {value:'1',label:'看书',checked:true},
                {value:'2',label:'打游戏'},
                {value:'3',label:'跑步'},
                {value:'4',label:'骑自行车',checked:true}
            ]
        },
    })

    效果图:

     2)推荐样式

    页面:

    <view>
        <view class="page-section">
            <view class="page-section-title">默认样式</view>
            <view class="weui-cells weui-cells_after-title">
                <checkbox-group bindchange="checkboxChange">
                    <label class="weui-cell weui-check__label" wx:for="{{hobby}}" wx:key="key">
                        <view class="weui-cell__hd">
                            <checkbox value="{{item.value}}" checked="{{item.checked}}" />
                        </view>
                        <view class="weui-cell__bd">{{item.label}}</view>
                    </label>
                </checkbox-group>
            </view>
        </view>
    </view>

    js:

    Page({
        data: {
            hobby:[
                {value:'1',label:'看书',checked:true},
                {value:'2',label:'打游戏'},
                {value:'3',label:'跑步'},
                {value:'4',label:'骑自行车',checked:true}
            ]
        },
        checkboxChange(e){
            console.log('选中的值为:', e.detail.value)
        }
    })

    效果图:

    推荐样式样式更好看,但要注意一个坑。其样式采用的weui样式,因此必须引入此依赖:在app.json中引入扩展组件

     "useExtendedLib": {
          "weui": true
      },

    3.13组件-单选框 redio

    只说明推荐样式。

    页面:

    <view>
        <view class="page-section">
            <view class="page-section-title">推荐样式</view>
            <view class="weui-cells weui-cells_after-title">
                <radio-group bindchange="radioChange">
                    <label class="weui-cell weui-check__label" wx:for="{{hobby}}" wx:key="key">
                        <view class="weui-cell__hd">
                            <radio value="{{item.value}}" checked="{{item.checked}}" />
                        </view>
                        <view class="weui-cell__bd">{{item.label}}</view>
                    </label>
                </radio-group>
            </view>
        </view>
    </view>

    js:

    Page({
        data: {
            hobby:[
                {value:'1',label:'看书'},
                {value:'2',label:'打游戏'},
                {value:'3',label:'跑步'},
                {value:'4',label:'骑自行车',checked:true}
            ]
        },
       radioChange(e){
            console.log('选中的值为:', e.detail.value)
        }
    })

    效果图:

    3.14组件-输入框 input和textarea

    文本框和多行输入框类型,其部分属性如下:

    属性 默认值 说明
    value   文本框初始内容
    type text 文本框类型,text文本输入键盘、number数字输入键盘、idcard身份证输入键盘、digit小数输入键盘。textarea无此属性
    password false 是否是密码框,true是。textarea无此属性
    placeholder   文本框占位符或提示文字
    disabled false 是否禁用,true禁用
    maxlength 140 最大输入长度,设置为 -1 的时候不限制最大长度,若限制了长度,当达到最大长度后就不能继续输入了
    focus false 是否自动获取焦点,true是
    bindinput   输入事件触发,详见事件绑定
    bindblur   文本框失去焦点时触发事件,详见事件绑定

    input页面:

    <view class="page-body">
        <view class="page-section">
            <view class="weui-cells__title">自动聚焦</view>
            <view class="weui-cells weui-cells_after-title">
                <view class="weui-cell weui-cell_input">
                    <input class="weui-input" focus placeholder="将会获取焦点" />
                </view>
            </view>
        </view>
        <view class="page-section">
            <view class="weui-cells__title">用户名:{{name}}</view>
            <view class="weui-cells weui-cells_after-title">
                <view class="weui-cell weui-cell_input">
                    <input class="weui-input" value="{{name}}" bindinput="bindKeyInput" />
                </view>
            </view>
        </view>
        <view class="page-section">
            <view class="weui-cells__title">密码</view>
            <view class="weui-cells weui-cells_after-title">
                <view class="weui-cell weui-cell_input">
                    <input class="weui-input" placeholder="密码" maxlength="10" />
                </view>
            </view>
        </view>
        <view class="page-section">
            <view class="weui-cells__title">数字输入</view>
            <view class="weui-cells weui-cells_after-title">
                <view class="weui-cell weui-cell_input">
                    <input class="weui-input" type="number" placeholder="数字输入" maxlength="5" />
                </view>
            </view>
        </view>
    </view>

    input的js:

    Page({
        data: {
            name: '张三'
        },
        bindKeyInput(e) {
            this.setData({
                name: e.detail.value
            })
        }
    })

    现象是页面打开时,光标自动在第一个输入框闪烁,输入用户名是,文本框上面的值也会发生变化,密码是隐藏不可见的,数字输入5位就不能输入了。这里的文本框包括后面的几乎都是为表单做铺垫。

    textarea页面:

    <view class="page-section">
            <view class="weui-cells__title">备注</view>
            <view class="weui-cells weui-cells_after-title">
                <view class="weui-cell weui-cell_input">
                    <textarea class="weui-input" placeholder="备注"/>
                </view>
            </view>
    </view>

    3.15组件-日期时间组件 picker

    从底部弹起的滚动选择器。它最重要是属性是mode,用来指定选择器的类型,其值有selector、multiSelector、time、date和region,具体说明且看后续。

    对于不同的mode,picker拥有不同的属性,请看介绍。

    1)selector:普通选择器

    属性 类型 默认值 描述
    range array/object array [] 选择的范围
    range-key string   当 range 是一个 Object Array 时,通过 range-key 来指定 Object 中 key 的值作为选择器显示内容
    value number 0 表示选择了 range 中的第几个(下标从 0 开始)
    bindchange     value 改变时触发 change 事件

    下面的页面使用了两种类型的数组呈现:

    <picker mode="selector" bindchange="bindPickerChange" value="{{index}}" range="{{array}}">
        <view class="picker">
            当前选择的是1:{{array[index]}}
        </view>
    </picker>
    
    <picker mode="selector" bindchange="bindPickerChange2" value="{{objectArray[objIndex].id}}" range="{{objectArray}}" range-key="name">
        <view class="picker">
            当前选择的是2:{{objectArray[objIndex].name}}
        </view>
    </picker>

    js:

    Page({
        data: {
            array: ['美国', '中国', '巴西', '日本'],
            index: 1,
            objectArray: [{
                    id: 0,
                    name: '2016年'
                },
                {
                    id: 1,
                    name: '2017年'
                },
                {
                    id: 2,
                    name: '2018年'
                },
                {
                    id: 3,
                    name: '2019年'
                }
            ],
            objIndex: 3
        },
        bindPickerChange(e) {
            console.log('picker发送选择改变,值为', e.detail.value)
            this.setData({
                index: e.detail.value
            })
        },
        bindPickerChange2(e) {
            console.log('picker发送选择改变,值为', e.detail.value)
            this.setData({
                objIndex: e.detail.value
            })
        },
    })

    2)multiSelector:多列选择器

    属性 类型 默认值 描述
    range array/object array [] 选择的范围
    range-key string   当 range 是一个 Object Array 时,通过 range-key 来指定 Object 中 key 的值作为选择器显示内容
    value number 0 表示选择了 range 中的第几个(下标从 0 开始)
    bindchange     value 改变时触发 change 事件
    bindcolumnchange     列改变时触发

     页面:

    <picker mode="multiSelector" bindchange="bindMultiPickerChange" value="{{multiIndex}}"
     range="{{multiArray}}">
        <view class="picker">
            当前选择:{{multiArray[0][multiIndex[0]]}},{{multiArray[1][multiIndex[1]]}},{{multiArray[2][multiIndex[2]]}}
        </view>
    </picker>

    js:

    Page({
        data: {
            multiArray: [
                ['无脊柱动物', '脊柱动物'],
                ['扁性动物', '线形动物', '环节动物', '软体动物', '节肢动物'],
                ['猪肉绦虫', '吸血虫']
            ],
            multiIndex: [0, 0, 0],
        },
         bindMultiPickerChange: function (e) {
            console.log('picker发送选择改变,携带值为', e.detail.value)
            this.setData({
              multiIndex: e.detail.value
            })
          },
    })

    3)time:时间选择器

    属性 类型 默认值 描述
    value string   选中的时间,格式为"hh:mm"
    start string   有效时间范围的开始,字符串格式为"hh:mm"
    end string 0 有效时间范围的结束,字符串格式为"hh:mm"
    bindchange     value 改变时触发 change 事件

    对于时间选择器,只能选择到分钟,若不指定有效开始时间和结束时间,那么默认从00:00到23:59可选。且看实例:

    页面:

    <picker mode="time" bindchange="bindPickerChange" value="{{time}}" start="{{start}}" end="{{end}}">
        <view class="picker">
            当前选择时间:{{time}}
        </view>
    </picker>

    js:

    Page({
        data: {
            time:'14:20',
            start:'10:30',
            end:'20:59'
        },
         bindPickerChange: function (e) {
            console.log('picker发送选择改变,携带值为', e.detail.value)
            this.setData({
              multiIndex: e.detail.value
            })
          },
    })

    4)date:日期选择器

    属性 类型 默认值 描述
    value string 当天 选中的日期,格式为"YYYY-MM-DD"
    start string   有效日期范围的开始,字符串格式为"YYYY-MM-DD"
    end string   有效日期范围的结束,字符串格式为"YYYY-MM-DD"
    fields string day 有效值 year,month,day,表示选择器到哪一粒度,如指定month则只选择到月份
    bindchange     value 改变时触发 change 事件

    有两个示例,一个使用默认值,一个指定了fields到月份,具体如下:

    页面:

    <picker mode="date" bindchange="bindDateChange" value="{{date}}" start="{{start}}" end="{{end}}">
        <view class="picker">
            当前选择日期:{{date}}
        </view>
    </picker>
    
    <picker mode="date" bindchange="bindDateChange2" value="{{date1}}" fields="month">
        <view class="picker">
            当前选择日期:{{date1}}
        </view>
    </picker>

    js:

    Page({
        data: {
            date: '2020-12-08',
            start: '2020-01-01',
            end: '2020-12-30',
            date1: '2020-12',
        },
        bindTimeChange: function(e) {
            console.log('picker发送选择改变,携带值为', e.detail.value)
            this.setData({
                time: e.detail.value
            })
        },
        bindDateChange: function(e) {
            console.log('picker发送选择改变,携带值为', e.detail.value)
            this.setData({
                date: e.detail.value
            })
        },
        bindDateChange2: function(e) {
            console.log('picker发送选择改变,携带值为', e.detail.value)
            this.setData({
                date1: e.detail.value
            })
        },
    })

    5)region:省市区选择器

    属性 类型 默认值 描述
    value array [] 选中的省市区,默认选中每一列的第一个值
    bindchange     value 改变时触发 change 事件

    省市区选择时使用微信的数据,只需存储文字即可。

    页面:

    <picker mode="region" bindchange="bindRegionChange" value="{{region}}" >
        <view class="picker">
            当前选择区:{{region[0]}}{{region[1]}}{{region[2]}}
        </view>
    </picker>

    js:

    Page({
        data: {
            region: ['广东省', '深圳市', '龙华区']
        },
        bindRegionChange(e) {
            console.log('picker发送选择改变,携带值为', e.detail.value)
            this.setData({
                region: e.detail.value
            })
        }
    })

    3.16组件-开关 switch

    开关主要说明一下类型,有switch和checkbox类型。

    页面:

    <view class="section__title">type="switch"</view>
    <view class="body-view">
        <switch checked="{{switch1Checked}}" bindchange="switch1Change" />
    </view>
    
    <view class="section__title">type="checkbox"</view>
    <view class="body-view">
        <switch type="checkbox" checked="{{switch2Checked}}" bindchange="switch2Change" />
    </view>

    js:

    Page({
        data: {
            switch1Checked: true,
            switch2Checked: false,
        },
        switch1Change(e){
            console.log('按钮1改变,值是:'+e.detail.value)
            this.setData({
                switch1Checked:e.detail.value
            })
        },
        switch2Change(e){
            console.log('按钮2改变,值是:'+e.detail.value)
            this.setData({
                switch2Checked:e.detail.value
            })
        }
    })

    效果:

     

    3.17组件-表单 form

     对于表单,主要就是表单提交事件bindsubmit,详见事件章节。另外,需要给每个输入框(包括单选框、多选框等)添加name属性,原因是在表单提交时会根据name属性去获取值。提交按钮只需要指定formType类型是submit即可。示例如下:

    页面:

    <view class="container">
        <form bindsubmit="formSubmit" bindrest="formRest">
            <view class="inbox">
                <label class="label">姓名<span style="color: red;">*</span></label>
                <input placeholder="姓名" value="{{form.name}}" name="name" maxlength="50"/>
            </view>
            <view class="inbox">
                <label class="label">密码<span style="color: red;">*</span></label>
                <input placeholder="密码" value="{{form.password}}" password="true" name="password" maxlength="50"/>
            </view>
            <view class="inbox">
                <label class="label">性别<span style="color: red;">*</span></label>
                <radio-group bindchange="radioChange" name="sex">
                    <radio class="radio-group-col" value="{{item.value}}" wx:for="{{sexOption}}" wx:key="key" checked="{{item.checked}}">
                        <text>{{item.label}}</text>
                    </radio>
                </radio-group>
            </view>
            <view class="inbox">
                <label class="label">爱好</label>
                <checkbox-group bindchange="checkboxChange" name="hobby">
                    <checkbox class="checkbox-group-col" wx:for="{{hobbyOption}}" wx:key="key" value="{{item.value}}" checked="{{item.checked}}">
                        <text>{{item.label}}</text>
                    </checkbox>
                </checkbox-group>
            </view>
            <view class="inbox">
                <label class="label">出生日期<span style="color: red;">*</span></label>
                <picker mode="date" bindchange="bindDateChange" value="{{form.brith}}" end="{{brithEnd}}">
                    <input placeholder="出生日期" name="brith" value="{{form.brith}}" />
                </picker>
            </view>
            <view class="inbox">
                <label class="label">输入时间<span style="color: red;">*</span></label>
                <picker mode="time" bindchange="bindTimeChange" value="{{form.nowTime}}">
                    <input placeholder="输入时间" name="nowTime" value="{{form.nowTime}}" />
                </picker>
            </view>
            <view class="inbox">
                <label class="label">所在地区<span style="color: red;">*</span></label>
                <picker mode="region" bindchange="bindRegionChange" value="{{region}}">
                    <input placeholder="所在地区" name="region" value="{{form.region}}" />
                </picker>
            </view>
            <view class="inbox">
                <label class="label">详细地址</label>
                <textarea class="textarea" placeholder="详细地址" name="addr" value="{{form.addr}}" maxlength="2000"/>
                </view>
            <view class="btn-group">
                <button type="primary" formType="submit">提交</button>
                <button formType="reset">取消</button>
            </view>
        </form>
    </view>

    js:

    const now = new Date()
    //导入工具类
    const util = require('../../utils/util.js');
    
    Page({
        data: {
            form: {},
            sexOption: [{
                    label: '',
                    value: 0
                },
                {
                    label: '',
                    value: 1
                }
            ],
            hobbyOption: [{
                    value: '1',
                    label: '看书',
                    checked: true
                },
                {
                    value: '2',
                    label: '打游戏'
                },
                {
                    value: '3',
                    label: '跑步'
                },
                {
                    value: '4',
                    label: '骑自行车',
                    checked: true
                }
            ],
            brithEnd: now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate(),
            region: []
        },
    
        //日期发生变化
        bindDateChange(e) {
            this.setData({
                'form.brith': e.detail.value
            })
        },
        //时间发生变化
        bindTimeChange(e) {
            this.setData({
                'form.nowTime': e.detail.value
            })
        },
        //地区发生变化
        bindRegionChange(e) {
            const region = e.detail.value
            this.setData({
                'region': region,
                'form.region': region[0] + region[1] + region[2]
            })
        },
        //多选按钮发生变化
        checkboxChange(e) {
            this.setData({
                'form.hobby': e.detail.value
            })
        },
        //单选按钮发生变化
        radioChange(e) {
            this.setData({
                'form.sex': e.detail.value
            })
        },
        //表单提交
        formSubmit(e) {
            const form = e.detail.value
            let isChecking = false
            if (!util.isNotBlank(form.name)) {
                isChecking = true
            } else if (!util.isNotBlank(form.password)) {
                isChecking = true
            } else if (!util.isNotBlank(form.sex)) {
                isChecking = true
            } else if (!util.isNotBlank(form.brith)) {
                isChecking = true
            } else if (!util.isNotBlank(form.nowTime)) {
                isChecking = true
            } else if (!util.isNotBlank(form.region)) {
                isChecking = true
            }
            if (isChecking) {
                wx.showToast({
                    title: "带*号为必填项",
                    icon: 'none',
                    duration: 2000
                })
            } else {
                this.data.form = form
                wx.showModal({
                    title:'表单内容' ,
                    icon: 'none',
                    content:JSON.stringify(form)
                })
            }
        },
    
    })

    页面样式:

    .checkbox-group-col {
        padding-left: 15px;
    }
    
    .radio-group-col{
        padding-right: 30px;
    }

    全局样式:

    /* *app.wxss* */
    .container {
        height: 100%;
        flex-direction: column;
        align-items: center;
        justify-content: space-between;
        padding: 10rpx 0 0 0;
        box-sizing: border-box;
    }
    
    .inbox {
        display: flex;
        margin: 20px 0 0 20px;
        padding-bottom: 10px;
        border-bottom: 1px solid var(--weui-FG-3);
        font-size: 18px;
    }
    
    .inbox .label {
         30%;
    }
    
    .textarea {
        height: 80rpx;
        margin-left: 20rpx;
    }
    
    .btn-group {
        display: flex;
        margin: 10px;
        /* 样式居中 */
        align-items: center;
        justify-content: center;
    }
    
    button {
         30% !important;
    }

    工具类方法:

    //是否为空
    const isNotBlank = val => {
        return val != null && val != ''
    }
    
    module.exports = {
      isNotBlank: isNotBlank
    }

    效果图:

    对于picker组件,当里面存放的input标签时,作为表单的输入,需要使用disabled把输入框设置为禁用,只能通过选择时间来输入,不能手动输入。原因是如果不禁用那么在选择时会同时弹出选择框和输入框,界面很不友好。

    4.js详解

    4.1App.js

    1)文件包裹

    app中,使用App构造器把整个文件包裹起来,所有的方法和变量都写在里面。对于方法,可直接按照ES6语法定义即可,而对于变量,需要放到data的属性中。

    App({
      data: {
          msg:'今天天气真好'  
      },
      test(){
        console.log(123)  
     }
    })

    2)系统方法

    另外在app.js中有一些默认的方法提供使用,如onLaunch方法,此方法是在页面加载完成会自动调用的,可以在里面进行数据的初始化。

    App({
      data: {
          onLoad: function (option){
              
           },
    })

    其方法中有一个参数,是一个对象,当进行页面跳转进行参数拼接传递时,就可以使用对应的参数来获取。示例如下:

    --index.js
    wx.navigateTo({
          url:'/pages/test/test?name=zys&age=20'
    })
    
    --test.js
    Page({
        onLoad:function(option){
            console.log(option.name)
            console.log(option.age)
        }
    })

    3)全局参数

    有些参数需要很多地方使用,就可以设置为全局的,需要在App.js中设置。其中有个对象globalData,里面是用来存放全局参数的。设置参数后在其他页面文件通过导入的方法,就可以使用其中的变量了。

    App.js设置全局参数:

    App({
       globalData: {
            userInfo: null
       }
    })

    index.js导入并使用参数:

    //获取应用实例
    const app = getApp()
    
    Page({
          onLoad: function (option){
              app.globalData.userInfo = 'admin'
              //console.log(app.globalData.userInfo)
          },
    })

    不仅可以直接使用这个值,还可以修改这个值。

    4.2页面js

    页面js就拿index.js为例说明。与app.js不同的是,它是通过Page构造器包裹的,也没有globalData参数。page构造器用来注册一个小程序页面。

    Page({
          onLoad: function (option){
          ...
          }
    })

    4.2.1使用setData设置值

    在页面js中获取变量的值,使用this.data来获取。但是要修改值,不能全部使用this.data,在很多情况下需要使用this.setData来设置值,this.setData将数据从逻辑层发送到视图层,同时改变对应的data的值。简单的说,就是保证js和界面的数据是同步的。

    Page({
        data: {
            name: 'admin'
        },
        onLoad: function() {
            //获取值
            console.log(this.data.name)
            //设置值:方法一
            this.data.name = '张三'
            //设置值:方法二
            this.setData({
                name:'李四'
            })
        },
    })

    若设置值,推荐使用第二种方法。

    需要注意的是,小程序中,当使用setData对对象或属性赋值时,用法是不一样的:

    (1)给对象直接赋值

    const myuser = {name:'张三',age:20}
    this.setData({
        user: myuser
    })

    (2)给对象的某个属性赋值

    const myuser = {name:'张三',age:20}
    this.setData({
        'user.name': myuser.name
    })

    注意区别就是给对象的某个属性赋值时,需要用引号括起来

    4.2.2系统内置的方法

    onLoad:页面加载完成时调用。页面初次加载的时候,微信客户端就会给Page实例派发onLoad事件,Page构造器参数所定义的onLoad方法会被调用,onLoad在页面没被销毁之前只会触发1次。

    onShow:小程序启动或切前台时调用。

    5.事件

    事件绑定分为两种,bind绑定和catch绑定,区别是catch能阻止事件冒泡。具体事件绑定以bind绑定为例,在bind后加上对应的事件名即可,也可以通过冒号的方式进行绑定,bindtap和bind:tap是一样的效果。以下只介绍常用的事件。

    5.1事件对象

    当事件回调触发的时候,会收到一个事件对象,对象的部分属性如下:

    type:事件类型
    target:触发事件的组件的一些属性值集合
    currentTarget:当前组件的一些属性值集合
    detail:额外的信息
    

     额外的信息主要用于事件获取参数值,一般使用event.detail.value来获取。

    5.1.1target和currTarget的区别

    对于target和currTarget,它们作用是不一样的,currentTarget为当前事件所绑定的组件,而target则是触发该事件的源头组件。下面的例子就是很好的说明:

    <!-- wxml -->
    <view catchtap="handleTap" data-name="outer">
      <view data-name="inner">点击我</view>
    </view>
    
    <!-- js -->
    Page({
        handleTap(e){
            console.log(e.target.dataset.name)//inner
            console.log(e.currentTarget.dataset.name)//outer
        }
    })

    5.1.2target和currentTarget的属性

    一般通过dataset来获取data-*的属性值,且看后续的章节介绍。推荐使用currentTarget,它在小程序中使用的很多,原因是小程序中事件的方法不能传递参数,只能通过属性值的方式传递并获取。

    5.2 tap

    绑定点击事件,点击时会触发指定的方法,会给方法传递一个事件对象。

    <!--wxml-->
    <view>
        <button bindtap="myTest">我是点击事件,点我触发</button>
    </view>
    
    <!--js-->
    Page({
        data: {},
        myTest(e){
           console.log(e)
           console.log(e.currentTarget.dataset)
        }
    })

    5.3 input

    绑定文本框事件,结合detail属性用于在逻辑层获取文本框输入的值。

    <!-- wxml -->
    <input type="text" bindinput="input" data-name="username" placeholder="请输入用户名"/>
    <input password='true' bindinput="input" data-name="password" placeholder="请输入密码"/>
    <button bindtap="getValue" type="primary">点我获取内容</button>
    
    <!-- js -->
    Page({
        data: {
            user:{
                username:'',
                password:''
            }
        },
        input(e){
            //获取data-name的值
            const key = e.currentTarget.dataset.name
            //获取文本框的值
            const value = e.detail.value
            this.data.user[key] = value
        },
        getValue(e){
            console.log(this.data.user)
        }
    })

    当输入数据后,点击按钮即可在输出对应的内容。输入结果如下:

    5.4 longpress

    手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发,如果不超过350ms就会触发tap事件,一般情况下只使用tap事件进行点击触发。

    <!-- wxml -->
    <button bindtap="tapHandle" bindlongpress="longpressHandle" type="primary">点我获取内容</button>
    
    <!-- js -->
    Page({
        tapHandle(e){
            console.log(111)
        },
        longpressHandle(e){
            console.log(222)
        }
    })

    5.5 submit

    绑定表单,绑定后通过detail来获取表单的具体数据。

    <!-- wxml -->
    <form bindsubmit="formSubmit">
        <text>账号:</text>
        <input type="text" placeholder='请输入账号' name="username" />
    
        <text>密码:</text>
        <input password='true' placeholder='请输入密码' name="password" />
    
        <button type='primary' form-type='submit'>登录</button>
    </form>
    
    <!-- js -->
    Page({
        formSubmit(e) {
            //获取表单数据的值
            const obj = e.detail.value
            console.log(obj)
        },
    })

    输入数据点击按钮即可看到数据。

    5.6confirm

    回车事件,点击回车按钮时触发。可用于输入框或按钮。

    <!-- wxml -->
    <input type="text" bindinput="input" bindconfirm="searchSubmit" placeholder="搜索"/>
    
    <!-- js -->
    Page({
        data: {
            username: ''
        },
        onLoad() {},
        input(e) {
            this.setData({
                username: e.detail.value
            })
        },
        searchSubmit(e) {
            console.log(this.data.username)
        }
    })

    输入数据后回车就可以看到打印的结果。

    6.WXSS

    WXSS全称是WeiXin Style Sheets,它是一套用于小程序的样式语言,用于描述WXML的组件样式的文件。

    6.1WXSS尺寸和位置

    上图是wxss的存放位置,其中公共样式放在app.wxss中,页面自己的也是放到页面目录下。

    在WXSS中,引入了rpx尺寸单位。目的是,适配不同宽度的屏幕,解决同一px在不同屏幕下的占比问题。小程序编译后,rpx会做一次px换算。换算是以375个物理像素为基准,也就是在一个宽度为375物理像素的屏幕下,1rpx = 1px。

    6.2WXSS引用

    在小程序中,需要引入其他的样式文件,引入方式是@import 样式文件路径,例子:

    引入当前目录下的test样式文件

    @import './test.wxss'

    7.常用API

    7.1路由

    路由的几种类型对比如下表:

    方法 说明 使用
    wx.reLaunch 关闭所有页面,打开到应用内的某个页面 wx.reLaunch({url:'url'})
    wx.redirectTo

    关闭当前页面,跳转到应用内的某个页面,

    但是不允许跳转到 tabbar 页面

    wx.redirectTo({url:'url'})
    wx.navigateTo

    保留当前页面,跳转到应用内的某个页面,

    但是不能跳到 tabbar 页面。

    页面栈最多十层,使用navigateBack返回上一层

    wx.navigateTo({url:'url'})
    wx.navigateBack 关闭当前页面,返回上一页面或多级页面 wx.navigateBack()

    前3个方法都可以传递参数,在跳转后的页面onload方法中获取参数的值,以navigateTo为例说明:

    index.wxml:

    <button type="primary" bindtap="goNext">进入下一页</button>

    index.js:

    Page({
        goNext(e) {
            wx.navigateTo({
                url: '/pages/test2/test2?name=zss&age=20'
            })
        }
    })

    test.wxml:

    <view>
        传递的参数:{{user.name+","+user.age}}
    </view>

    test.js:

    Page({
        data: {
            user: {}
        },
        onLoad: function(options) {
            console.log(options)
            this.setData({
                user: options
            })
        },
    
    })

    7.2消息框

    先看下表的分类:

    类型 消息提示框 模态对话框  loading 提示框 操作菜单
    方法 wx.showToast wx.showModal wx.showLoading wx.showActionSheet

    且看详细说明:

    1)wx.showToast

    属性 类型 说明
    title string 提示的内容
    icon string

    默认值是success。提示的图标。

    success:成功图标,此时 title 文本最多显示 7 个汉字长度

    none:不显示图标,此时 title 文本最多可显示两行

    duration number 默认值是number,提示显示的时间,但是是毫秒。

    下面包含有图标和无图标的例子:

    wx.showToast({
         title:'成功提示',
         duration:2000
    })
    wx.showToast({ title:
    '无图标提示', icon:'none' })

    2)wx.showModal

    属性 类型 说明
    title string 提示的标题
    context string

    提示的内容

    showCancel boolean

    默认值是true。是否显示取消按钮。

    cancelText string 默认值是'取消',取消按钮的文字,最多 4 个字符。
    confirmText string 默认值是'确定',取消按钮的文字,最多 4 个字符.
    success function

    接口调用成功的回调函数。函数的参数有两个属性:

    confirm为true时表示用户点击了确定按钮,cancel为true时表示用户点击了取消按钮

    下面包含有删除按钮和无删除按钮的例子:

    wx.showModal({
        title:'消息提示',
        content:'您确定要删除吗?',
        success:function(res){
            if(res.confirm){
                console.log('点击了确定')
            }else if(res.cancel){
                console.log('点击了取消')
            }
        },
    })
    
    wx.showModal({
        title: '消息提示',
        content: '操作成功',
        showCancel: false,
        success: function(res) {
            console.log('点击了确定')
        },
    })

    3)wx.showLoading

    其最重要的属性就是title,加载时提示的文字。如果不关闭则会一直加载,关闭使用wx.hideLoading()。

    下面例子是加载弹框显示5秒后自动关闭,在实际情况中是数据加载完成后关闭。

    wx.showLoading({
        title: '加载中',
    })
    setTimeout(function() {
        //关闭加载框
        wx.hideLoading()
    }, 5000)

    4)wx.showActionSheet

    属性 类型 说明
    itemList Array,元素是string 按钮的文字数组,数组长度最大为 6
    success function

    接口调用成功的回调函数。函数的参数有属性tapIndex:

    表示用户点击的按钮序号,从上到下的顺序,从0开始

    下面例子是选择了不同的菜单就显示不同的值

    const arr = ['A', 'B', 'C']
        wx.showActionSheet({
        itemList: arr,
        success(res) {
            console.log("您选择了:" + arr[res.tapIndex])
        },
    })

    7.3网络

    小程序请求后台时,必须要联网,没有网络是请求不到后台的。另外,部分域名需要先通国小程序后台设置为信任域名才能去请求访问。需要注意是,如果需要在请求后使用this,那么必须在请求之前先定义一个变量存储this,然后在请求后使用定义的变量,不能直接使用this,此时this的null。请求的方式如下表:

    属性 说明
    url 请求的路径
    method 请求的方法,包括GET(默认)、POST、DELETE、PUT
    data 传递的参数,必须是一个对象
    header

    请求头信息,属性content-type的默认值是application/json。可在其中添加token等认证信息

    success

    接口调用成功的回调函数,有参数response,数据是其中的data,即response.data

    1)get请求

    wx.request({
        url:'https://autumnfish.cn/api/joke/list',
        data:{
            num: 5
        },
        success(res){
            console.log(res.data)
        }
    }),

    2)post请求

    post直接传递对象,后台通过@RequestBody接收;

    先看第一种:

    wx.request({
        url:'https://autumnfish.cn/api/user/reg',
        data:{
            username:'123456556'
        },
        method:'POST',
        success(res){
            console.log(res.data)
        }
    })

    3)请求的封装

    post请求的另一种方式是把参数拼接在请求路径后面,后台通过@RequestParam接收。

    const app = getApp();
    
    function get(url, callback) {
        wx.request({
            method: 'GET',
            url: url,
            header: {
                'token': app.globalData.token
            },
            success(res) {
                callback(res.data);
            }
        })
    }
    
    function post(url, data, callback) {
        wx.request({
            method: 'POST',
            url: url,
            data: data,
            header: {
                'token': app.globalData.token
            },
            success(res) {
                callback(res.data);
            }
        })
    }
    
    function postParam(url, data, callback) {
        const keys = Object.keys(data)
        let params = '?'
        for (let i = 0; i < keys.length; i++) {
            const key = keys[i]
            let value = data[key]
            if (value != null && value != '') {
                if (i != 0) {
                    params += '&'
                }
                //对特殊字符进行转义
                value = encodeURIComponent(value)
                params += key + '=' + value
            }
    
        }
        wx.request({
            method: 'POST',
            url:url + params,
            header: {
                'token': app.globalData.token
            },
            success(res) {
                callback(res.data);
            }
        })
    }

    7.4数据缓存

    数据缓存分为存数据、取数据和删除数据。缓存就是把数据存到本地,允许存储的最大长度是1M,最大数据是10M。主要介绍同步操作。

    1)setStorageSync:对指定的key存储value

    wx.setStorageSync("username","zys")

    2)getStorageSync:获取指定key的value

    const username = wx.getStorageSync("username")

    3)removeStorageSync:删除指定key的value

    wx.removeStorageSync("username")

    7.5用户登录

    小程序登录时需要先给微信发送请求,获取此用户唯一的openid,后期用户的唯一性验证就需要它,详细的配置请看官网或参考demo,代码地址https://github.com/zhongyushi-git/mini-program.git。

    7.6图片的下载

    图片下载时,一般需要保存到系统相册中。实例如下:

    wxml:

    <view>
        <button type="warn" bindtap="download">下载图片</button>
    </view>

    js:

    Page({
        download(){
            const url ='http://192.168.43.123:8887/image/5.jpg'
            //下载文件到本地
            wx.downloadFile({
                url:url,
                success(res){
                    //把图片保存到系统相册
                    wx.saveImageToPhotosAlbum({
                        filePath:res.tempFilePath,
                        success(resp){
                            wx.showToast({
                                title:'保存成功',
                                icon:'success',
                                duration:2000
                            })
                        },
                        fail(err){
                            console.log('保存错误',err)
                        }
                    })
                },
                fail(err){
                    console.log('下载错误',err)
                }
            })
        },
        
    })

    点击按钮就可以把图片保存到本地相册了,不过需要注意的是,url必须是图片的地址,不能是字节流。

    8.自定义组件

    8.1创建组件

    组件的结构和普通页面的结构类似,但也不完全相同,在js中,它使用的是Component构造器,其中是属性也有所不同;另外在json文件中需要指定是组件。

    1)在项目根目录下新建一个component目录,再创建子目录mycon目录

    2)在微信开发者工具中选择mycon目录,然后右键新建component,就会自动生成组件的相关配置

    3)mycon.json的内容:指定是组件

    {
      "component": true,
      "usingComponents": {}
    }

    4)编辑mycon.js内容:

    Component({
        /**
         * 组件的属性列表
         */
        properties: {
            titles:{
                type:Array,
                value:[]
            }
        },
        /**
         * 组件的方法列表
         */
        methods: {
            handleChange(e) {
                const index = e.currentTarget.dataset.index
                const {
                    titles
                } = this.data
                titles.forEach((item, i) => i == index ? item.isActive = true : item.isActive = false)
                this.setData({
                    titles
                })
                //子组件调用父组件的方法,可传递参数
                this.triggerEvent('itemChange',{index})
            }
        }
    })

    在组件中,使用了slot标签,他相当于一个占位符,当传值时会将其替换为传递的内容。

    5)wxss样式:

    .title{
        display: flex;
        padding: 10px;
    }
    
    .title-item{
        flex:1;
        display: flex;
        /*垂直水平居中*/
        justify-content: center;
        align-items: center;
    }
    
    .active{
        color: red;
        border-bottom: 1px solid currentColor;
    }

    8.2声明组件

    在需要使用组件的页面的json中声明组件

    {
      "usingComponents": {
          "mycon":"../../components/mycon/index"
      }
    }

    是以键值对的形式声明的,key是指定的组件的名称,value是组件的路径,一般使用相对路径。

    8.3使用组件

    声明之后,在wxml中直接使用即可。

    wxml内容:

    <mycon titles="{{titles}}" binditemChange="handleItemChange">
        <view>
            <block wx:if="{{titles[0].isActive}}">我是首页内容</block>
            <block wx:elif="{{titles[1].isActive}}">我是分类内容</block>
            <block wx:else>我是原创内容</block>
        </view>
    </mycon>

    js内容:

    Page({
        data: {
            titles: [{
                    name: '首页',
                    isActive: true
                },
                {
                    name: '分类',
                },
                {
                    name: '原创',
                }
            ]
        },
        handleItemChange(e){
            const {
                titles
            } = this.data
            titles.forEach((item, i) => i == e.detail.index ? item.isActive = true : item.isActive = false)
            this.setData({
                titles
            })
        }
    })

      效果图如下:

    8.4组件传值说明

    在上述自定义组件中,存在父子组件之间的传值,在此讲解。

    1)父组件向子组件传值

    父组件向子组件传递时,只需要在子组件的标签上添加对应的属性,然后在子组件中获取即可。在此实例中,父组件给子组件传递了标题数组titles,子组件在properties中接收并指定类型和默认值。

           

    2)子组件向父组件传递方法

    子组件给父组件传值时,需要通过方法的方式传递,即调用父组件的方法,把值放到参数中。在此实例中,子组件通过triggerEvent方式调用父组件的方法,并传递了参数,父组件在标签上定义了方法。

       

     

     图片上传

    <view>
        <mp-uploader title="提示    " tips="图片上传提示" delete="false" max-size="{{10*1024*1024}}" max-count="5" files="{{files}}"
         upload="{{uplaodFile}}" bindfail="uploadError" bindsuccess="uploadSuccess"></mp-uploader>
         <button bindtap="saveImg">保存</button>
    </view>
    Page({
        data: {
            files: [],
            filePath: []
        },
        onLoad() {
            this.setData({
                uplaodFile: this.uplaodFile.bind(this)
            })
        },
        //文件上传的函数,返回一个promise
        uplaodFile(files) {
            this.data.files = this.data.files.concat(files.tempFilePaths);
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve({
                        urls: files.tempFilePaths
                    })
                }, 1000)
            })
        },
        //上传失败的回调
        uploadError(e) {
            console.log('图片上传失败', e.detail)
        },
        //上传成功的回调
        uploadSuccess(e) {
            console.log('图片上传成功', e.detail)
        },
        //把图片上传到服务器
        saveImg() {
            //一次上传一张图片
            const files = this.data.files
            for (var i = 0; i < files.length; i++) {
                wx.uploadFile({
                    url: 'http://localhost:8080/file/upload',
                    filePath: files[i],
                    name: 'file',
                    complete: (res) => {
                        this.data.filePath.push(res.data)
                        if (i === files.length) {
                            wx.showToast({
                                title: '上传成功'
                            })
                            console.log('图片路径:' + this.data.filePath)
                        }
                    }
                })
            }
    
    
        }
    })
  • 相关阅读:
    pix-PID介绍
    我的四轴专用PID参数整定方法及原理---超长文慎入(转)
    卡尔曼滤波原理
    5种常用的四轴飞行器PID算法讲解集合
    深入浅出无人机姿态,欧拉角,四元数,指数表示及数据转换与程序实现
    理解四元数
    Normal Equation(正规方程)
    特征与多项式回归
    实际梯度下降中的两个重要调节方面
    BZOJ 3624 Apio2008 免费道路
  • 原文地址:https://www.cnblogs.com/zys2019/p/14032885.html
Copyright © 2011-2022 走看看