小程序开发经验

小程序

一、起步

1、开发者工具

下载地址

2、开发者账户

  • 注册地址:下一步下一步的注册
  • 成功后进入页面,点开发=>开发设置,就可以看到AppID账号

3、创建项目

  • 新建文件夹
  • 打开开发工具,将文件地址输入,不选择云开发
  • 然后就会自动初始化项目文件

4、预览项目

  • 点开发工具预览功能,生成二维码
  • 手机微信扫描查看
  • 体验人员管理,在注册地址成功页面的成员管理进行配置

二、开发

1、文件介绍

  1. project.content.js:项目配置文件

    • 建议在详情内选项修改
    • 自己可以改AppIDprojectname
  2. sitemap.json:配置小程序索引,基本都是可索引

  3. App.js:注册小程序

  4. app.json:全局配置

    • pages:配置路由

    那个路由在上面就那个为首页

    • window:配置窗口表现,

    导航栏颜色,字体,字色,窗口背景色,下拉loading,

    是否下拉刷新,上拉到顶部距离,屏幕旋转

    • entryPagePath:不按照pages顺序,指定首页
    • 替他略
  5. app.wxss:就是css文件:微信不能使用ID选择器

  6. pages:里面是页面文件

  7. static:自己创建的文件夹,放置静态文件

2、开发语法

1、创建页面

  • 在pages创建文件加,然后选中右键选中新增page,就会自动生成页面的文件,并在app.json里面注册路由
  • view对于divtext对应span
  • 适配:1px = 2rpx;设计图为750
  • 注意:公共样式添加:page { heigth: 100% }

2、当前页窗口配置

app.json里window的属性之间拿到当前页面的index.json

{
  "usingComponents": {},
  "navigationBarTitleText": "Hello" // 当前页面直接设置
   // 局部优先级大于全局 
}

js动态修改

wx.setNavigationBarTitle({ title: '旭大王' })
// 文档 => api => 交互 => 导航栏
// 还有其他控制

3、数据绑定

1、创建初始化数据:

  • 在页面文件下index.js里面page对象的data里面创建数据

  • 可以通过调试器的appData查看初始化数据

  • 视图层:{{ msg }}

  • 视图层:

  • js: console.log(this.data.msg)

2、修改数据

  • js修改数据this.setDate({ msg: 'success' });同步

4、事件绑定

  • 会冒泡:
  • 不会冒泡:
  • 绑定的事件和data平级
  • Tap 相当于 click
  • touchstart:手指点击:e.touches[0].clientY
  • touchmove:手指移动
  • touchend:手指抬起

通过距离判断实现上拉自定义动画

style="transform: {{ coverTansform }}"

target:可能是当前元素,可能是父元素

currentTarget:肯定是当前元素

detail.value:表单组件返回的value

事件入参

<view
  id="dataSet"
  data-alpha-beta="1"
  data-alphaBeta="2"
  bindtap="bindViewTap"
> DataSet Test view>
Page({
  bindViewTap:function(event){
    event.currentTarget.id === dataSet
    event.currentTarget.dataset.alphaBeta === 1 // - 会转为驼峰写法
    event.currentTarget.dataset.alphabeta === 2 // 大写会转为小写
  	cosnt value = event.detail.value // 表单组件返回的value
  }
})

5、条件渲染

<view wx.if="{{ isUser }}">有用户view>
<view wx.else >无用户view>

6、列表渲染

  • 语法:wx:for

  • 默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item

    <view wx:for="{{array}}">
      {{index}}: {{item.message}}
    view>
    
    
    <view
      wx:for="{{array}}"
      wx:for-index="idx"
      wx:for-item="itemName"
    >
      {{idx}}: {{itemName.message}}
    view>
    
    
    
    <view wx:for="{{ arr }}" wx:key="name">
    	{{ item.name }}
    view>
    

7、自定义组件

  • 新建components文件夹,文件夹创建nav文件,右键选中新建component

  • 新建后出现的4个文件和页面文件一样,但是不会自动添加路由

  • 引入注册:在页面的.json文件里usingComponents配置

    {
      "usingComponents": {
          "HeadBox": "/components/HeadBox/HeadBox"
      }
    }
    

8、组件传值

组件间传值:无法传值

父传子:

<view>
	父组件
    <Child title="传入值">子组件Child>
view>
// 子组件的js里面会有properties, 接收传值
// 和vue的props类似,value 相当于 default
properties: {
    title: {
        type: String,
        value: '默认值'
    }
}
// 且properties的值会自带同步给data

子传父

  • 父创建事件传递给子
  • 子调用父事件进行传参
  • 父事件通过事件进行回调
  • 还可以通过promise的resolve触发then完成反向触发

9、父子事件

  • 父传子:

    
    <component-tag-name bindmyevent="onMyEvent" />
    
    // 父组件
    onMyEvent(e) { console.log(e.detail.name) }
    
    
    <button bindtap="onTap">点击这个按钮将触发“myevent”事件button>
    
    // 子组件
    onTap() {
        this.triggerEvent('myevent', { name: 'xu' })
    }
    
  • 子传父:

    1. 给父组件给子组件定义id
    2. 父组件通过const son = this.selectComponent("#id")获取子组件
    3. 再通过son.go()调用子组件go方法
    4. 组件列表使用时就不能使用了,需要通过其他方式实现
  • 其他方式

    • 使用第三方插件pubsub-js
    import Pubsub from 'pubsub-js'
    // 订阅
    const pubsub = Pubsub.subscribe("订阅名", (msg, data) => {
        console.log(msg) // 这里将会输出对应设置的 pubsubID
        console.log(data) // 这里将会输出对应设置的参数
    })
    // 取消订阅
    Pubsub.unsubscribe(pubsub)
    // 取消全部订阅
    PubSub.clearAllSubscriptions()
    
    import Pubsub from 'pubsub-js'
    // 发布
    Pubsub.publish("订阅名", data)
    // 或
    PubSub.publishSync("订阅名", data)
    

10、模板

  • 创建templates文件夹,和pages同级

  • 创建test文件夹,并新建页面

  • 页面里面wxml写模板,模板样式协助

    
    <template name="msgItem">
      <view class="username">
        <text>username: {{ name }} text>
      view>
    template>
    
    /* 模板样式 */
    .msgItem {
        height: 40px;
        border: 1px solid red;
    }
    .username {
        line-height: 30px;
        font-size: 16px;
    }
    
  • 页面使用模板

    <import src="/templates/test/test.wxml" />
    <view>
    	<template is="msgItem" data="{{...item}}"/>
        
    view>
    
    @import "/templates/test/test.wxss"
    /* 下面定义的样式会覆盖模板样式,注意命名 */
    

3、路由和导航组件

  • 编程式跳转

    1. wx.navigateTo()

      wx.navigateTo({
          url: '/pages/index/index', // 必须加根路径
          events: { callback: (data) => { console.log(data) } } 
          // 被打开页面给当前页面反馈
          // 其他还有success回调,fail失败回调,complete跳转回调
          success: (res) => {
          	 res.eventChannel.emit('reverse', { name: '大王' })
          }
      })
      // 会保留跳转记录
      
      // 被打开页面
      onLoad(options) {
          const eventChannel = this.getOpenerEventChannel()
          eventChannel.emit('callback', { name: '旭' });
          // 调用上个页面的回调
          eventChannel.on('reverse', (data) => { console.log(data) });
          // 本页面给上个页面的回调
      }
      
    2. wx.navigateBack:相当于history.go()

    3. wx.redirectTo():不传值,不保存记录

    4. wx.reLaunch():关闭其他,然后跳转,不传值

    5. wx.switchTab():关闭其他,跳转到tabar页面

  • 进行传值

    上面的方法以及可以实现路由上下两个组件进行传参

    通过get方式传参,传递query(缺点, 传递有限)

  • 获取传值

    获取get参数:onLoad(options) {} :options就是get传递的query

  • tabBar底部导航

  • 全局tabBar

    就是直接在app.json里面定义tabBar属性:和window,pages同级

    在文档 => 框架 => 全局配置 => tabBar里面有说明

    顶部无法使用icon,会有下边框,且2 <= list.length <= 5

    "tabBar": {
        "backgroundColor": "#f0f0f0",
        "color": '#333',
        "selectedColor": "#d43c33",
        "position": "botton/top",
        "custom": false,
        "list": [
            {
                "pagePath": "tabBar导航地址",
                "text": "tab文字",
                "iconPath": "未选中icon图片链接",
                "selectedIconPath": "选中icon图片链接"
            }
        ]
    }
    
  • 自定义tabBar (可以局部,也可以全局)

    1. 设置custom为true即可,然后配置的list就会失效
    2. pages同级别下创建custom-tab-bar文件夹并创建index组件
    3. 然后就可以在组件里面写自定义tabBar组件
    4. 注意不要使用view标签,可能会导致页面覆盖tabBar
    5. 使用cover-viewcover-image组件替代view

4、生命周期

页面生命周期

  • 初始化:onLoad() {}:只执行一次
  • 页面显示:onShow() {}
  • Dom渲染完成:onReady() {}:只执行一次
  • 页面隐藏:onHide() {};页面隐藏再次显示会触发onShow() {}
  • 页面卸载(页面销毁):onUnload() {}

组件生命周期:看自定义组件文档

5、数据store

1、数据store管理

  • app.js文件创建globalData对象存储store全局数据

  • 在局部使用const appInstance = getApp()获取

    const appInstance = getApp();
    Page({
        onLoad() {
            console.log(appInstance.globalData.name)
            appInstance.globalData.name = "hello"
        }
    })
    

2、数据本地存储

js本地存储差不多:

同步:wx.setStorageSync,多个异步方法wx.setStorage

同步:wx.getStorageSync,多个异步方法wx.getStorage

还有remove, clear

6、授权

  1. 首次登录触发授权

    <button bindgetuserinfo="handleGetInfo" open-type="getUserInfo">获取授权button>
    
    
  2. 授权后就可以使用wx.getuserInfo();重复获取信息

    wx.getUserInfo({
        success: () => {}, // 成功回调
        fail() {} // 失败回调,错误不会给用户看到
        complete() {} // 执行回调无论成败
    })
    // 用于授权后组件内onLoad周期内使用
    

7、组件

1、基础组件

小程序内置组件有轮播图,按钮等等原生组件

  • swapperprevious-margin调整前偏距
  • swappernext-margin调整后偏距

2、icon使用

  • 使用案例icon,建立项目,和使用class名
  • 在static里创建iconfont文件夹=>index.wxss
  • 将icon提供的链接打开的代码复制到刚刚的index.wxss文件
  • app.wxss里面引入@import "/static/iconfont/index.wxss"
  • 使用:

3、可滚动视图

微信内置组件scroll-view

实现上下滚动,左右滚动,下拉刷新等等页面滚动功能

8、请求

  1. 接口请求使用wx.request()进行

  2. 初始化请求会放在onLoadonReady里面

  3. url地址必须是完整的,且在小程序管理页面(就是注册成功后页面),开发 => 开发设置 => 服务器域名设置 => 添加服务器域名

  4. 最多添加20个域名,并发不能超过10个

  5. 必须是https协议,不是的话可以先在开发工具详情里面设置不校验

    也不需要去小程序管理页面添加域名,可以本地调试了

  6. 文件上传wx.UploadTask()

  7. 文件下载wx.downloadFile()

  8. cookie携带:

    • 通过登录时获取,存储到本地数据或者store
    • 登录页面调整其他页面需要关闭其他页面调整,用于触发其他页面onLoad
    • 其他页面onLoad获取cookie,发送请求,将cookie放在head属性里面
    • wx.request文档里head和url同级
  9. 封装

    // utils/request.js
    
    

9、内网穿透

  • 解决真机调试的时候接口没有服务的问题
  • 下载uTools软件进行操作 => 插件中心 => 内网穿透
  • 然后配置就可以实现真机调试了,但不能预览调试

10、npm使用

  • 项目文件打开cmd运行npm init
  • 开发者工具详情 => 项目配置 => 使用npm
  • 开发者工具 工具=> 构建npm
  • 然后就可以使用npm第三方插件了

11、获取登录凭证

  • 使用wx.login({ success(res) { console.log(res.code) } })
  • 然后将code发送给后端
  • 后端通过code生成验证token, 然后拥有了登录验证的功能

12、小程序分包

  • 将大于2M小于16M的包进行拆分

1、常规分包

  • app.json里面配置subpackages;这是一个数组

    "subpackages": [
        {
          "root": "packageA",
          "pages": [
            "pages/cat",
            "pages/dog"
          ]
        }, {
          "root": "packageB",
          "name": "pack2",
          "pages": [
            "pages/apple",
            "pages/banana"
          ]
        }
    ]
    
  • root:包的根路径名称

  • name:包的别名

  • pages:包的路由配置

  • 然后和主包pages同级创建包根路径名称文件夹做分包,如:packageA

  • 然后pageageA里面也创建pages文件夹,和主包一样结构

  • 分包可以使用主包资源,路径修改下就可以了

  • 主包跳转分包是路由根路径为分包名

2、独立分包

  • 就是在需要独立分包的配置加"independent": true

    {
      "root": "packageB",
      "name": "pack2",
      "pages": [
        "pages/apple",
        "pages/banana"
      ],
      "independent": true
    }
    
  • 独立分的包无法使用主包资源,路由跳转和常规分包一样

3、分包预加载

  • app.json里的preloadRule里面进行配置

    "preloadRule": {
        "pages/index": {
          "network": "all",
          "packages": ["packageA"]
        },
        "sub1/index": {
          "packages": ["packageA", "packageB"]
        },
        "sub3/index": {
          "packages": ["packageB"]
        },
        "indep/index": {
          "packages": ["__APP__"]
        }
      }
    
  • "pages/index":打开路由路径或打开包index路径

  • network:指定网络模式,wifi还是其他

  • packages:分包的rootname名称,其中主包叫__APP__

13、自定义组件详解

1、组件插槽

  • 子组件模板

    <view class='child'>
    	<view>这是子组件view>
        <slot>slot>
    view>
    
  • 父组件

    <view class='father'>
      <component-tag-name>
        
        <view>这里是插入到组件slot中的内容view>
      component-tag-name>
    view>
    
  • 页面使用

    <view>
    	<Father><Child />Father>
    view>
    
  • 多个slot和具名

    
    <view class='child'>
    	<view>这是子组件view>
        <slot name='slotA'>slot>
        <slot name='slotB'>slot>
    view>
    
    
    <view class'father'>
          
    	<component-tag-name
            prop-a="{{dataFieldA}}"
            prop-b="{{dataFieldB}}"
        >
        	<view slot="slotA">"slotA"中的内容view>
        	<view slot="slotB">"slotB"中的内容view>
        component-tag-name>
    view>
    

2、数据

组件data里定义的数据

  • _前缀:纯数据字段,不会被渲染,不会传递给其他组件
  • 不加前缀:正常字段

3、数据监听

observers === watch

observers: {
    // 监听obj所有值变化
    'obj.**': function (obj) { console.log(obj) }
}

4、生命周期

  • created === created
  • attached=== mounted
  • detached === destroyed

5、组件父子传值


<view class'father'>
      
	<component-tag-name
        prop-a="{{dataFieldA}}"
        prop-b="{{dataFieldB}}"
    >component-tag-name>
view>

6、组件父子事件

<view class="father">
    <component-tag-name bindmyevent="onMyEvent" />
view>
// 父组件
onMyEvent(e) { console.log(e.detail.name) }
// 子组件
handleBtn() {
    this.triggerEvent('myevent', { name: 'xu' })
}

三、开发经验

1、input获取值

<view>
	<input type="text" id="text" bindinput="handleInput"/>
	<input type="password" id="password" bindinput="handleInput"/>
view>
handleInput(e) {
    const type = e.currentTarget.id
    this.setData({
        [type]: e.detail.value
    })
}

2、消息提示

  • 微信原生提示:wx.showToast({ title: '成功' })
  • 还有替他提示:文档 => api => 界面 => 交互

3、video多个播放

  • video多个播放不符合逻辑

  • 我们需要video播放下一个停止当前上一个video

  • wx.createVideoContext:创造一个VideoContext对象来操作video

  • 使用案例

    <view wx:for="{{array}}" wx:key="src">
        <video
           bindplay="handlePlay"
           src="{{item.src}}"
           id="{{item.data.id}}"
        />
    view>
    
    handlePlay(e) {
        const vid = e.currentTaget.id;
        // 判断是否时同一个视频 && 判断上一个video控件是否存在
        if (this.vid !== vid && this.VideoContent) {
            this.VideoContent.stop(); //停止视频播放
        }
        this.vid = vid
        this.VideoContext = wx.createVideoContext(vid);
    }
    

4、image代替video

  • 和原生一样使用video的poster属性添加img链接
  • 创建一个image和video同级
  • 通过wx:if="{{vid === item.data.vid}}"判断video是否隐藏,实现优化
  • 此时也解决了多个视频同时播放的问题

5、视频面积大小

使用video的object-fit的属性设置

6、下拉刷新

  • scroll-view
  1. scroll-view的refresher-enabled开启下拉刷新
  2. scroll-viewbindrefresherrefresh监视下拉是否触发
  3. scroll-view的下拉可控状态:refresher-triggered
  • 页面也有下拉刷新
  1. 页面有onPullDownRefresh生命周期函数,监视下拉触发
  2. 下拉需要全局或局部设置enablePullDownRefresh为true
  3. 全局在page.json的window里面设置
  4. 局部就在json里面设置
  5. 页面下拉不需要可控状态还原

7、上拉加载

  • scroll-view的上拉加载:bindscrolltolower属性触发
  • 页面的上拉加载: onReachBottom生命周期函数进行监视触发

8、分享好友

  • button设置open-type为share就可以触发分享好友功能

  • 用户点击页面上方头部分享按钮

    头部分享菜单是创建onShareAppMessage生命周期函数才会有

    点击菜单后触发onShareAppMessage

    通过form判断是按钮触发的分享,还是头部菜单触发分享

  • 自定义分享内容

    onShareAppMessage可以返回一个对象,用来自定义分享

    title: 标题 path: 分享页面路径 imageUrl:分享图片

9、音乐播放

音乐播放使用背景音频功能:文档 => api => 媒体 => 背景音频

效果,关闭后还能继续播放

关键:BackgroundAudioManager

音频关键:在onLoad() {}里面添加 播放监听,暂停监听,停止监听

播放,暂停,停止,音乐播放自然停止都是BackgroundAudioManager的方法

还有进入更新监听事件,获取播放进度

播放进度/总时长 * 进度条宽长度 = 当前进度条宽长度

10、动画使用

  • 通过wx.createAnimation创建一个动画对象,通常在onload初始化时创建

  • 将创建的对象添加到this上面,方便下面绑定动画时使用

    onload() {
        this.animation = wx.createAnimation({ duration: 2000 })
        // createAnimation是可以进行传参配置的
    }
    
  • 创建动画dom

    <view animation="{{ animationData }}">view>
    
  • 创建动画值

    data: {
        animationData: {}
    }
    
  • 将动画对象赋值给动画值,触发dom的动画效果

    handleBtn() {
        // 先定义需要的动画效果,如旋转45度
        this.animation.rotate(45)
        this.setData({
            // export调用动画
            animationData: this.animation.export()
        })
        // 此时已经实现了动画调用
    }
    
  • 多动画同时调用

    handleBtn() {
        this.animation.rotate(45).scale(2,2)
        this.setData({
            animationData: this.animation.export()
        })
    }
    
  • 多动画依次调用

    handleBtn() {
        // 使用step实现动画依次加载
        // step停止上一次动画动作
        this.animation.rotate(45).step().scale(2,2).step()
        this.setData({
            animationData: this.animation.export()
        })
    }
    
  • 动画还原:就是将动画效果还原成初始状态

你可能感兴趣的:(前端学习,小程序)