F2e踩坑之路JS相关让前端飞

小程序开发总结

2017-12-29  本文已影响199人  人类进化又没带我
还有两三天就跨年了,今天总结下开发小程序的心得与体会

开发前准备
本文首先假定开发者已经粗略阅读过微信小程序的开发文档,所以注册小程序的流程就不介绍了。不过需要注意,小程序现在只允许企业用户注册,所以认证需要企业营业执照复印件和加盖公章的小程序申请公函。如果是选择对公账户认证,则不需要公函。另外,如果需要使用微信支付接口,则需要另外进行一次微信认证,这个就必须使用300块的方式了,如果要进行第三方平台开发小程序,建议使用对公账户,一般几毛钱就能认证一个小程序。

开发工具介绍

我调试用的开发工具就是微信官方提供的IDE,编写代码还是使用Atom编辑器,毕竟代码高亮提示等等是必须的啊,现在也有了很多第三方的IDE或者插件,但是用起来感觉整合度不如官方版,索性不换了。新建项目需要输入注册小程序时获取的AppId。需要注意的是设置页面:其中有一项是开发环境不校验请求域名以及TLS版本。这一项需要勾选上,因为微信只支持HTTPS的协议而且必须是指定域名,这让开发者使用localhost调试变的很麻烦,勾选此项之后就没有这种限制了,但只有在开发环境才可以,
开发者工具调试界面和Chorem浏览的开发者工具类似,调试工具分为 7 大功能模块:Wxml、Console、Sources、Network、Appdata、Storage、Sensor、Trace。

语言
首先,小程序类Web,但不同于我所认识的HTML,他有属于自己的开发语言:

一、准备工作
注册一个小程序账号,得用一个没注册过公众号的邮箱注册。
注册完账号,登录,在主页面左边列表中点击设置,然后再设置页面中选开发设置就可以看到AppID,用于登录开发工具。

二、开始项目


image.png

启动后


image.png

这是官方提供的示例模版

1、框架
先看下一目录: image.png

app.js: 小程序逻辑,生命周期,,全局变量app.json: 小程序公共设置,导航栏颜色等,不可以注释app.wxss :小程序公共样式,类CSS 。

小程序页面构成:
image.png

每一个小程序页面是由同路径下同名的四个不同后缀文件的组成,如:index.js、index.wxml、index.wxss、index.json。

微信小程序中的每一个页面的【路径+页面名】都需要写在 app.json 的 pages 中,且 pages 中的第一个页面是小程序的首页。


image.png

每个基础页面组成


image.png

这四个文件按照功能可以分成三个部分:

配置:json 文件
逻辑层:js文件
视图层:wxss.wxml文件

在 iOS 上,小程序的 javaScript 代码是运行在 JavaScriptCore 中,在 Android上,小程序的 javaScript 代码是通过 X5 内核来解析,在开发工具上,小程序的 javaScript 代码是运行在 NW.js(chrome内核)中,所以开发工具上的效果跟实际效果有所出入。

2、组件

微信提供了许多组件,主要分为八种:

 视图容器、基础内容、表单组件、操作反馈、导航、媒体组件、地图、画布

包含view、scroll-view、button、form等普通常用的组件,也提供了地图map、画布canvas

组件主要属于视图层,通过wxml来进行结构布局,类似于html。通过wxss修改样式,类似于css。组件使用语法实例:

<!--普通视图-->
<view>这是一个普通视图</view>
<!--wxss样式修改-->
<view class="mainView">样式修改过的视图</view>

更多的组件以及相关使用方法可以到官方文档-组件查看

3、API
网络媒体数据位置设备界面开发接口

其中网络请求的使用必须先到公众平台登录小程序账号,在设置页面那里,设置允许访问的域名,网络请求包含了普通的http请求、支持上传、下载、socket。基本上满足了我们开发中所需要的网络需求。

这些API属于逻辑层,写在js文件中,使用示例:

//获取当前定位,返回经纬度等具体信息
wx.getLocation({  
   type: 'wgs84',   
   success: function(res) {       
      var latitude = res.latitude        
      var longitude = res.longitude       
      var speed = res.speed        
      var accuracy = res.accuracy 
    }
})

可以到官方文档-API查看其它API的使用方法。
生命周期
当然,微信小程序和其他前端框架类似也是有生命周期的:

Page({
/**
* 页面的初始数据
*/
data: {},

/**
* 生命周期函数--监听页面加载(像首页数据请求可以放在这里)
*/
onLoad: function (options) {},

/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {},

/**
* 生命周期函数--监听页面显示
*/
onShow: function () {},

/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {},

/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {},

/**
* 页面相关事件处理函数--监听用户下拉动作(这里添加了下拉刷新的功能)
*/
onPullDownRefresh: function () {},

/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {},

/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {}
})

当我们在data中初始化的值需要修改时,可在各生命周期及方法中通过setData()修改。由于小程序的入口页面就是首页,在首页添加了用户登陆和网络状态的检测在onLoad中。

tabBar

tabBar即小程序的底部导航栏,由于微信的限制,最少2个最多5个导航栏,只可设置文案、图标。(知识点:图的大小为81px边缘要留透明的白边,不然图会很大)

样式

小程序样式采用WXSS语言(具有CSS大部分特性)。他也提供了一种新的单位rpx(可根据屏幕宽度自行适应)。官方规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素,既然这样我们也推荐了我们设计师采用iPhone6作为设计标准,即750px宽度。
但是在实际的开发过程中如果字体大小也使用rpx做单位的话,在iPhone6 Puls上显示文字过大,影响美观。后经过测试采用了px做单位,即原设计稿尺寸的一半+px,这样可以保证文字大小在各设备中保持一致。

网络状态

在官方文档上有明确规定,本地资源是无法通过CSS获取的,图片的话只能使用网络资源或base64方式。首页有个需要判断网络状态的需求,由于断网情况下无法获取网络资源,最后就使用了base64的方式。
官方获取网络状态的API是getNetworkType为异步接口,通过它的返回结果再进行下一步(是显示无网络还是调用数据列表接口),说到这里大家都知该怎么办了——Promise,具体封装如下

new Promise((resolve, reject) => {
  let req = wx.getNetworkType({
    success: function (res) {
      var networkType = res.networkType;
      if (networkType === 'none') {
        resolve(false)
      } else {
        resolve(true)
      }
    },
    fail() {
      reject(false)
    }
  });
})
调试

调试的时候最大的问题呢是:无论是开发者工具上还是手机上,记得先把缓存删干净再测。特别是开发者工具每次切换host都要清理缓存,再重新打开,而且出现bug的时候尽量多测几次,进行反复确定。不然的话,你可能会发现,本来测好的功能又出现问题了,或者是本来有问题的部分又没有问题了。

页面编写 (跟vue类似)

知识点1:

<text wx:for="{{titles}}"  wx:key="{{item}}"  class="home-title {{index == activeIndex ? 'active' : ''}}" bindtap='changeClassify'>
 {{item.name}}
</text>
// index == activeIndex class为 "home-title active" 否则为 "home-title "

知识点2:

// 普通的单次循环
<text wx:for="{{titles}}" wx:key="{{index}}">{{item.name}}</text>

//循环嵌套时使用 wx:for-item="XXX" 
<view wx:for="{{hotArr}}">
  <view class="classify-title" bindtap="goClassifyPage">
    <text>{{item.name}}</text>
  </view>

  <view class="classify-items">
    <view class="classify-item" wx:for="{{item.data}}"  wx:for-item="cell" wx:key="index">
      <view>
        <text class="classify-item_name">{{cell.name}}</text>
      </view>
    </view>
  </view>
</view>

知识点3:

//router 跳转传参及参数获取
<text wx:for="{{titles}}" wx:key="{{index}}" bindtap='changeClassify' data-id="{{index}}">{{item.name}}</text>
//js
function changeClassify(e) {
  //
  let id = e.currentTarget.dataset.id;

  //跳转到classify 页面
  wx.navigateTo({
    url: '../classify/classify?id=' + id
  })
}

//classify 页面 获取参数
onLoad: function (opts) {
  console.log(opts.id)
  console.log(this.options.id)
}

知识点:4

上拉加载更多, 下拉刷新
// 上拉加载更多
onReachBottom() {
  if (this.data.next) {
    this.setData({ isHideLoadMore: false })
    this.getNextPage()
  }
}
// 下拉刷新
onPullDownRefresh: function() {
  this.refreshData()
}
//this.refreshDate里一定要使用停止下拉刷新的API

知识点:5

对于通用的组件可以抽出一个template
/**
* 1. 给template 设置name
* 2. 组件传过来的值可以直接使用  hidden="{{!isloading}}"
*/
<template name="loading">
  <view class="qtshe-loadmore" hidden="{{!isloading}}">
    <view class="qtshe-loading"></view>
    <view class="qtshe-loadmore-tips">正在加载</view>
  </view> 
</template>
// 
/** 
* 使用通用的template 
* 1. 按路径引入
* 2. 设置 is 等于 template的name data="{{isloading}}" 给template的数据
*/
<import src="../template/loading.wxml"/>
<template is="loading" data="{{isloading}}"></template>

知识点:6

如果你的页面需要加载一段html
踩坑(详细问题看精品兼职详情页)
 <scroll-view class="recommend_scroll_x_box" scroll-x="true">
      <view class="recommend_hot_box" wx:for="{{hotList}}">
        <image src="{{item.pic}}" class="recommend_hot_image"></image>
      </view>
    </scroll-view>

scroll-view.wxss

.recommend_scroll_x_box {
  height: 245rpx;
  white-space: nowrap;
  display: flex;
}

::-webkit-scrollbar {
  width: 0;
  height: 0;
  color: transparent;
}

.recommend_hot_box {
  width: 230rpx;
  height: 245rpx;
  margin-right: 24rpx;
  display: inline-block;
}

.recommend_hot_image {
  width: 230rpx;
  height: 143rpx;
}

scroll-view.js

Page({
  data: {
    hotList: [
      {
        pic: 'https://ojlf2aayk.qnssl.com//act/1501760559/banner.png'
      }, {
        pic: 'https://ojlf2aayk.qnssl.com//act/1501760559/banner.png'
      }, {
        pic: 'https://ojlf2aayk.qnssl.com//act/1501760559/banner.png'
      }, {
        pic: 'https://ojlf2aayk.qnssl.com//act/1501760559/banner.png'
      }, {
        pic: 'https://ojlf2aayk.qnssl.com//act/1501760559/banner.png'
      }
    ]
  }

完美解决

因为前端通过小程序官方提供的接口获取到的是个二进制的流,使用小程序自带的image标签是不能进行展示的,并且前端暴露AppID和AppSecret密钥不安全,所以这里的操作都是需要后端来进行的,此时交给后端进行转换并返回一张小程序码的图片给你。

前端只需要拿到后端返回图片的图片展示即可。现与后端约定:

我给页面page(第一,第三个接口是path)路径,以及需要的scene字段。

期间遇到的问题:scene字段是什么?我怎么拿到?

期间设想scene是扫码后才能拿到的场景值,注意是扫码后才会有,那我怎么生成小程序码,这里陷入一个误区了。

其实scene在这里你可以理解为传参数的一个字段。

⚠️第一个第三个接口是不需要传入scene字段的且字段为path

path: 'pages/index/index?jobId=111111' //此时字段是path

⚠️第二个接口是需要的且字段为page

scene: 'jobId=111111',  //(string类型)
page: 'pages/index/index' //此时字段是page注意前面不要加'/'

⚠️生成的小程序码都是只能跳转线上的小程序页面,如果线上没有页面是跳转不了的,当然跳转后需要在我要跳转的页面onLoad里拿到scene字段然后进行逻辑操作

使用如下代码可以获取到二维码中的 scene 字段的值。调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 encodeUrl

Page({
  onLoad: function(options) {
    // options 中的 scene 需要使用 decodeURIComponent 才能获取到生成二维码时传入的 scene
    var scene = decodeURIComponent(options.scene)
  }
})
<view class="canvas-box" wx:if="{{isCanvas}}">
  <canvas style="width: {{canvasWidth}}px; height: {{canvasHeight}}px; margin:0 auto;" canvas-id="mycanvas" />
</view>
//将title绘制到canvas的固定位置
  setName(context) {
    var unit = this.data.screenWidth / 375
    var title = this.data.partJobVo.title
    context.setFontSize(18)
    context.setFillStyle('#333333')
    context.save()
    context.translate(24 * unit, 40 * unit) //必须先将旋转原点平移到文字位置
    context.fillText(title, 0, 0) //必须为(0,0)原点
    context.restore()
    context.stroke()
  },
  //将金额绘制到canvas的固定
  setMoney(context) {
    var unit = this.data.screenWidth / 375
    var money = this.data.partJobVo.salary
    context.setFontSize(22)
    context.setFillStyle('#FF2A52')
    context.fillText(money, 24 * unit, 80 * unit)
    context.stroke()
  },
  setQrcode(context) {
    var unit = this.data.screenWidth / 375
    let path = this.data.qtPath
    context.drawImage(path, 200 * unit, 50 * unit, 120 * unit, 120 * unit)
  },
  //将canvas转换为图片保存到本地,然后将图片路径传给image图片的src
  createNewImg() {
    var that = this
    var unit = this.data.screenWidth / 375
    var context = wx.createCanvasContext('mycanvas')
    var path = that.data.qtPaths
    context.drawImage(path, 0, 0, 343 * unit, 220 * unit)
    that.setMoney(context)
    that.setName(context)
    that.setQrcode(context)
    //绘制图片
    context.draw()
    context.save()
    //将生成好的图片保存到本地,需要延迟一会,绘制期间耗时
    setTimeout(() => {
      wx.canvasToTempFilePath({
        canvasId: 'mycanvas',
        success: function(res) {
          wx.hideLoading()
          that.setData({
            imagePath: res.tempFilePath
          })
        },
        fail: function(res) {
          console.log(res.errMsg)
        }
      })
    }, 2000)
  },
  savePhoto() {
    var that = this
    wx.showLoading({
      title: '正在保存...',
      mask: true
    })
    setTimeout(() => {
      wx.saveImageToPhotosAlbum({
        filePath: that.data.imagePath,
        success(res) {
          that.wetoast.toast({
            title: '保存成功',
            duration: 1500
          })
          setTimeout(() => {
            wx.hideLoading()
            that.setData({
              isCanvas: false,
              isXcxCode: false
            })
          }, 300)
        },
        fail() {
          that.wetoast.toast({
            title: '保存失败,请重试',
            duration: 1500
          })
          setTimeout(() => {
            wx.hideLoading()
            that.setData({
              isCanvas: false,
              isXcxCode: false
            })
          }, 300)
        }
      })
    }, 2000)
  }

测试(IOS6.5.22有问题,安卓6.5.23有问题)其他版本都是好的,微信客户端的问题,后端也是可以截图的,但是因为暂时没有资源,最后导致砍掉这个功能。
其他坑,也有很多小的坑,就不一一说了。遇到了你可以来问下我,万一我早就遇到并解决了呢。(联系方式就留在最下边吧,毕竟还要打一波广告)

4、编译运行

1、模拟器可以在模拟器上看效果,上面讲到了运行底层不同,效果跟在手机上运行有些差异(感谢运营小姐姐的美图)


image.png

2.真机预览,点预览会生产一个二维码,用管理员微信号扫一扫就可以在真机上看实际效果


image.png
真机预览效果图
image.png

坑挺多的,不过业务前景还是挺不错的,小程序最近出了小游戏。看了一下源代码,头疼ing。
再推荐一波开源的demo:

微信小程序 - 从零开始制作一个跑步微信小程序 - 前端 - 掘金

微信小程序电影推荐 demo 实战开发小结(附源码及思维导图) - 前端 - 掘金

微信小程序 - 仿淘宝 - 前端 - 掘金

微信小程序 Demo - 仿知乎 - 前端 - 掘金

仿 「ONE · 一个」 微信小程序 - 前端 - 掘金

比较完整的微信小程序示例 - 知乎日报 - 前端 - 掘金

微信小程序实现 1024 小游戏 - 前端 - 掘金

一个干净的简单的微信小程序 Demo - 前端 - 掘金

微信小程序实战之 Gank 客户端 - 前端 - 掘金

微信小程序 cnode 社区版 - 前端 - 掘金

微信小程序 音乐播放器 真机测试 - 前端 - 掘金

最后重磅来了

青团社招聘:

招聘岗位:高级前端开发工程师P5及以上
坐标杭州市余杭区文一西路1380号金之源大厦11层

简历投递到:hr@qtshe.com||haochen@qtshe.com

职位描述:

1、建设工具、提炼组件、抽象框架,促进前端工程化、服务化,持续提升研发效率,保障线上产品质量

2、构建H5/PC应用基础设施,主导建设前端各种发布/监控等平台,指导落实解决方案

3、持续优化前端页面性能,维护前端代码规范,钻研各种前沿技术和创新交互,增强用户体验、开拓前端能力边界

祝大家新年快乐,在新的一年里,事业节节高升。

上一篇下一篇

猜你喜欢

热点阅读