本文简单介绍下小程序的开发流程及自定义组件、自定义头部标题栏使用

开发流程

1、小程序开发需要用到开发者ID,所以还没有注册小程序的需要先去注册 小程序注册页。注册好后进入小程序管理系统,点击菜单:"开发--开发设置" 获取AppID。

2、得到开发者ID后下载小程序开发专用工具 小程序开发工具。附:微信官方文档

3、一个小程序页面由 .json, .js, .wxml, .wxss 四个文件构成。文件与文件之间无需引用,只要四个文件名相同,框架会自动找到页面对应的所有文件。

  • .wxml文件:等同于html,主要书写页面结构。对应的页面标签请查看官方文档。
  • .wxss文件:等同于css。扩展了rpx尺寸单位和@import样式导入。
    rpx可根据屏幕宽度进行自适应,小程序标准尺寸为750px,即如果设计图是750px我们在做程序时只需把所有的像素尺寸写为rpx即可
  • .js文件:页面的逻辑代码。
  • .json文件:页面的配置文件。

微信小程序 + mock.js模拟请求数据

官方的mockjs没法直接用到小程序中,不过有个基于mockjs开发的WxMock模拟数据工具
Github地址https://github.com/webx32/WxMock

使用方法

1. 在小程序工程根目录下新建mock目录,copy文件https://raw.githubusercontent.com/webx32/WxMock/1.0.1-beta3/dist/mock.js(dist/mock.js此文件小程序不支持) dist/WxMock.js 到该目录下

2. 在mock目录继续新建index.js。引入 WxMock 代码,书写需要模拟的接口及返回结构

/** /mock/index.js **/

const Mock = require('./WxMock.js');

const productList = () => {
  let data = [];
  for (let i = 0; i < 6; i++) {
    data.push({
      img: '/static/img/p' + (i + 1) + '.jpg',
      name: '标题' + (i + 1)
    })
  };
  return {
    status: true,
    data: data
  }
};
Mock.mock('http://www.xxx.com/api/getProductList', productList); 

3. 在app.js中引入配置好的js文件

/** app.js **/

require('/mock/index.js'); 

4. 只要在 wx.request 中使用url为 mock对应的地址 就会返回响应mock数据

wx.request({
  url: 'http://www.xxx.com/api/getBannerList',
  header: {
    'content-type': 'application/json'
  },
  success(res) {
    console.log(res)
  }
}) 

小程序使用字体文件

PS:小程序中禁止加载本地字体文件资源,只允许加载网络字体文件资源。如果要使用字体文件需要用到下面两种方法

方法一:把字体文件转为base64数据写到wxss文件中

这里推荐一个转换字体文件的网站 transfonter ,具体转换步骤如下:

把得到的base64数据复制到项目的字体图标样式文件中即可

方法二:在样式文件中字体文件资源直接写为网络资源地址

/** iconfont.wxss **/

@font-face {
  font-family: 'iconfont';  /* project id 1288189 */
  src: url('//at.alicdn.com/t/font_1288189_fej8p459kvb.eot');
  src: url('//at.alicdn.com/t/font_1288189_fej8p459kvb.eot?#iefix') format('embedded-opentype'),
  url('//at.alicdn.com/t/font_1288189_fej8p459kvb.woff2') format('woff2'),
  url('//at.alicdn.com/t/font_1288189_fej8p459kvb.woff') format('woff'),
  url('//at.alicdn.com/t/font_1288189_fej8p459kvb.ttf') format('truetype'),
  url('//at.alicdn.com/t/font_1288189_fej8p459kvb.svg#iconfont') format('svg');
}

PS: 使用此方法需要注意在IOS系统中只被允许https协议,所以我们在写资源地址时最好以 '双斜杠' 开头,不要加协议头

自定义组件

1. json文件中进行自定义组件申明

{
  "component": true
}

2. WXML文件结构

<view>
  <text>{{innerText}}</text>
  <button wx:if="{{showBtn}}" catchtap="_testEvent">测试按钮</button>
</view>

3. js文件书写

Component({
  options: {
    // 在组件定义时的选项中启用多slot支持
    multipleSlots: true
  },
  properties: {
    // 这里定义使用组件时可指定的参数
    innerText: {
      type: String,
      value: 'default value',
    },
    showBtn: {
      type: Boolean,
      value: true,
    }
  },
  data: {
    // 这里是一些组件内部数据
    someData: {},
    number: 0
  },
  methods: {
    /**
     * 组件对外开放的公用方法
     */
    testFun: function(){},

    /**
     * 组件内部使用的私有方法,以下划线开头
     * triggerEvent 用于向父级传递事件
     */
    _testEvent: function(){
      // this.triggerEvent里指定的名字即为使用组件时可绑定的事件名(本处可绑定的事件名为: testEvent)
      this.triggerEvent('testEvent');
    }
  }
})

4. 在需要使用到组件的json文件中引入组件文件,并定义组件名

"usingComponents": {
  "testComponent": "/component/test/test" // 定义组件名,引入组件文件地址
} 

5. WXML文件中使用组件

// getDataFun为页面自有的方法
<testComponent
  id="testElement"
  innerText="文本内容"
  showBtn="{{true}}"
  bind:testEvent="getDataFun">
</testComponent> 

6. 页面js中调用组件方法

onReady: function () {
  this.testEle = this.selectComponent("#testElement");
},
onLoad: function () {
  this.testEle.testFun();
},
getDataFun: function () {}, 

两个自定义组件进行关联并通信

有时需要实现这样的组件:

// pages/index/index.wxml
<my-dropdown-menu>
  <my-dropdown-item placeholder="菜单列表1"></my-dropdown-item>
  <my-dropdown-item placeholder="菜单列表2"></my-dropdown-item>
  <my-dropdown-item placeholder="菜单列表3"></my-dropdown-item>
</my-dropdown-menu>

这时我们需要在父组件里定义关联子组件,并且还需要在子组件里定义关联父组件。。父组件中可通过this.getRelationNodes(子组件相对路径)获取所有子组件对象,子组件通过this.triggerEvent(事件名, {传递出去的参数对象}, { bubbles: true, composed: true })触发关联父组件绑定的方法

// components/dropdownMenu/index.wxml
<view bindopen="_openFun">
    <slot></slot>
</view>

// components/dropdownMenu/index.js
relations: {
    '../dropdownItem/index': {
        type: 'child'
    }
},
methods: {
    _openFun(e) {
        let activeNodeId = e.detail.self.__wxExparserNodeId__
        let nodes = this.getRelationNodes('../dropdownItem/index')
        for (let i = 0; i < nodes.length; i++) {
            let node = nodes[i]
            if(node.__wxExparserNodeId__ != activeNodeId) node.setData({open: false})
        }
    }
}
// components/dropdownItem/index.js
data: {
    open: false
},
relations: {
    '../dropdownMenu/index': {
        type: 'parent'
    }
},
methods: {
    _showMenuList(e) {
        this.setData({
            open: true
        })
        this.triggerEvent('open', {self: this}, { bubbles: true, composed: true })
    },
}

下载组件代码 。实际效果图:

自定义navigationBar标题栏

组件封装

WXML文件

<view class="topnav {{fixed ? 'fixed' : ''}}" style="height:{{totalNavHeight}}px; padding-top:{{statusBarHeight}}px;background-color: {{backgroundColor}}">
  <view class='content-container'>
    <view wx:if="{{showBack}}" class='back-box'>
      <view class='ico-back' bindtap='goback'></view>
    </view>
    <view class="content {{fullWidth ? 'full' : ''}}">
      <slot></slot>
    </view>
  </view>
</view>
<view wx:if='{{fixed}}' style='height:{{totalNavHeight}}px'></view>

WXSS文件

.topnav {
  box-sizing: border-box;
}
.topnav.fixed {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9;
  width: 100%;
  background: #fff;
}
.topnav .content-container {
  display: flex;
  position: relative;
  height: 100%;
  justify-content: center;
  align-items: center;
}
.topnav .back-box {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 9;
  width: 80rpx;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
.ico-back{
  padding-bottom: 10rpx;
  color: #000;
  font-family: "iconfont";
  font-weight: 700;
  font-size: 40rpx;
  line-height: 1;
  text-align: center;
}
.ico-back:before {
  content: 'e716';
}
.topnav .content-container .content {
  width: 100%;
  padding: 0 103px 10rpx 80rpx;
}
.topnav .content-container .content.full {
  padding-left: 0;
  padding-right: 0;
}

JSON文件

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

JS文件

Component({
  data: {
    statusBarHeight: wx.getSystemInfoSync()['statusBarHeight'],
    totalNavHeight: (wx.getSystemInfoSync()['model'].indexOf('iPhone X') !== -1) ? 88 : ((wx.getSystemInfoSync()['model'].indexOf('iPhone') !== -1) ? 64 : 68) // 安卓68px,iPhoneX 88px,其它iPhone 64px
  },
  properties: {
    backgroundColor: {
      type: String,
      value: ' ',
    },
    showBack: {
      type: Boolean,
      value: true
    },
    fullWidth: {
      type: Boolean,
      value: true
    },
    fixed: {
      type: Boolean,
      value: false
    }
  },
  methods: {
    // 返回上一页
    goback: function () {
      wx.navigateBack({
        delta: 1,
      })
    }
  }
})

开启自定义navigationBar

自定义navigationBar分为全局自定义和单页面自定义,如果开启了全局自定义则单页面定义将失效

全局自定义: 在app.json文件中配置

{
  "window": {
    "navigationStyle": "custom"
  }
} 

单页面自定义: 在需要自定义navigationBar页面的json文件中配置

{
  "navigationStyle": "custom"
} 

引入weui

在app.js里添加以下配置即可

"useExtendedLib": {
  "weui": true 
},
"usingComponents": {
  "mp-icon": "weui-miniprogram/icon/icon",
  ...更多weui组件...
}

参考资料