even

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

1、小程序核心技术

  • 页面布局: WXML (类似html);
  • 页面样式: WXSS(就是css, 对原生css进行了一些增强,有些则不支持);
  • 页面脚本:  javascript + WXS(weixinScript)

2、小程序注册账号

入口: 微信公众平台

appid:  开发管理 / 开发设置 

小程序开发工具: 文档 / 工具  

 3、vscode开发小程序的插件

 4、小程序目录结构介绍

pages  // 存放页面
utils  // 基础方法存放
app.json  // 小程序的关键文件,配置页面信息,以及窗口的基础配置

 5、小程序的入门体验

Page({
  data: {
    content: 'this is test',
    list: ['first', 'second', 'third']
  },
  // 页面的方法可以直接写在page的json中,如果是组件,那么需要写在methods中
  testEvent() {
    console.log('test')
  },
  checkEvent(event: any) {
    console.log('ok', event)
  }
})

相对应的wxml

<!--index.wxml-->
<text>{{content}}</text>

<view>
  <text>abc</text>
  <button size="mini" type='primary' bind:tap="testEvent">button</button>
</view>

<view>
  <!-- block相当于vue中的template的功能 -->
  <block wx:for="{{list}}" wx:for-item="per" wx:key="*this">
    <!-- 阻止冒泡事件 -->
    <text catch:tap="checkEvent">{{per}}{{index}}</text>
  </block>
</view>

<view hidden>this is view</view>

 微信小程序数据改变导致的界面刷新需要依赖setData文件进行视图层的刷新 , 这个特性需要与vue的数据截持区分开

Page({
  data: {
    content: 'this is test',
  },
  changeEvent() {
    // 这个方法不仅可以改变data中的数据,也可以实现视图层的刷新

    this.setData({
      content: "what are you doing???"
    })

    console.log(this.data.content)
  }
})

6、小程序配置文件

注意:通常来讲,小程序的展示顺序是按照app.json中的page中配置页的页面进行编译,但是为了方便开发,也可以在顶部栏的添加编译模式

7、小程序下拉刷新配置

在app.json中有一个配置

// app.json中的配置  
"window": {
    "backgroundTextStyle": "dark",   // 定义下拉刷新的样式, 目前有light, dark两种
    "enablePullDownRefresh": false   // 是否开启全局下拉刷新,通常不开启全局的下拉刷新,只在页面中开启,即在page.json中配置
  },

// page页面中的配置
{
  "usingComponents": {},
  "enablePullDownRefresh": true
}
Page({
  onPullDownRefresh() {
    console.log('用户下拉刷新')

    // 停止刷新,默认是刷新3秒
    wx.stopPullDownRefresh({
      success(res) {
        console.log('success', res)
      },
      fail() {
        console.log('fail')
      },
      complete(res) {
        console.log('complete', res)
      }
    })
  }
})

 8、小程序触底刷新配置

{
  "usingComponents": {},
  "onReachBottomDistance": 100  // 表示在距离底部100时触发触底事件
}

// 上面配置配合page内部的函数进行使用

Page({
  // 触底时会触发这个事件
  onReachBottom() {
    console.log('reach Bottom')
  }
})

 9、App的生命周期函数

每个小程序只能实例化一个App实例,并且是全局共享(可以利用这个特性做一些简单的全局数据共享),这个App实例也是指定的生命周期函数  具体参看文档地址: https://developers.weixin.qq.com/miniprogram/dev/reference/api/App.html

在Page中如果需要获取App实例,可以使用 getApp()这个方法进行获取

获取小程序的进入场景(获取相应的场景值)

// app.ts
App<IAppOption>({
  globalData: {},
  onLaunch(options: any) {
    console.log(options.scene)  // 获取小程序是通过何种方式进入的, 也可以使用 wx.getLaunchOptionSync()进行获取
  },

  onShow(options: any) {
    console.log(options.scene) // onShow时也会获取相当的参数
  }
})

注意:相关的code可以对照  https://developers.weixin.qq.com/miniprogram/dev/reference/scene-list.html

为了方便模拟进入的code可以点击下图按钮进行模拟,不过onLaunch只会触发一次

10、微信小程序头像获取方法

微信小程序的头像获取方式已做调整,新的获取方法见链接 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/userProfile.html 

11、微信小程序从应用中获取图片和视频的方法如下

wxml

<view>
  <button bind:tap="tapEvent">选择图片</button>
  <image src="{{imageSrc}}" mode="aspectFit" />
</view>

js

Page({
  data: {
    imageSrc: 'https://up.deskcity.org/pic_source/2f/f4/42/2ff442798331f6cc6005098766304e39.jpg',
  },
  tapEvent() {
    wx.chooseMedia({
      mediaType: ['image']
    }).then(res => {
      console.log(res)
    })
  }
})

 12、微信小程序的双向绑定

wxml

<!-- <input type="text" value="{{message}}" bind:input="inputEvent"/> -->  // 方法一

<input type="text" model:value="{{message}}" bind:input="emptyEvent" />  // 方法二

<button bind:tap="tapEvent">点击</button>

js

{
   ...
  tapEvent() {
    console.log(this.data.message)
  },
  inputEvent(e: any) {
    console.log(e)
  },
  emptyEvent(e: any) {
    
  }

}

注意:以前常用的双向绑定是以第一种方式进行,但是第二种方式实现会报警告,为了解决不必要的警告,可以绑定一个空的input事件

13、 wxss样式编写

小程序的样式分成三种,行内样式,页面样式(页面的wxss),全局样式(app.wxss)

wxss的扩展:尺寸单位(rpx: 可以根据屏幕宽度进行自适应, 规定屏幕宽为750rpx)

如在 iphone6上,屏幕宽度为 375px, 共有750个物理像素, 则 750rpx = 375px = 750物理像素, 1rpx = 0.5px = 1物理像素

建议:开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准

14、wxml的相关语法

判断语法: wx:if ...wx:elif...wx:else

实现元素的显示隐藏可以使用  hidden 属性 

<text hidden="{{sign % 3 == 0}}">haha{{sign}}</text>

列表循环

<view>
  <block wx:for="{{list}}" wx:key="id" wx:for-item="abc" wx:for-index="kk">
      <view>{{abc.name}}=={{abc.id}}--{{kk}}</view>
  </block>
  <!-- 这里也可以遍历数字或字符串 -->
  <block wx:for="{{10}}" wx:key="*this">
      <text>{{item}}</text>
  </block>
</view>

注意:默认访问每一项用item, 访问索引用 index,如果需要改需要用到 wx:for-item, wx:for-index来改变

 15、wxs的使用

WXS与javascript 是小程序的一套脚本语言, 结合WXML, 可以构建出页面的结构

限制和特点:

  • wxs不依赖于运行时的基础库版本,可以在所有的版本的小程序中运行
  • wxs的运行环境和其他 javascript 代码是隔离的,wxs中不能调用其他的 javascript 文件中定义的函数, 也不能调用小程序提供的 api
  • 由于运行环境的差异, 在 IOS 设备上 wxs 会比 javascript 代码快 2-20倍,在 android 设置上二者运行效率差不多

wxs的写法一:

<!-- 注意:这里只能用es5的语法,不能用es6以上的语法 -->
<wxs module="format">
  function parsePrice(price) {
    return "¥" + price
  }

  // 这里必需用common.js的语法进行导出
  module.exports = {
    parsePrice: parsePrice
  }
</wxs>


<view>
  <block wx:for="{{list}}" wx:key="id">
    <view><text>{{item.id}}</text><text>{{item.name}}</text><text>{{format.parsePrice(item.price)}}</text></view>
  </block>
</view>

 wxs的写法二:

定义一个wxs文件,内容如下

function parsePrice(price) {
  return "¥" + price
}

module.exports = {
  parsePrice: parsePrice
}

在wxml文件中内容如下

<!-- 注意:这里只能用es5的语法,不能用es6以上的语法 -->
<wxs module="format" src="/utils/format.wxs"></wxs>


<view>
  <block wx:for="{{list}}" wx:key="id">
    <view><text>{{item.id}}</text><text>{{item.name}}</text><text>{{format.parsePrice(item.price)}}</text></view>
  </block>
</view>

 注意:如果需要计算总价格,那么则需要把列表数据传到wxs函数中

16、事件参数的传递

在小程序中,事件参数的传递主要有两种方式:方式一,通过 data- 的方式进行传递,接收使用 event.currentTarget.dataset 进行接收; 方式二, 通过 mark: 的方式进行传递,接收使用 event.mark 进行接收

wxml

<view>
  <block wx:for="{{list}}" wx:key="id">
    <view>
      <text>{{item.id}}</text>
      <text>{{item.name}}</text>
      <text>{{item.price}}</text>
      <!-- 这里分别使用了两种方式进行传递 -->
      <button data-info="{{item}}" mark:it="{{item}}" size="mini" type="primary" plain bind:tap="tapEvent">购买</button>
    </view>
  </block>
</view>

js

Page({
  data: {
    list: [
      { id: 1, name: 'javacript', price: 20 },
      { id: 2, name: 'php', price: 25 },
      { id: 3, name: 'java', price: 30 },
      { id: 4, name: 'python', price: 18 }
    ]
  },
  tapEvent(event: any) {
    // 接收方式一
    const info = event.currentTarget.dataset
    // 接收方式二
    const info2 = event.mark

    console.log(info, info2)
  }
})

 注意:使用currentTarget, 尽量不要使用target

17、小程序的组件化

小程序中创建组件,这个时候在组件对应的json文件中 component属性为 true, 表示这是一个组件,并且对应的js或ts文件是component对象如下示例

// components/book-item.ts
Component({

  /**
   * 组件的属性列表
   */
  properties: {

  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {

  }
})

需要注意一些细节:

  • 自定义组件也可以引用自定义组件,引用方法类似页面引用自定义组件的方式,(使用 usingComponents字段)
  • 自定义组件和页面所在项目根目录名 不能以 "WX-" 为前缀, 否则会报错
  • 如果 在app.json的usingComponents 声明某个组件,那么所有的页面和组件可以直接使用该组件

组件的样式细节

  • 组件内的class样式, 只对组件wxml内的节点生效,对于引用组件的Page页面不生效
  • 组件内不能使用id选择器,属性选择器,标签选择器(因为这个会导致该样式作用于组件范围以外的元素)

通常来讲,组件与页面的样式是有隔离的,但是可以配置选项让其互相影响: 在 Components对象中,可以传入一个 options属性,其中 options 属性有一个 styleIsolation (隔离) 属性

styleIsolation有三个取值

  1. isolated 表示启动样式隔离,在自定义组件内外,使用class 指定的样式将不会相互影响(默认取值)
  2. apply-shared 表示页面的 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面
  3. shared 表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置

 组件的通信

页面传递数据, 样式,标签给组件分别通过 properties, externalClasses, slot进行传递

组件传递数据页面 是通过自定义事件进行传递

page wxml

<view>
  <block wx:for="{{list}}" wx:key="id">
    <Book-Item info="{{item}}" bind:buyEvent="itemBuyEvent"></Book-Item>
  </block>
</view>

page ts

Page({
  data: {
    list: [
      { id: 1, name: 'javacript', price: 20 },
      { id: 2, name: 'php', price: 25 },
      { id: 3, name: 'java', price: 30 },
      { id: 4, name: 'python', price: 18 }
    ]
  },
  itemBuyEvent(item: any) {
    console.log(item.detail)
  }
})

组件 wxml

<view>
  <text>{{info.id}}</text>
  <text>{{info.name}}</text>
  <text>{{info.price}}</text>
  <button type="primary" size="mini" bind:tap="buyEvent">购买</button>
</view>

组件 ts 

Component({

  properties: {
    info: {
      type: Object,
      value: { id: 0, name: '', price: 0 }
    }
  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {
    buyEvent() {
      this.triggerEvent('buyEvent', this.data.info)
    }
  }
})

注意: triggerEvent相当于vue中的emit,   小程序中组件向父组件传递数据的方式是一样的, properties支持的类型有: String, Number, Boolean, Object, Array,null(不限制类型) 默认值通过value进行配置

externalClasses的用法

组件ts

// components/book-item.ts
Component({
...

  // 需要在组件中配置这个字段, item表示外部传入的类名
  externalClasses: ['item'],
...
})

组件的 wxml

<!-- 这里可以直接使用item这个类名 -->
<view class="item">
  <text>{{info.id}}</text>
  <text>{{info.name}}</text>
  <text>{{info.price}}</text>
  <button type="primary" size="mini" bind:tap="buyEvent">购买</button>
</view>

页面调用组件

<view>
  <block wx:for="{{list}}" wx:key="id">
    <Book-Item info="{{item}}" item="{{index<2? 'bookItem': ''}}" bind:buyEvent="itemBuyEvent"></Book-Item>
  </block>
</view>

页面scss文件

.bookItem {
  color: red;
  background: yellow;
  font-size: 36rpx;
}

小程序中获取元素以及组件的做法

<view>
  <view class="title">这个是一个标题</view>
  <block wx:for="{{list}}" wx:key="id">
    <Book-Item class="book" info="{{item}}" item="{{index<2? 'bookItem': ''}}" bind:buyEvent="itemBuyEvent"></Book-Item>
  </block>
  <button type="primary" bind:tap="getElementEvent">获取元素</button>
</view>

js文件

  getElementEvent() {
    // 获取元素的方法
    const handle = wx.createSelectorQuery();
    const title = handle.select('.title')

    // 获取单个组件的方法
    const book = this.selectComponent('.book')

    // 获取多个组件的做法
    const bookss = this.selectAllComponents('.book')

    // 也可以通过事件的currentTarget或者target来获取
  }

 小程序中slot的使用

 页面wxml(多插槽的情况)

<view>
  <block wx:for="{{list}}" wx:key="id">
    <Book-Item info="{{item}}" bind:buyEvent="itemBuyEvent">
      <view slot="content"><text>{{item.id}}--{{item.name}}--{{item.price}}</text></view>
      <button slot="action" type="warn">点击</button>
    </Book-Item>
  </block>
</view>

页面ts

Page({
  data: {
    list: [
      { id: 1, name: 'javacript', price: 20 },
      { id: 2, name: 'php', price: 25 },
      { id: 3, name: 'java', price: 30 },
      { id: 4, name: 'python', price: 18 }
    ]
  }
})

组件wxml

<view>
  <view class="content">
    <slot name="content"></slot>
  </view>
  <view class="content-default">
    <text>{{info.id}}</text>
    <text>{{info.name}}</text>
    <text>{{info.price}}</text>
  </view>

  <view class="action">
    <slot name='action'>
    </slot>
  </view>
  <view class="action-default">
    <button type="primary" size="mini" bind:tap="buyEvent">购买</button>
  </view>
</view>

注意:content-default与action-default是默认内容,如果没有内容的情况下,展示default中的内容,这个需要配合css的样式实现,如下代码

组件scss

.content-default,
.action-default {
  display: none;
}

.content:empty+.content-default,
.action:empty+.action-default {
  display: block
}

组件ts

// components/book-item.ts
Component({

  properties: {
    info: {
      type: Object,
      value: { id: 0, name: '', price: 0 }
    }
  },

  options: {
    styleIsolation: "isolated",  // 样式隔离
    multipleSlots: true  // 实现多插槽
  },

  externalClasses: ['item'],

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {
    buyEvent() {
      this.triggerEvent('buyEvent', this.data.info)
    }
  }
})

 小程序中的mixins --- behaviors

  • 每个behaviors可以包含一组属性,数据,生命周期函数和方法

  • 组件引用它时,它的属性,数据和方法会被合并到组件中; 生命周期函数也会在对应的时机被调用

  • 每个组件可以引用多个behavior, behavior可以引用其他的behavior

 定义count-behavios.ts文件

export const CountBehavior = Behavior({
  data: {
    count: 0
  },
  methods: {
    increment() {
      this.setData({
        count: this.data.count + 1
      })
    },
    decrement() {
      this.setData({
        count: this.data.count - 1
      })
    }
  }
})

 组件wxml

<view class="item">
  <text>{{count}}</text>
  <view>
    <button type="primary" bind:tap="increment">+ 1</button>
    <button type="warn" bind:tap="decrement">- 1</button>
  </view>
</view>

组件ts

import { CountBehavior } from "../behaviors/count-behavior";

// components/book-item.ts
Component({
  behaviors: [CountBehavior]
})

小程序组件中的生命周期函数

具体可见文档  组件生命周期函数

小程序的数据监听器

具体可见文档 数据监听器

 18、小程序常见API

 a、网络请求

注意:每个微信小程序需要事先设置通讯域名,小程序只可以跟指定的域名进行网络通信,设置地址:小程序登录后台 -- 开发管理 -- 开发设置 -- 服务器域名(域名需要进行备案)

开发阶段,为了防止不能请求,可以配置 详情 -- 本地设置 -- 不较验合法域名

wx.request()

 对wx.request进行简单的封装

// request.ts
type RequestOptions<T> = {
  url: string,
  method?: 'GET' | 'POST', // 可以根据需要添加更多的HTTP方法
  data?: T,
  header?: Record<string, string>
}

export class Request {
  baseUrl: string;

  constructor(baseUrl: string) {
    this.baseUrl = baseUrl;
  }

  private request<T, U = any>(options: RequestOptions<T>): Promise<U> {
    return new Promise((resolve, reject) => {
      wx.request({
        url: this.baseUrl + options.url,
        method: options.method || 'GET',
        data: options.data,
        header: options.header || {
          'content-type': 'application/json'
        },
        success: (res) => {
          if (res.statusCode === 200) {
            resolve(res.data as U);
          } else {
            reject(res.errMsg);
          }
        },
        fail: (err) => {
          reject(err);
        }
      });
    });
  }

  get<U>(url: string, params?: Record<string, any>): Promise<U> {
    return this.request<undefined, U>({ url, method: 'GET', data: params });
  }

  post<T, U>(url: string, data: T): Promise<U> {
    return this.request<T, U>({ url, method: 'POST', data });
  }

  // 可以根据需要添加其他方法
}

 b、微信弹框(具体见链接

 c、微信分享

 在进行微信分享的时候,会默认调用Page中的一个方法,如下

Page {
    // 分享功能
    onShareAppMessage () {
        return {
              title: '分享的标题',
              path: 'pages/test/share'  // 分享后点击进入的路由
              imageUrl: '分享封面的图片,如果没有配置,则为缩略图'
        }
    }
}

 d、获取设备信息以及地理位置

在开发过程中,我们需要获取当前设备的信息,用于收集信息或者进行一些适配工作

小程序提供了相关的api: wx.getSystemInfo(object object)

 wx.getSystemInfo({
   success(result) {
     console.log(result)
   }
 })

如果需要获取地理位置的信息,那么就需要进行权限申请以及配置,具体的文档: 地理位置 

在获取上以的地理位置权限后,需要添加以下的权限:权限

{
  "pages": ["pages/index/index"],
  "permission": {
    "scope.userLocation": {
      "desc": "你的位置信息将用于小程序位置接口的效果展示" // 高速公路行驶持续后台定位
    }
  }
}

 e、小程序页面跳转的方式

界面的跳转有两种方式:通过navigator组件 和 通过 wx 的api跳转

这里先以 wx 的 api 作为讲解

 

posted on 2023-06-20 00:17  even_blogs  阅读(83)  评论(0编辑  收藏  举报