小程序开发攻略:架构|View – WXML、View – WXSS、View – Component

2018-09-0713:10:48APP与小程序开发Comments4,054 views字数 6625阅读模式

小程序架构

小程序开发攻略:架构|View – WXML、View – WXSS、View – Component

微信小程序的框架包含两部分 View 视图层、App Service逻辑层。View 层用来渲染页面结构,AppService 层用来逻辑处理、数据请求、接口调用。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

它们在两个线程里运行。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

它们在两个线程里运行。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

它们在两个线程里运行。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

视图层和逻辑层通过系统层的 JSBridage 进行通信,逻辑层把数据变化通知到视图层,触发视图层页面更新,视图层把触发的事件通知到逻辑层进行业务处理。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

补充文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

小程序开发攻略:架构|View – WXML、View – WXSS、View – Component

视图层使用 WebView 渲染,iOS 中使用自带 WKWebView,在 Android 使用腾讯的 x5 内核(基于 Blink)运行。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

逻辑层使用在 iOS 中使用自带的 JSCore 运行,在 Android 中使用腾讯的 x5 内核(基于 Blink)运行。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

开发工具使用 nw.js 同时提供了视图层和逻辑层的运行环境。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

在 Mac下 使用 js-beautify 对微信开发工具 @v1.02.1808080代码批量格式化:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

cd /Applications/wechatwebdevtools.app/Contents/Resources/package.nw
find . -type f -name '*.js' -not -path "./node_modules/*" -not -path -exec js-beautify -r -s 2 -p -f '{}' \;
复制代码

js/extensions/appservice/index.js 中找到:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

	267: function(a, b, c) {
    const d = c(8),
      e = c(227),
      f = c(226),
      g = c(228),
      h = c(229),
      i = c(230);
    var j = window.__global.navigator.userAgent,
      k = -1 !== j.indexOf('game');
    k || i(), window.__global.getNewWeixinJSBridge = (a) => {
      const {
        invoke: b
      } = f(a), {
        publish: c
      } = g(a), {
        subscribe: d,
        triggerSubscribeEvent: i
      } = h(a), {
        on: j,
        triggerOnEvent: k
      } = e(a);
      return {
        invoke: b,
        publish: c,
        subscribe: d,
        on: j,
        get __triggerOnEvent() {
          return k
        },
        get __triggerSubscribeEvent() {
          return i
        }
      }
    }, window.WeixinJSBridge = window.__global.WeixinJSBridge = window.__global.getNewWeixinJSBridge('global'), window.__global.WeixinJSBridgeMap = {
      __globalBridge: window.WeixinJSBridge
    }, __devtoolsConfig.online && __devtoolsConfig.autoTest && setInterval(() => {
      console.clear()
    }, 1e4);
    try {
      var l = new window.__global.XMLHttpRequest;
      l.responseType = 'text', l.open('GET', `http://${window.location.host}/calibration/${Date.now()}`, !0), l.send()
    } catch (a) {}
  }
复制代码

js/extensions/gamenaitveview/index.js 中找到:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

  299: function(a, b, c) {
    'use strict';
    Object.defineProperty(b, '__esModule', {
      value: !0
    });
    var d = c(242),
      e = c(241),
      f = c(243),
      g = c(244);
    window.WeixinJSBridge = {
      on: d.a,
      invoke: e.a,
      publish: f.a,
      subscribe: g.a
    }
  },
复制代码

js/extensions/pageframe/index.js中找到:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

317: function(a, b, c) {
    'use strict';

    function d() {
      window.WeixinJSBridge = {
        on: e.a,
        invoke: f.a,
        publish: g.a,
        subscribe: h.a
      }, k.a.init();
      let a = document.createEvent('UIEvent');
      a.initEvent('WeixinJSBridgeReady', !1, !1), document.dispatchEvent(a), i.a.init()
    }
    Object.defineProperty(b, '__esModule', {
      value: !0
    });
    var e = c(254),
      f = c(253),
      g = c(255),
      h = c(256),
      i = c(86),
      j = c(257),
      k = c.n(j);
    'complete' === document.readyState ? d() : window.addEventListener('load', function() {
      d()
    })
  },
复制代码

我们都看到了 WeixinJSBridge 的定义。分别都有 oninvokepublishsubscribe 这个几个关键方法。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

invoke 举例,在 js/extensions/appservice/index.js中发现这段代码:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

f (!r) p[b] = s, f.send({
    command: 'APPSERVICE_INVOKE',
    data: {
        api: c,
        args: e,
        callbackID: b
    }
});
复制代码

js/extensions/pageframe/index.js 中发现这段代码:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

g[d] = c, e.a.send({
    command: 'WEBVIEW_INVOKE',
    data: {
        api: a,
        args: b,
        callbackID: d
    }
})

复制代码

简单的分析得知:字段 command 用来区分行为,invoke 用来调用 Native 的 Api。在不同的来源要使用不同的前缀。data 里面包含 Api 名,参数。另外 callbackID 指定接受回调的方法句柄。Appservice 和 Webview 使用的通信协议是一致的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

我们不能在代码里使用 BOM 和 DOM 是因为根本没有,另一方面也不希望 JS 代码直接操作视图。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

在开发工具中 remote-helper.js 中找到了这样的代码:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

const vm = require("vm");

const vmGlobal = {
    require: undefined,
    eval: undefined,
    process: undefined,
    setTimeout(...args) {
        //...省略代码
        return timerCount;
    },
    clearTimeout(id) {
        const timer = timers[id];
        if (timer) {
            clearTimeout(timer);
            delete timers[id];
        }
    },
    setInterval(...args) {
        //...省略代码
        return timerCount;
    },
    clearInterval(id) {
        const timer = timers[id];
        if (timer) {
            clearInterval(timer);
            delete timers[id];
        }
    },
    console: (() => {
        //...省略代码
        return consoleClone;
    })()
};
const jsVm = vm.createContext(vmGlobal);
// 省略大量代码...
function loadCode(filePath, sourceURL, content) {
    let ret;
    try {
        const script = typeof content === 'string' ? content : fs.readFileSync(filePath, 'utf-8').toString();
        ret = vm.runInContext(script, jsVm, {
            filename: sourceURL,
        });
    }
    catch (e) {
        // something went wrong in user code
        console.error(e);
    }
    return ret;
}
复制代码

这样的分层设计显然是有意为之的,它的中间层完全控制了程序对于界面进行的操作, 同时对于传递的数据和响应时间也能做到监控。一方面程序的行为受到了极大限制, 另一方面微信可以确保他们对于小程序内容和体验有绝对的控制。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

这样的结构也说明了小程序的动画和绘图 API 被设计成生成一个最终对象而不是一步一步执行的样子, 原因就是 Json 格式的数据传递和解析相比与原生 API 都是损耗不菲的,如果频繁调用很可能损耗过多性能,进而影响用户体验。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

下载小程序完整包

小程序开发攻略:架构|View – WXML、View – WXSS、View – Component

App Service - Life Cylce

小程序开发攻略:架构|View – WXML、View – WXSS、View – Component

面试题

1.动画需要绑定在 data 上,而绘图却不用。你觉得是为什么呢?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

var context = wx.createCanvasContext('firstCanvas')
    
context.setStrokeStyle("#00ff00")
context.setLineWidth(5)
context.rect(0, 0, 200, 200)
context.stroke()
context.setStrokeStyle("#ff0000")
context.setLineWidth(2)
context.moveTo(160, 100)
context.arc(100, 100, 60, 0, 2 * Math.PI, true)
context.moveTo(140, 100)
context.arc(100, 100, 40, 0, Math.PI, false)
context.moveTo(85, 80)
context.arc(80, 80, 5, 0, 2 * Math.PI, true)
context.moveTo(125, 80)
context.arc(120, 80, 5, 0, 2 * Math.PI, true)
context.stroke()
context.draw()
复制代码
Page({
  data: {
    animationData: {}
  },
  onShow: function(){
    var animation = wx.createAnimation({
      duration: 1000,
  	  timingFunction: 'ease',
    })

    this.animation = animation
    
    animation.scale(2,2).rotate(45).step()
    
    this.setData({
      animationData:animation.export()
    })
  }
})
复制代码

2.小程序的 Http Rquest 请求是不是用的浏览器 Fetch API?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

知识点考察文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

  • 知道 Request 是由 Native 实现的
  • JSCore 是不带 Http Request、Websocket、Storage等功能的,那是 Webkit 带的
  • 小程序的 wx.request 是不是遵循 fetch API 规范实现的呢?答案,显然不是。因为没有 Promise

View - WXML

WXML(WeiXin Markup Language)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

  • 支持数据绑定
  • 支持逻辑算术、运算
  • 支持模板、引用
  • 支持添加事件(bindtap)
小程序开发攻略:架构|View – WXML、View – WXSS、View – Component

Wxml编译器:Wcc 把 Wxml文件 转为 JS文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

执行方式:Wcc index.wxml文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

使用 Virtual DOM,进行局部更新文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

View - WXSS

WXSS(WeiXin Style Sheets)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

小程序开发攻略:架构|View – WXML、View – WXSS、View – Component

wxss编译器:wcsc 把wxss文件转化为 js文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

执行方式: wcsc index.wxss文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

支持大部分CSS特性

亲测包含但不限于如下内容:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

  • Transition
  • Animation
    • Keyframes
  • border-radius
  • calc()
  • 选择器,除了官方文档列出的,其实还支持
    • element>element
    • element+element
    • element element
    • element:first-letter
    • element:first-line
    • element:first-child
    • element:last-child
    • element~element
    • element:first-of-type
    • element:last-of-type
    • element:only-of-type
    • element:only-child
    • element:nth-child(n)
    • element:nth-last-child(n)
    • element:nth-of-type(n)
    • element:nth-last-of-type(n)
    • :root
    • element:empty
    • :not(element)
  • iconfont

建议 Css3 的特性都可以做一下尝试。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

尺寸单位 rpx

rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为 750rpx。公式:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

const dsWidth = 750

export const screenHeightOfRpx = function () {
  return 750 / env.screenWidth * env.screenHeight
}

export const rpxToPx = function (rpx) {
  return env.screenWidth / 750 * rpx
}

export const pxToRpx = function (px) {
  return 750 / env.screenWidth * px
}

复制代码
设备rpx换算px (屏幕宽度/750)px换算rpx (750/屏幕宽度)
iPhone51rpx = 0.42px1px = 2.34rpx
iPhone61rpx = 0.5px1px = 2rpx
iPhone6 Plus1rpx = 0.552px1px = 1.81rpx

可以了解一下 pr2rpx-loader 这个库。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

样式导入

使用 @import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用 ; 表示语句结束。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

内联样式

静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

全局样式与局部样式

定义在 app.wxss 中的样式为全局样式,作用于每一个页面。在 page 的 wxss 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

iconfont

截止20180810文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

小程序未来有计划支持字体。参考微信公开课文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

小程序开发与平时 Web开发类似,也可以使用字体图标,但是 src:url() 无论本地还是远程地址都不行,base64 值则都是可以显示的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

将 ttf 文件转换成 base64。打开这个平台 transfonter.org/。点击 Add fonts 按钮,加载ttf格式的那个文件。将下边的 base64 encode 改为 on。点击 Convert 按钮进行转换,转换后点击 download 下载。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

复制下载的压缩文件中的 stylesheet.css 的内容到 font.wxss ,并且将 icomoon 中的 style.css 除了 @font-face 所有的代码也复制到 font.wxss 并将i选择器换成 .iconfont,最后:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

<text class="iconfont icon-home" style="font-size:50px;color:red"></text>
复制代码

View - Component

小程序提供了一系列组件用于开发业务功能,按照功能与HTML5的标签进行对比如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

小程序开发攻略:架构|View – WXML、View – WXSS、View – Component

小程序的组件基于Web Component标准文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

使用Polymer框架实现Web Component文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

View - Native Component

目前Native实现的组件有文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

  • cavnas
  • video
  • map
  • textarea
    小程序开发攻略:架构|View – WXML、View – WXSS、View – Component

Native组件层在 WebView 层之上。这目前带来了一些问题:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html

  • Native 实现的组件会遮挡其他组件
  • WebView 渲染出来的视图在滚动时,Native 实现的组件需要更新位置,这会带来性能问题,在安卓机器上比较明显
  • 小程序原生组件 cover-view 可以覆盖 cavnas video 等,但是也有一下弊端,比如在 cavnas 上覆盖 cover-view,就会发现坐标系不统一处理麻烦。
文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/4459.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/xcx/4459.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定