小程序底层简单剖析实现-logic层解析

目录

logic层主要运行我们的业务逻辑代码,我们写的大部分业务代码比如 methods 和 生命周期里面的代码都在这里,通过接收来自 UI层的生命周期触发通知或者事件调用通知来执行相应函数。

初始化实例

当收到 UI层vue实例的created通知,则在logic层也对应实现一份相对简单的实例数据

const componentOptions = compCtx(pagePath).default

const c = (componentMap[`${pid},${cid}`] = new Component(componentOptions, {
    route: res.route,
    cid,
    pid,
    initData: res.initData
  }))

其中 cid 是组件id,使用 vue实例的唯一id;而 pid 是页面id,由路由创建页面的时候分配。

我们看看 Component 做了什么:

class Component {
  constructor(options, { cid, pid, route, initData }) {
    this.cid = cid
    this.pid = pid
    this._route = route
    this.data = initData // 含props

    // 处理方法事件
    if (isObject(options.methods)) {
      for (const k in options.methods) {
        if (isFunction(options.methods[k])) {
          this[k] = options.methods[k]
        }
      }
    }

    // 处理生命周期
    for (const k in lifetimeMappings) {
      // 先设置默认的生命周期
      this[lifetimeMappings[k]] = noop
    }
    for (const k in lifetimeMappings) {
      if (isFunction(options[k])) {
        this[lifetimeMappings[k]] = options[k]
      }
    }

    if (cid === 1) {
      // page组件
      this.onShow = isFunction(options.onShow) ? options.onShow : noop
      this.onHide = isFunction(options.onHide) ? options.onHide : noop
    } else {
      // 子组件
      this.onShow = noop
      this.onHide = noop

      if (isObject(options.pageLifetimes)) {
        if (isFunction(options.pageLifetimes.show)) {
          this.onShow = options.pageLifetimes.show
        }
        if (isFunction(options.pageLifetimes.hide)) {
          this.onHide = options.pageLifetimes.hide
        }
      }
    }
  }

  ...
}
  • 为了不需要同步去实现propscomputed逻辑,初始数据 initData 不使用业务 options 写的,而是同步UI层的数据(包括data, props, computed)
  • methods和生命周期同步自 options。

以下是一个生成的实例:

image.png

setData

由于Vue的响应式原理是一个比较复杂的工程,逻辑层用了跟小程序类似的 setData 来手动触发变化。

每一次setData先对自身实例数据进行修改,再通知到UI层。

class Component {
  ...

  setData(data) {
    const newData = {}
    for (const k in data) {
      try {
        mergeData(this.data, k, data[k])
        newData[k] = data[k]
      } catch (e) {
        console.error(e.message)
      }
    }

    postMessageToPage(
      {
        cmd: SET_DATA,
        data: newData
      },
      this.cid,
      this.pid
    )
  }
}

以上代码中,我们发现了 mergeData 这函数,因为小程序的setData是支持 a.b.c.d 这种key值方式,这样可以避免大量数据的修改。

function mergeData(parent, key, value) {
  if (isString(key)) {
    if (key.indexOf('.') !== -1) {
      let [a, ...b] = key.split('.')
      mergeData(parent[a], b.join('.'), value)
      return
    }
  }

  parent[key] = value
}

上一篇
下一篇

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。