小程序的mpvue

mpvue

Vue.js 小程序版, forkvuejs/vue@2.4.1,保留了 vue runtime 能力,添加了小程序平台的支持。 mpvue 是一个使用 Vue.js 开发小程序的前端框架。框架基于 Vue.js 核心,mpvue 修改了 Vue.jsruntimecompiler 实现,使其可以运行在小程序环境中,从而为小程序开发引入了整套 Vue.js 开发体验

框架原理

两个大方向

  • 通过mpvue提供 mpruntime 适配小程序
  • 通过mpvue-loader产出微信小程序所需要的文件结构和模块内容

七个具体问题

  • 要了解 mpvue 原理必然要了解 Vue 原理,这是大前提

现在假设您对 Vue 原理有个大概的了解

  • 由于 Vue 使用了 Virtual DOM,所以 Virtual DOM可以在任何支持 JavaScript 语言的平台上操作,譬如说目前 Vue 支持浏览器平台或 weex,也可以是 mp(小程序)。那么最后 Virtual DOM 如何映射到真实的 DOM节点上呢?vue为平台做了一层适配层,浏览器平台见 runtime/node-ops.jsweex平台见runtime/node-ops.js,小程序见runtime/node-ops.js。不同平台之间通过适配层对外提供相同的接口,Virtual DOM进行操作Real DOM节点的时候,只需要调用这些适配层的接口即可,而内部实现则不需要关心,它会根据平台的改变而改变
  • 所以思路肯定是往增加一个 mp 平台的 runtime方向走。但问题是小程序不能操作 DOM,所以 mp 下的node-ops.js里面的实现都是直接 return obj
  • Virtual DOM 和旧 Virtual DOM 之间需要做一个 patch,找出 diffpatch完了之后的 diff 怎么更新视图,也就是如何给这些 DOM 加入 attrclassstyleDOM 属性呢? Vue中有 nextTick 的概念用以更新视图,mpvue这块对于小程序的 setData 应该怎么处理呢?
  • 另外个问题在于小程序的 Virtual DOM 怎么生成?也就是怎么将 template编译成render function。这当中还涉及到运行时-编译器-vs-只包含运行时,显然如果要提高性能、减少包大小、输出 wxmlmpvue 也要提供预编译的能力。因为要预输出 wxml 且没法动态改变 DOM,所以动态组件,自定义 render,和<script type="text/x-template">字符串模版等都不支持

另外还有一些其他问题,最后总结一下

  • 1.如何预编译生成render function
  • 2.如何预编译生成 wxmlwxsswxs
  • 3.如何 patchdiff
  • 4.如何更新视图
  • 5.如何建立小程序事件代理机制,在事件代理函数中触发与之对应的vue组件事件响应
  • 6.如何建立vue实例与小程序 Page实例关联
  • 7.如何建立小程序和vue生命周期映射关系,能在小程序生命周期中触发vue生命周期

platform/mp的目录结构

.
├── compiler //解决问题1,mpvue-template-compiler源码部分
├── runtime //解决问题3 4 5 6 7
├── util //工具方法
├── entry-compiler.js //mpvue-template-compiler的入口。package.json相关命令会自动生成mpvue-template-compiler这个package。
├── entry-runtime.js //对外提供Vue对象,当然是mpvue
└── join-code-in-build.js //编译出SDK时的修复

mpvue-loader

mpvue-loadervue-loader 的一个扩展延伸版,类似于超集的关系,除了vue-loader 本身所具备的能力之外,它还会利用mpvue-template-compiler生成render function

entry

  • 它会从 webpack 的配置中的 entry 开始,分析依赖模块,并分别打包。在entryapp 属性及其内容会被打包为微信小程序所需要的 app.js/app.json/app.wxss,其余的会生成对应的
  • 页面page.js/page.json/page.wxml/page.wxss,如示例的 entry 将会生成如下这些文件,文件内容下文慢慢讲来:
// webpack.config.js
{
    // ...
    entry: {
        app: resolve('./src/main.js'),               // app 字段被识别为 app 类型
        index: resolve('./src/pages/index/main.js'),   // 其余字段被识别为 page 类型
        'news/home': resolve('./src/pages/news/home/index.js')
    }
}

// 产出文件的结构
.
├── app.js
├── app.json
├──· app.wxss
├── components
│   ├── card$74bfae61.wxml
│   ├── index$023eef02.wxml
│   └── news$0699930b.wxml
├── news
│   ├── home.js
│   ├── home.wxml
│   └── home.wxss
├── pages
│   └── index
│       ├── index.js
│       ├── index.wxml
│       └── index.wxss
└── static
    ├── css
    │   ├── app.wxss
    │   ├── index.wxss
    │   └── news
    │       └── home.wxss
    └── js
        ├── app.js
        ├── index.js
        ├── manifest.js
        ├── news
        │   └── home.js
        └── vendor.js

wxml 每一个 .vue 的组件都会被生成为一个 wxml 规范的 template,然后通过 wxml 规范的 import 语法来达到一个复用,同时组件如果涉及到 propsdata 数据,我们也会做相应的处理,举个实际的例子:

<template>
    <div class="my-component" @click="test">
        <h1>{{msg}}</h1>
        <other-component :msg="msg"></other-component>
    </div>
</template>
<script>
import otherComponent from './otherComponent.vue'

export default {
  components: { otherComponent },
  data () {
    return { msg: 'Hello Vue.js!' }
  },
  methods: {
    test() {}
  }
}
</script>

这样一个 Vue的组件的模版部分会生成相应的 wxml

<import src="components/other-component$hash.wxml" />
<template name="component$hash">
    <view class="my-component" bindtap="handleProxy">
        <view class="_h1">{{msg}}</view>
        <template is="other-component$hash" wx:if="{{ $c[0] }}" data="{{ ...$c[0] }}"></template>
    </view>
</template>

可能已经注意到了 other-component(:msg="msg") 被转化成了 。mpvue 在运行时会从根组件开始把所有的组件实例数据合并成一个树形的数据,然后通过 setDataappData,$c$children 的缩写。至于那个 0 则是我们的 compiler处理过后的一个标记,会为每一个子组件打一个特定的不重复的标记。 树形数据结构如下

// 这儿数据结构是一个数组,index 是动态的
{
  $child: {
    '0'{
      // ... root data
      $child: {
        '0': {
          // ... data
          msg: 'Hello Vue.js!',
          $child: {
            // ...data
          }
        }
      }
    }
  }
}

wxss

这个部分的处理同 web 的处理差异不大,唯一不同在于通过配置生成 .css.wxss ,其中的对于 css的若干处理,在 postcss-mpvue-wxsspx2rpx-loader 这两部分的文档中又详细的介绍

  • 推荐和小程序一样,将 app.json/page.json 放到页面入口处,使用 copy-webpack-plugin copy 到对应的生成位置。

这部分内容来源于 apppageentry 文件,通常习惯是 main.js,你需要在你的入口文件中 export default { config: {} },这才能被我们的 loader 识别为这是一个配置,需要写成 json 文件

import Vue from 'vue';
import App from './app';

const vueApp = new Vue(App);
vueApp.$mount();

// 这个是我们约定的额外的配置
export default {
    // 这个字段下的数据会被填充到 app.json / page.json
    config: {
        pages: ['static/calendar/calendar', '^pages/list/list'], // Will be filled in webpack
        window: {
            backgroundTextStyle: 'light',
            navigationBarBackgroundColor: '##455A73',
            navigationBarTitleText: '美团汽车票',
            navigationBarTextStyle: '##fff'
        }
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值