Open PengXing opened 6 years ago
我有一个问题:如果每个组件只需要用自己的数据,是不是就和 props 一样了。
@huanghuiquan 组件内部可以写 js
我理解这里的 initStore 不是为了构建组件自己的 data,而是类似于向页面的 store 去 register,从而构建页面那个 store?这样 store 感觉就是按照业务模块来组织起来的了,比如
<mip-content>
<mip-a>
{
name: '',
list: [],
objNeedShare: {}
}
</mip-a>
<mip-b>
<mip-content>
store: {
state: {
'mip-a': {
name: '', ...
},
'mip-b': {}
}
}
这里还有个问题:merge 操作的时候,页面间要共享的数据也未必是同级对应的吧?还是说这里需要一个规则,如果想要共享数据,在 state 树的位置就要对应?而且按前面的理解,store 是按照页面模块组织的,要共享数据的话,似乎也不太可能百分百要求页面之间的模块就存在对应关系,再找到模块下的 state 来 merge
我原来的想法是全局 store,然后因为我们实际上是 mpa,我们不能一下子获取所有页面的 store 信息,可是我们应该可以在用户的访问过程中逐步给全局 store 增加 module(这些 module 对应页面),可是问题又在于如果站内有很多页面,store 就很非常大,而且数据可能会存在冗余。不过这个方法倒是比较直接,也不会存在需要通知另一个页面我改变了什么数据的操作问题
@huanghuiquan @ccksfh ck 理解的对,是向全局的 store 去 register 一个 namespace 的初始值
按照组件来行不通吧,一个页面包括多个同名的组件,怎么做 store 的设计?按照 Vue 的还应该是按照业务模块来
所以,store 并不是没有工作量的
@xiaoiver
一个子组件需要获取数据,有几种方式
根据4 月 27 日
上午的会议决定,MIP2.0 的 store 沿用 vuex 和 vue 的项目,保持全局统一的地方书写 store 及初始化,考虑的原因主要有以下:
综上所述,我们依然保留 vuex 的全局 store 的逻辑
用户在调用 mip2 publish
的时候,将带有 components, store, common, static, package.json
的项目提交到 MIP 端进行审核
OVER.
mip 1.0页面是被iframe隔离渲染的,如果2.0保留此机制,全局的store共享需要考虑iframe数据传递。
MIP2.0 暂定是在同一个上下文进行渲染,不需要 iframe 数据传递,后续如果同一上下文渲染有问题,再来考虑放在 iframe 进行渲染
搜索侧也是同一个上下文渲染吗?
同一个 host 同一个上下文
基于以上 mip-store 的基本方案制定以下规范:
开发者可以在提交项目的时候同时提交 store 文件夹,并在文件夹中创建单独的模块文件, mip 会将这些单独的模块组合起来,生成最终的 Vuex.Store 实例。mip 默认一个文件代表一个模块,以目录/文件名作为命名空间,可嵌套,默认 namespaced: true;若发现 index.js 模块,默认注册到全局;每个模块至少包含 state,而 state 必须是一个返回初始状态的方法。lavas/nuxt 的方式
示例:
// user.js
export const state = () => {
return {
users: []
};
};
export const mutations = {
addUser(state, userInfo) {
state.users.push(userInfo);
}
};
...
2. 对于开发者需要用到的全局初始数据,我们鼓励开发者使用 mip-store 组件设置数据源。要求 mip-store 不得被嵌套在其他标签下。使用 mip-store 主要有两种方式:
1. **同步数据**
在这里我们要求开发者必须把同步数据放在 **_model_** 层级下
<mip-store>
<script type="application/json">
{
"model": {
"name": "张三",
"age": 25,
"job": {
"desc": "互联网从业者",
"location": "北京"
}
}
}
</script>
</mip-store>
2. **异步数据**
如果需要异步数据,则需指定 src 地址(注:src 需要是 https 或 // 协议开头,否则在 HTTPS 环境下会出现问题),如
<mip-store src="https://www.example.org/data"></mip-store>
熟悉 mip1 的朋友应该比较了解,与 mip-data 类似
mip-store 获取到数据后会把数据放到全局 store 的 **global** 命名空间下,开发者可在任意页面和任意组件使用其中的数据。
mip-store 提供了 **global/setData** 的 mutation 方法,方便开发者更改 global 空间下的数据。该方法接受一个 _Object_ 作为参数,示例:
```javascript
state {
detail: {
info: {
name: 'detail-1',
content: '',
desc: ''
}
}
}
...mip.Store.mapMutations('global', ['setData'])
this.setData({
detail: {
info: {
name: 'detail-2'
}
}
})
考虑到某些特殊情况(需要提升成内置却又自带 store 的组件),我们提供 initStore 的生命周期钩子,开发者可以通过这个钩子在组件加载的时候动态向全局 store 注册 store module,要求书写方式如下:
initStore() {
return {
// 指定命名空间,如果需要多级命名空间的就用 / 分割,比如 'appshell/appheader',模块默认 namespaced: true
namespace: '',
// 模块注册内容规范参照本规范第一条
module: {
state: () => {
return {};
},
getters: {},
mutations: {},
actions: {}
}
}
}
我们提供全局的 mip.Store,开发者可以通过调用 mip.Store.mapState/mapGetters/mapMutations/mapActions 等方法,或者在组件中调用 this.$store.dispatch 等方法,就像使用 vuex 一样管理数据
目前 mip-store 组件并非内置组件,要求对这个组件的引用必须在 mip.js 之后,其他自定义组件之前。(是否应该内置还有待商榷) 已内置
欢迎讨论
基于 2018.5.14 的会议,store 设计方案改为类似单向数据流的设计,以上规范作废。移除 vuex 相关代码、移除 mip-store 内置组件、移除 initStore 生命周期钩子、组件提交不需要提交 store 文件夹。
补充一句: 目前 mip-store 单独的例子在 examples/store/index.html 集成在 SPA 环境中的例子在 examples/page/data.html
均包含了同步和异步两种设置和获取数据的方式。提交 store 文件夹的方式在 page 的例子中暂不包括。待确定最终引入方式(可能 @clark-t @ccksfh )之后再行确定。
沿用 mip1 的 mip-data 和 mip-bind,在此基础上增加
支持开发者在 MIP 页面中编写 JS 操作 state,要求使用以下 type 作为标识:
<script type="application/mip-script"></script>
在 script 中仅允许操作 state,建议操作有
观察数据变化
MIP.watch([数据字段,以 . 分割]: String | Array, cb(newVal, oldVal))
修改全局数据
MIP.setData()
支持多页共享 state:在需要全局共享的数据前添加 # 标识(仅检测数据第一层),如
<mip-data>
<script type="application/json">
{
"#globalState": {},
"pageState": []
}
</script>
</mip-data>
提升为全局态的 state 将在每个页面都能读取到,如果页面自身有与全局 state 的数据冲突的字段,将优先读取页面数据,页面数据不存在将读取全局数据
调用 MIP.setData 修改数据时,不需要给数据带上 # 标识
基于单向数据流的设计,我们给出的最佳实践如下:
a.html
<mip-a m-bind:globaldata="globalState"></mip-a>
mip-a 组件内部
template: `
<div>
<mip-b :globaldata="globaldata"></mip-b>
</div>
`,
props: {
globaldata: {
type: Object
}
}
组件内部 不允许 使用 m-bind: 语法来绑定全局数据
组件内部可以通过调用 MIP.setData 来修改全局数据,重新渲染组件
背景
有必要先阐述一下传统的 Vue 项目和 MIP2.0 的设计的不同之处。
Vue 的渲染模式
完全是 SPA 的,所有资源都在第一次加载初始化,特点有这些
MIP2.0 的渲染模式
MIP2.0 的渲染模式和 Vue 有本质的区别,是将多个(或单个)通过 customElement 堆积而成的 HTML 页面通过 runtime/router 用 JS 在一个 webview 里渲染,每个 HTML 的页面也能直接访问,因此,每个单独的 HTML 页面都需要一个自身能够运行的所有资源的方案,包括 runtime/router, store, mip-elements.js 等等,这里我们不讨论怎么避免重复加载 runtime 或者 elements 的资源,集中在 store 上。
MIP 2.0 的 store 的需求和问题
综上所述,MIP2.0 的 store 有几个需求:
MIP2.0 store 的设计
store
的数据还通过mapState
的方式来使用,方式不变