提交 f692fe15 编写于 作者: fxy060608's avatar fxy060608

feat(v3): init

上级 5995070e
......@@ -5853,7 +5853,7 @@ var serviceContext = (function () {
);
}
function restoreGlobal(
function restoreGlobal (
newWeex,
newPlus,
newSetTimeout,
......@@ -6336,6 +6336,7 @@ var serviceContext = (function () {
const WEBVIEW_READY = 'webviewReady';
const WEBVIEW_UI_EVENT = 'webviewUIEvent';
const VD_SYNC_CALLBACK = 'vdSyncCallback';
const pageFactory = Object.create(null);
......@@ -6347,7 +6348,7 @@ var serviceContext = (function () {
return pageFactory[pagePath]()
});
function createPage (pagePath, pageId) {
function createPage (pagePath, pageId, pageQuery, pageInstance) {
if (!pageFactory[pagePath]) {
console.error(`${pagePath} not found`);
}
......@@ -6355,7 +6356,9 @@ var serviceContext = (function () {
const pageVm = new (getPageVueComponent(pagePath))({
mpType: 'page',
pageId,
pagePath
pagePath,
pageQuery,
pageInstance
});
if (process.env.NODE_ENV !== 'production') {
console.log(`new ${pagePath}`, Date.now() - startTime);
......@@ -6430,6 +6433,9 @@ var serviceContext = (function () {
const index = pages.findIndex(page => page === this);
if (index !== -1) {
pages.splice(index, 1);
if (!webview.nvue) {
this.$vm.$destroy();
}
if (process.env.NODE_ENV !== 'production') {
console.log(`[uni-app] removePage`, path, webview.id);
}
......@@ -6461,9 +6467,7 @@ var serviceContext = (function () {
}
}, [pageId]);
pageInstance.$vm = createPage(route, pageId);
pageInstance.$vm.$scope = pageInstance;
pageInstance.$vm.$mount();
createPage(route, pageId, query, pageInstance).$mount();
}
}
......@@ -7674,7 +7678,8 @@ var serviceContext = (function () {
pause: [],
resume: [],
start: [],
stop: []
stop: [],
error: []
};
class RecorderManager {
......@@ -8942,8 +8947,12 @@ var serviceContext = (function () {
};
}
function noop() {}
const callbacks$a = []; // 数据同步 callback
class VDomSync {
constructor (pageId, pagePath) {
constructor(pageId, pagePath) {
this.pageId = pageId;
this.pagePath = pagePath;
this.batchData = [];
......@@ -8955,9 +8964,19 @@ var serviceContext = (function () {
this._init();
}
_init () {
_init() {
UniServiceJSBridge.subscribe(VD_SYNC_CALLBACK, () => {
const copies = callbacks$a.slice(0);
callbacks$a.length = 0;
for (let i = 0; i < copies.length; i++) {
copies[i]();
}
});
registerWebviewUIEvent(this.pageId, (cid, nid, event) => {
console.log(`[EVENT]`, cid, nid, event);
event.preventDefault = noop;
event.stopPropagation = noop;
if (
this.handlers[cid] &&
this.handlers[cid][nid] &&
......@@ -8966,29 +8985,49 @@ var serviceContext = (function () {
this.handlers[cid][nid][event.type].forEach(handler => {
handler(event);
});
} else {
console.error(`event handler[${cid}][${nid}][${event.type}] not found`);
}
});
}
getVm (id) {
addMountedVm(vm) {
vm._$mounted(); // 触发vd数据同步
this.addCallback(function mounted() {
vm.__call_hook('mounted');
});
}
addUpdatedVm(vm) {
vm._$updated(); // 触发vd数据同步
this.addCallback(function mounted() {
vm.__call_hook('updated');
});
}
addCallback(callback) {
isFn(callback) && callbacks$a.push(callback);
}
getVm(id) {
return this.vms[id]
}
addVm (vm) {
addVm(vm) {
this.vms[vm._$id] = vm;
}
removeVm (vm) {
removeVm(vm) {
delete this.vms[vm._$id];
}
addEvent (cid, nid, name, handler) {
addEvent(cid, nid, name, handler) {
const cHandlers = this.handlers[cid] || (this.handlers[cid] = Object.create(null));
const nHandlers = cHandlers[nid] || (cHandlers[nid] = Object.create(null));
(nHandlers[name] || (nHandlers[name] = [])).push(handler);
}
removeEvent (cid, nid, name, handler) {
removeEvent(cid, nid, name, handler) {
const cHandlers = this.handlers[cid] || (this.handlers[cid] = Object.create(null));
const nHandlers = cHandlers[nid] || (cHandlers[nid] = Object.create(null));
const eHandlers = nHandlers[name];
......@@ -9000,11 +9039,11 @@ var serviceContext = (function () {
}
}
push (type, nodeId, data) {
push(type, nodeId, data) {
this.batchData.push([type, [nodeId, data]]);
}
flush () {
flush() {
if (!this.initialized) {
this.initialized = true;
this.batchData.push([PAGE_CREATED, [this.pageId, this.pagePath]]);
......@@ -9020,7 +9059,7 @@ var serviceContext = (function () {
}
}
destroy () {
destroy() {
this.batchData.length = 0;
this.vms = Object.create(null);
this.initialized = false;
......@@ -9044,8 +9083,7 @@ var serviceContext = (function () {
}
}
function diff (newData, oldData) {
const result = Object.create(null);
function diff (newData, oldData, result) {
let id, cur, old;
for (id in newData) {
cur = newData[id];
......@@ -9059,25 +9097,47 @@ var serviceContext = (function () {
return result
}
function initData (Vue) {
function initData(Vue) {
Vue.prototype._$s = setData;
Vue.prototype._$i = setIfData;
Vue.prototype._$f = setForData;
Vue.prototype._$e = setElseIfData;
Vue.prototype._$setData = function setData (type, data) {
Vue.prototype._$setData = function setData(type, data) {
this._$vd.push(type, this._$id, data);
};
Vue.prototype._$mounted = function mounted() {
if (!this._$vd) {
return
}
diff(this._$newData, this._$data, this._$vdMountedData);
this._$data = JSON.parse(JSON.stringify(this._$newData));
console.log(`[${this._$id}] mounted ` + Date.now());
if (this.mpType === 'page') {
// 页面 mounted 之后,第一次同步数据
this._$vd.flush();
}
};
Vue.prototype._$updated = function updated() {
if (!this._$vd) {
return
}
diff(this._$newData, this._$data, this._$vdUpdatedData);
this._$data = JSON.parse(JSON.stringify(this._$newData));
console.log(`[${this._$id}] updated ` + Date.now());
this._$vd.initialized && this.$nextTick(this._$vd.flush.bind(this._$vd));
};
Object.defineProperty(Vue.prototype, '_$vd', {
get () {
get() {
return this.$root._$vdomSync
}
});
Vue.mixin({
beforeCreate () {
beforeCreate() {
if (this.$options.mpType) {
this.mpType = this.$options.mpType;
}
......@@ -9090,52 +9150,34 @@ var serviceContext = (function () {
if (this._$vd) {
this._$id = guid();
this._$vd.addVm(this);
this._$vdMountedData = Object.create(null);
this._$setData(MOUNTED_DATA, this._$vdMountedData);
console.log(`[${this._$id}] beforeCreate ` + Date.now());
// 目前全量采集做 diff(iOS 需要保留全量状态做 restore),理论上可以差量采集
this._$data = Object.create(null);
this._$newData = Object.create(null);
}
},
mounted () {
if (!this._$vd) {
return
}
const diffData = diff(this._$newData, this._$data);
this._$data = JSON.parse(JSON.stringify(this._$newData));
console.log(`[${this._$id}] mounted ` + Date.now());
this._$setData(MOUNTED_DATA, diffData);
if (this.mpType === 'page') {
// 页面 mounted 之后,第一次同步数据
this._$vd.flush();
}
},
beforeUpdate () {
beforeUpdate() {
if (!this._$vd) {
return
}
this._$vdUpdatedData = Object.create(null);
this._$setData(UPDATED_DATA, this._$vdUpdatedData);
console.log(`[${this._$id}] beforeUpdate ` + Date.now());
this._$newData = Object.create(null);
},
updated () {
if (!this._$vd) {
return
}
const diffData = diff(this._$newData, this._$data);
this._$data = JSON.parse(JSON.stringify(this._$newData));
console.log(`[${this._$id}] updated ` + Date.now());
this._$setData(UPDATED_DATA, diffData);
},
beforeDestroy () {
beforeDestroy() {
if (!this._$vd) {
return
}
this._$vd.removeVm(this);
this._$vdomSync && this._$vdomSync.destory();
this._$vdomSync && this._$vdomSync.destroy();
}
});
}
function setData (id, name, value) {
function setData(id, name, value) {
const diffData = this._$newData[id] || (this._$newData[id] = {});
if (typeof name !== 'string') {
......@@ -9151,14 +9193,19 @@ var serviceContext = (function () {
return (diffData[name] = value)
}
function setForData (id, value) {
function setForData(id, value) {
const diffData = this._$newData[id] || (this._$newData[id] = {});
const vForData = diffData['v-for'] || (diffData['v-for'] = []);
if (value.forItems) {
return value.forItems
}
const {
forIndex,
key
} = value;
const diffData = this._$newData[id] || (this._$newData[id] = {});
const vForData = diffData['v-for'] || (diffData['v-for'] = []);
if (!hasOwn(value, 'keyIndex')) {
vForData[forIndex] = key;
} else {
......@@ -9167,11 +9214,11 @@ var serviceContext = (function () {
return key
}
function setIfData (id, value) {
function setIfData(id, value) {
return ((this._$newData[id] || (this._$newData[id] = {}))['v-if'] = value)
}
function setElseIfData (id, value) {
function setElseIfData(id, value) {
return ((this._$newData[id] || (this._$newData[id] = {}))['v-else-if'] = value)
}
......@@ -9233,12 +9280,42 @@ var serviceContext = (function () {
});
}
function initLifecycle (Vue) {
lifecycleMixin(Vue);
Vue.mixin({
beforeCreate () {
if (this.mpType === 'page') {
this.$scope = this.$options.pageInstance;
this.$scope.$vm = this;
delete this.$options.pageInstance;
}
},
created () {
if (this.mpType === 'page') {
callPageHook(this.$scope, 'onLoad', this.$options.pageQuery);
callPageHook(this.$scope, 'onShow');
}
},
beforeDestroy () {
if (this.mpType === 'page') {
callPageHook(this.$scope, 'onUnload');
}
},
mounted () {
if (this.mpType === 'page') {
callPageHook(this.$scope, 'onReady');
}
}
});
}
var vuePlugin = {
install (Vue, options) {
initVue(Vue);
initData(Vue);
lifecycleMixin(Vue);
initLifecycle(Vue);
const oldMount = Vue.prototype.$mount;
Vue.prototype.$mount = function mount (el, hydrating) {
......
......@@ -2619,20 +2619,21 @@ function renderList (
if (Array.isArray(val) || typeof val === 'string') {
ret = new Array(val.length);
for (i = 0, l = val.length; i < l; i++) {
ret[i] = render(val[i], i);
ret[i] = render(val[i], i, i, i);
}
} else if (typeof val === 'number') {
ret = new Array(val);
for (i = 0; i < val; i++) {
ret[i] = render(i + 1, i);
ret[i] = render(i + 1, i, i, i);
}
} else if (isObject(val)) {
if (hasSymbol && val[Symbol.iterator]) {
ret = [];
var iterator = val[Symbol.iterator]();
var result = iterator.next();
i = 0;
while (!result.done) {
ret.push(render(result.value, ret.length));
ret.push(render(result.value, ret.length, i++, i));
result = iterator.next();
}
} else {
......@@ -2640,7 +2641,7 @@ function renderList (
ret = new Array(keys.length);
for (i = 0, l = keys.length; i < l; i++) {
key = keys[i];
ret[i] = render(val[key], key, i);
ret[i] = render(val[key], key, i, i);
}
}
}
......@@ -3127,9 +3128,14 @@ var componentVNodeHooks = {
var context = vnode.context;
var componentInstance = vnode.componentInstance;
if (!componentInstance._isMounted) {
// fixed by xxxxxx
componentInstance._isMounted = true;
if (componentInstance._$vd) {// 延迟 mounted
componentInstance._$vd.addMountedVm(componentInstance);
} else {
callHook(componentInstance, 'mounted');
}
}
if (vnode.data.keepAlive) {
if (context._isMounted) {
// vue-router#1212
......@@ -4074,9 +4080,14 @@ function mountComponent (
// manually mounted instance, call mounted on self
// mounted is called for render-created child components in its inserted hook
if (vm.$vnode == null) {
// fixed by xxxxxx
vm._isMounted = true;
if (vm._$vd) {// 延迟 mounted 事件
vm._$vd.addMountedVm(vm);
} else {
callHook(vm, 'mounted');
}
}
return vm
}
......@@ -4340,9 +4351,14 @@ function callUpdatedHooks (queue) {
var watcher = queue[i];
var vm = watcher.vm;
if (vm._watcher === watcher && vm._isMounted && !vm._isDestroyed) {
// fixed by xxxxx
if (vm._$vd) { // 延迟 updated 事件
vm._$vd.addUpdatedVm(vm);
}else{
callHook(vm, 'updated');
}
}
}
}
/**
......@@ -6692,17 +6708,33 @@ function normalizeStyleBinding (bindingStyle) {
}
function updateExtras(oldVnode, vnode) {
if (isUndef(vnode.data.extras) && isUndef(vnode.data.attrs)) {
var attrs = vnode.data.attrs;
var extras = vnode.data.extras;
var isExtrasUndef = isUndef(extras);
if (isExtrasUndef && isUndef(attrs)) {
return
}
var elm = vnode.elm;
var context = vnode.context;
var attrs = vnode.data.attrs;
var extras = vnode.data.extras;
var id = attrs['_i'];
// 存储事件标记
elm.setAttribute('nid', String(id));
elm.setAttribute('cid', context._$id);
if (
(
isExtrasUndef ||
Object.keys(extras).length === 0
) &&
Object.keys(attrs).length === 1
) {
return
}
var $s = vnode.context._$s.bind(vnode.context);
if (extras) {
......@@ -6722,9 +6754,7 @@ function updateExtras(oldVnode, vnode) {
key$1 !== '_i' && $s(id, 'a-' + key$1, attrs[key$1]);
}
}
// 存储事件标记
elm.setAttribute('nid', String(id));
elm.setAttribute('cid', context._$id);
}
......
......@@ -2627,20 +2627,21 @@ function renderList (
if (Array.isArray(val) || typeof val === 'string') {
ret = new Array(val.length);
for (i = 0, l = val.length; i < l; i++) {
ret[i] = render(val[i], i);
ret[i] = render(val[i], i, i, i);
}
} else if (typeof val === 'number') {
ret = new Array(val);
for (i = 0; i < val; i++) {
ret[i] = render(i + 1, i);
ret[i] = render(i + 1, i, i, i);
}
} else if (isObject(val)) {
if (hasSymbol && val[Symbol.iterator]) {
ret = [];
var iterator = val[Symbol.iterator]();
var result = iterator.next();
i = 0;
while (!result.done) {
ret.push(render(result.value, ret.length));
ret.push(render(result.value, ret.length, i++, i));
result = iterator.next();
}
} else {
......@@ -2648,7 +2649,7 @@ function renderList (
ret = new Array(keys.length);
for (i = 0, l = keys.length; i < l; i++) {
key = keys[i];
ret[i] = render(val[key], key, i);
ret[i] = render(val[key], key, i, i);
}
}
}
......
......@@ -12,6 +12,20 @@ function assertCodegen (template, generatedCode, ...args) {
/* eslint-disable quotes */
describe('codegen', () => {
it('generate block', () => {
assertCodegen(
'<block v-if="show"></block>',
`with(this){return (_$i(0,show))?void 0:_e()}`
)
assertCodegen(
'<div><block v-for="item in items"><div></div><div></div></block></div>',
`with(this){return _c('div',{attrs:{"_i":0}},[_l((_$f(1,{forItems:items})),function(item,$10,$20,$30){return [_c('div',{key:_$f(1,{forIndex:$20,keyIndex:0,key:1+'-0-'+$30}),attrs:{"_i":("2-"+$30)}}),_c('div',{key:_$f(1,{forIndex:$20,keyIndex:1,key:1+'-1-'+$30}),attrs:{"_i":("3-"+$30)}})]})],2)}`
)
assertCodegen(
'<div><block v-for="item in items" :key="item.id"><div></div><div></div></block></div>',
`with(this){return _c('div',{attrs:{"_i":0}},[_l((_$f(1,{forItems:items})),function(item,$10,$20,$30){return [_c('div',{key:_$f(1,{forIndex:$20,keyIndex:0,key:item.id+'_0'}),attrs:{"_i":("2-"+$30)}}),_c('div',{key:_$f(1,{forIndex:$20,keyIndex:1,key:item.id+'_1'}),attrs:{"_i":("3-"+$30)}})]})],2)}`
)
})
it('generate directive', () => {
assertCodegen(
'<p v-custom1:[arg1].modifier="value1" v-custom2></p>',
......@@ -21,23 +35,27 @@ describe('codegen', () => {
it('generate v-for directive', () => {
assertCodegen(
'<div><template v-for="item in items"><div></div><div></div></template></div>',
`with(this){return _c('div',{attrs:{"_i":0}},[_l((items),function(item,$i){return [_c('div',{key:_$f(1,{forIndex:$i,keyIndex:0,key:'1-0-'+$i}),attrs:{"_i":("2-"+$i)}}),_c('div',{key:_$f(1,{forIndex:$i,keyIndex:1,key:'1-1-'+$i}),attrs:{"_i":("3-"+$i)}})]})],2)}`
`with(this){return _c('div',{attrs:{"_i":0}},[_l((_$f(1,{forItems:items})),function(item,$10,$20,$30){return [_c('div',{key:_$f(1,{forIndex:$20,keyIndex:0,key:1+'-0-'+$30}),attrs:{"_i":("2-"+$30)}}),_c('div',{key:_$f(1,{forIndex:$20,keyIndex:1,key:1+'-1-'+$30}),attrs:{"_i":("3-"+$30)}})]})],2)}`
)
assertCodegen(
'<div><template v-for="item in items">text</template></div>',
`with(this){return _c('div',{attrs:{"_i":0}},[_l((items),function(item,$i){return [_c('text',{key:_$f(1,{forIndex:$i,keyIndex:0,key:'1-0-'+$i}),attrs:{"_i":("1-"+$i)}})]})],2)}`
`with(this){return _c('div',{attrs:{"_i":0}},[_l((_$f(1,{forItems:items})),function(item,$10,$20,$30){return [_c('text',{key:_$f(1,{forIndex:$20,keyIndex:0,key:1+'-0-'+$30}),attrs:{"_i":("1-"+$30)}})]})],2)}`
)
assertCodegen(
'<div><template v-for="item in items">{{text}}</template></div>',
`with(this){return _c('div',{attrs:{"_i":0}},[_l((items),function(item,$i){return [_c('text',{key:_$f(1,{forIndex:$i,keyIndex:0,key:'1-0-'+$i}),extras:{t0:_s(text)},attrs:{"_i":("1-"+$i)}})]})],2)}`
`with(this){return _c('div',{attrs:{"_i":0}},[_l((_$f(1,{forItems:items})),function(item,$i){return [_c('text',{key:_$f(1,{forIndex:$i,keyIndex:0,key:'1-0-'+$i}),extras:{t0:_s(text)},attrs:{"_i":("1-"+$i)}})]})],2)}`
)
assertCodegen(
'<div><template v-for="item in items"><span></span>{{text}}</template></div>',
`with(this){return _c('div',{attrs:{"_i":0}},[_l((items),function(item,$i){return [_c('span',{key:_$f(1,{forIndex:$i,keyIndex:0,key:'1-0-'+$i}),attrs:{"_i":("2-"+$i)}}),_c('text',{extras:{t0:_s(text)},attrs:{"_i":("1-"+$i)}})]})],2)}`
`with(this){return _c('div',{attrs:{"_i":0}},[_l((_$f(1,{forItems:items})),function(item,$i){return [_c('span',{key:_$f(1,{forIndex:$i,keyIndex:0,key:'1-0-'+$i}),attrs:{"_i":("2-"+$i)}}),_c('text',{extras:{t0:_s(text)},attrs:{"_i":("1-"+$i)}})]})],2)}`
)
assertCodegen(
'<div><template v-for="item in items">a {{text1}} b {{text2}}</template></div>',
`with(this){return _c('div',{attrs:{"_i":0}},[_l((items),function(item,$i){return [_c('text',{key:_$f(1,{forIndex:$i,keyIndex:0,key:'1-0-'+$i}),extras:{t0:_s(text1),t1:_s(text2)},attrs:{"_i":("1-"+$i)}})]})],2)}`
`with(this){return _c('div',{attrs:{"_i":0}},[_l((_$f(1,{forItems:items})),function(item,$i){return [_c('text',{key:_$f(1,{forIndex:$i,keyIndex:0,key:'1-0-'+$i}),extras:{t0:_s(text1),t1:_s(text2)},attrs:{"_i":("1-"+$i)}})]})],2)}`
)
assertCodegen(
'<div><template v-for="item in items"><span v-if="item.sub"></span></template></div>',
`with(this){return _c('div',{attrs:{"_i":0}},[_l((_$f(1,{forItems:items})),function(item,$i){return [(_$i(("2-"+$i),item.sub))?_c('span',{key:_$f(1,{forIndex:$i,keyIndex:0,key:'1-0-'+$i}),attrs:{"_i":("2-"+$i)}}):_e()]})],2)}`
)
})
it('generate text with multiple statements', () => {
......
......@@ -23,6 +23,10 @@ describe('codegen', () => {
'<div><template v-for="item in items"><div></div><div></div></template></div>',
`with(this){return _c('v-uni-view',{attrs:{"_i":0}},[_l(($r['1']['v-for']),function(item,$i){return [_c('v-uni-view',{key:item['k0'],attrs:{"_i":("2-"+$i)}}),_c('v-uni-view',{key:item['k1'],attrs:{"_i":("3-"+$i)}})]})],2)}`
)
assertCodegen(
'<div><template v-for="item in items"><span v-if="item.sub"></span></template></div>',
`with(this){return _c('v-uni-view',{attrs:{"_i":0}},[_l(($r['1']['v-for']),function(item,$i){return [($r[("2-"+$i)]['v-if'])?_c('v-uni-label',{key:item['k0'],attrs:{"_i":("2-"+$i)}}):_e()]})],2)}`
)
})
it('generate events with multiple statements', () => {
assertCodegen(
......
......@@ -41,30 +41,30 @@ describe('codegen', () => {
it('generate v-for directive', () => {
assertCodegen(
'<div><li v-for="item in items" :key="item.uid"></li></div>',
`with(this){return _c('div',{attrs:{"_i":0}},_l((items),function(item,$i){return _c('li',{key:_$f(1,{forIndex:$i,key:item.uid}),attrs:{"_i":("1-"+$i)}})}),0)}`
`with(this){return _c('div',{attrs:{"_i":0}},_l((_$f(1,{forItems:items})),function(item,$10,$20,$30){return _c('li',{key:_$f(1,{forIndex:$20,key:item.uid}),attrs:{"_i":("1-"+$30)}})}),0)}`
)
// iterator syntax
assertCodegen(
'<div><li v-for="(item, i) in items"></li></div>',
`with(this){return _c('div',{attrs:{"_i":0}},_l((items),function(item,i){return _c('li',{key:_$f(1,{forIndex:i,key:'1-'+i}),attrs:{"_i":("1-"+i)}})}),0)}`
`with(this){return _c('div',{attrs:{"_i":0}},_l((_$f(1,{forItems:items})),function(item,i,$20,$30){return _c('li',{key:_$f(1,{forIndex:$20,key:1+'-'+$30}),attrs:{"_i":("1-"+$30)}})}),0)}`
)
assertCodegen(
'<div><li v-for="(item, key, index) in items"></li></div>',
`with(this){return _c('div',{attrs:{"_i":0}},_l((items),function(item,key,index){return _c('li',{key:_$f(1,{forIndex:index,key:'1-'+index}),attrs:{"_i":("1-"+index)}})}),0)}`
`with(this){return _c('div',{attrs:{"_i":0}},_l((_$f(1,{forItems:items})),function(item,key,index,$30){return _c('li',{key:_$f(1,{forIndex:index,key:1+'-'+$30}),attrs:{"_i":("1-"+$30)}})}),0)}`
)
// destructuring
assertCodegen(
'<div><li v-for="{ a, b } in items"></li></div>',
`with(this){return _c('div',{attrs:{"_i":0}},_l((items),function({ a, b },$i){return _c('li',{key:_$f(1,{forIndex:$i,key:'1-'+$i}),attrs:{"_i":("1-"+$i)}})}),0)}`
`with(this){return _c('div',{attrs:{"_i":0}},_l((_$f(1,{forItems:items})),function({ a, b },$10,$20,$30){return _c('li',{key:_$f(1,{forIndex:$20,key:1+'-'+$30}),attrs:{"_i":("1-"+$30)}})}),0)}`
)
assertCodegen(
'<div><li v-for="({ a, b }, key, index) in items"></li></div>',
`with(this){return _c('div',{attrs:{"_i":0}},_l((items),function({ a, b },key,index){return _c('li',{key:_$f(1,{forIndex:index,key:'1-'+index}),attrs:{"_i":("1-"+index)}})}),0)}`
`with(this){return _c('div',{attrs:{"_i":0}},_l((_$f(1,{forItems:items})),function({ a, b },key,index,$30){return _c('li',{key:_$f(1,{forIndex:index,key:1+'-'+$30}),attrs:{"_i":("1-"+$30)}})}),0)}`
)
// v-for with extra element
assertCodegen(
'<div><p></p><li v-for="item in items"></li></div>',
`with(this){return _c('div',{attrs:{"_i":0}},[_c('p',{attrs:{"_i":1}}),_l((items),function(item,$i){return _c('li',{key:_$f(2,{forIndex:$i,key:'2-'+$i}),attrs:{"_i":("2-"+$i)}})})],2)}`
`with(this){return _c('div',{attrs:{"_i":0}},[_c('p',{attrs:{"_i":1}}),_l((_$f(2,{forItems:items})),function(item,$10,$20,$30){return _c('li',{key:_$f(2,{forIndex:$20,key:2+'-'+$30}),attrs:{"_i":("2-"+$30)}})})],2)}`
)
})
......@@ -113,7 +113,7 @@ describe('codegen', () => {
it('generate ref on v-for', () => {
assertCodegen(
'<ul><li v-for="item in items" ref="component1"></li></ul>',
`with(this){return _c('ul',{attrs:{"_i":0}},_l((items),function(item,$i){return _c('li',{key:_$f(1,{forIndex:$i,key:'1-'+$i}),ref:"component1",refInFor:true,attrs:{"_i":("1-"+$i)}})}),0)}`
`with(this){return _c('ul',{attrs:{"_i":0}},_l((_$f(1,{forItems:items})),function(item,$10,$20,$30){return _c('li',{key:_$f(1,{forIndex:$20,key:1+'-'+$30}),ref:"component1",refInFor:true,attrs:{"_i":("1-"+$30)}})}),0)}`
)
})
......@@ -625,7 +625,7 @@ describe('codegen', () => {
// normalize type: 2
assertCodegen(
'<div><child></child><template v-for="item in list">{{ item }}</template></div>',
`with(this){return _c('div',{attrs:{"_i":0}},[_c('child',{attrs:{"_i":1}}),_l((list),function(item,$i){return [_c('text',{key:_$f(2,{forIndex:$i,keyIndex:0,key:'2-0-'+$i}),extras:{t0:_s(item)},attrs:{"_i":("2-"+$i)}})]})],2)}`
`with(this){return _c('div',{attrs:{"_i":0}},[_c('child',{attrs:{"_i":1}}),_l((_$f(2,{forItems:list})),function(item,$i){return [_c('text',{key:_$f(2,{forIndex:$i,keyIndex:0,key:'2-0-'+$i}),extras:{t0:_s(item)},attrs:{"_i":("2-"+$i)}})]})],2)}`
)
})
......
......@@ -41,7 +41,7 @@ describe('codegen', () => {
it('generate v-for directive', () => {
assertCodegen(
'<div><li v-for="item in items" :key="item.uid"></li></div>',
`with(this){return _c('v-uni-view',{attrs:{"_i":0}},_l(($r['1']['v-for']),function(item,$i){return _c('v-uni-view',{key:item,attrs:{"_i":("1-"+$i)}})}),1)}`
`with(this){return _c('v-uni-view',{attrs:{"_i":0}},_l(($r['1']['v-for']),function(item,$10,$20,$30){return _c('v-uni-view',{key:item,attrs:{"_i":("1-"+$30)}})}),0)}`
)
// iterator syntax
assertCodegen(
......@@ -272,7 +272,7 @@ describe('codegen', () => {
// input + value
assertCodegen(
'<input :value="msg">',
`with(this){return _c('v-uni-input',{attrs:{"_i":0},domProps:{"value":$r['0']['a-value']}})}`
`with(this){return _c('v-uni-input',{attrs:{"value":$r['0']['a-value'],"_i":0}})}`
)
// non input
assertCodegen(
......
const compiler = require('../lib')
const res = compiler.compile(
`
<p slot="one">{{hello}}</p>
<div>
<view v-for="(item, index) in list" :key="index">
<view ref="add" class="warp" @change="change">
<view v-for="(sub, key) in item.data">
</view>
</view>
</view>
</div>
`, {
resourcePath: '/User/fxy/Documents/test.wxml',
isReservedTag: function (tag) {
......@@ -13,7 +20,7 @@ const res = compiler.compile(
mp: {
platform: 'app-plus'
},
// service: true
// service: true,
view: true
})
console.log(require('util').inspect(res, {
......
module.exports = function parseBlock (el) {
if (el.tag === 'block') {
el.tag = 'template'
const vForKey = el.key
if (vForKey) {
delete el.key
el.children.forEach((childEl, index) => {
const childVForKey = childEl.key
if (childVForKey) {
childEl.key = `${childVForKey}+'_'+${vForKey}+'_${index}'`
} else {
childEl.key = `${vForKey}+'_${index}'`
}
})
}
}
}
const {
ID,
hasOwn
} = require('./util')
} = require('../util')
const tags = require('../../../uni-cli-shared/lib/tags')
const {
getTagName
} = require('../h5')
const tags = require('../../../../uni-cli-shared/lib/tags')
// 仅限 view 层
module.exports = function parseComponent (el) {
// TODO 需要把自定义组件的 attrs, props 全干掉
el.tag = getTagName(el.tag)
if (!hasOwn(tags, el.tag)) {
// 需要把自定义组件的 attrs, props 全干掉
if (el.tag && !hasOwn(tags, el.tag.replace('v-uni-', ''))) {
// 仅保留 ID
el.attrs = el.attrs.filter(attr => attr.name === ID)
}
......
const {
hasOwn
} = require('./util')
} = require('../util')
const {
getTagName
} = require('../../h5')
const tags = require('../../../../uni-cli-shared/lib/tags')
const tags = require('../../../uni-cli-shared/lib/tags')
// 仅限 view 层
module.exports = function parseTag (el) {
el.tag = getTagName(el.tag)
if (el.tag.indexOf('v-uni-') !== 0 && hasOwn(tags, el.tag)) {
el.tag = 'v-uni-' + el.tag
}
......
......@@ -4,19 +4,23 @@ const {
isVar,
getForEl,
processForKey,
updateForEleId
updateForEleId,
traverseNode
} = require('./util')
const {
isComponent
} = require('../util')
const parseText = require('./text-parser')
const parseEvent = require('./event-parser')
const parseText = require('./parser/text-parser')
const parseEvent = require('./parser/event-parser')
const parseBlock = require('./parser/block-parser')
const preTransformNode = require('./pre-transform-node')
function genData (el) {
delete el.$parentIterator3
const {
events,
dynamicClass,
......@@ -130,14 +134,6 @@ function processIfConditions (el) {
})
el.if = `_$i(${el.attrsMap[ID]},${el.if})`
}
el.children && el.children.forEach(child => {
processIfConditions(child)
})
el.scopedSlots && Object.values(el.scopedSlots).forEach(child => {
processIfConditions(child)
})
}
function removeStatic (el) {
......@@ -162,8 +158,10 @@ function processKey (el) {
if (processForKey(el)) {
el = el.children[0] // 当 template 下仅文本时,处理第一个动态文本
}
if (el.key) { // renderList key
if (el.key && (
el.key.indexOf('_$f') !== 0 &&
el.key.indexOf('_$s') !== 0
)) { // renderList key
const forEl = getForEl(el)
if (forEl) {
if (!isVar(forEl.for)) {
......@@ -184,8 +182,7 @@ function processKey (el) {
}
function processIf (el) {
// 因为时机问题,在最后处理根节点时,遍历处理 ifConditions
!el.parent && processIfConditions(el)
processIfConditions(el)
}
function processDirs (el) {
......@@ -226,7 +223,8 @@ function processDynamicText (el, state) {
el.hasBindings = true
if (el.text) {
const ret = parseText(el.text, false, state)
// fixed by xxxxxx 注意:保持平台一致性,trim 一下
const ret = parseText(el.text.trim(), false, state)
if (ret && ret.dynamicTexts.length) {
el.dynamicTexts = ret.dynamicTexts
}
......@@ -274,7 +272,14 @@ function processAttrs (el) {
}
}
function postTransformNode (el) {
function processFor (el) {
if (el.for && isVar(el.for)) {
el.for = `_$f(${el.forId},{forItems:${el.for}})`
}
}
function transformNode (el, parent, state) {
parseBlock(el)
parseEvent(el)
removeStatic(el)
......@@ -283,13 +288,22 @@ function postTransformNode (el) {
processAttrs(el)
processText(el)
updateForEleId(el)
updateForEleId(el, state)
processFor(el)
processKey(el)
processIf(el)
processDirs(el)
}
function postTransformNode (el) {
if (!el.parent) { // 从根节点开始递归处理
traverseNode(el, false, {
forIteratorId: 0,
transformNode
})
}
}
module.exports = {
preTransformNode,
postTransformNode,
......
......@@ -2,8 +2,10 @@ const VARS = ['true', 'false', 'null']
const NUMBER_RE = /^-?\d*(\.\d+)?$/
const ID = '_i'
const ITERATOR = '$i'
const DATA_ROOT = '$r'
const ITERATOR1 = '$1'
const ITERATOR2 = '$2'
const ITERATOR3 = '$3'
const DATA_ROOT = '_$g'
function isVar (str) {
if (!str) {
......@@ -29,7 +31,7 @@ function addAttr (el, name, value) {
})
}
function updateEleId (el, it) {
function updateEleId (el, it, state) {
if (el.type !== 1) {
return
}
......@@ -39,7 +41,12 @@ function updateEleId (el, it) {
const attr = el.attrs.find(attr => attr.name === ID)
attr.value = newId
el.children.forEach(child => {
if (!child.for) { // 忽略嵌套 for
updateEleId(child, it)
} else {
child.$parentIterator3 = (child.$parentIterator3 ? (child.$parentIterator3 + '+') : '') + it
child.forId = `${child.forId}+'-'+${it}`
}
})
}
......@@ -63,12 +70,28 @@ function getAndRemoveAttr (el, name) {
return val
}
function updateForEleId (el) {
if (el.for) {
function updateForIterator (el, state) {
if (!el.for) {
return
}
// 简单处理,确保所有 for 循环,均包含 1,2,3
const forIteratorId = state.forIteratorId++
if (!el.iterator1) {
el.iterator1 = ITERATOR
el.iterator1 = ITERATOR1 + forIteratorId
}
if (!el.iterator2) {
el.iterator2 = ITERATOR2 + forIteratorId
}
updateEleId(el, el.iterator2 || el.iterator1)
if (!el.iterator3) {
el.iterator3 = ITERATOR3 + forIteratorId
}
}
function updateForEleId (el, state) {
updateForIterator(el, state)
if (el.for) {
const it = el.$parentIterator3 ? (el.$parentIterator3 + '+' + el.iterator3) : el.iterator3
updateEleId(el, it, state)
}
}
......@@ -76,30 +99,30 @@ function getForEl (el) {
if (el.for) {
return el
}
if (el.parent && el.parent.for && el.parent.tag === 'template') {
if (el.parent && el.parent.for && (el.parent.tag === 'template' || el.parent.tag === 'block')) {
return el.parent
}
}
function processForKey (el) {
const forEl = getForEl(el)
if (forEl && !el.key) {
if (forEl && !el.key && !el.dynamicTexts) { // 占位的 text 标签也无需添加 key
if (!isVar(forEl.for)) { // <view v-for="10"></view>
return
}
const it = forEl.iterator2 || forEl.iterator1 || ITERATOR
if (forEl.tag === 'template') {
const it = forEl.iterator3
if (forEl.tag === 'template' || forEl.tag === 'block') {
if (forEl !== el) {
const keyIndex = forEl.children.indexOf(el)
el.key = `'${forEl.forId}-${keyIndex}-'+${it}`
el.key = `${forEl.forId}+'-${keyIndex}'+${it}`
} else { // 当 template 下只有文本节点
if (el.children && el.children.length && !el.children.find(child => child.key)) {
el.children[0].key = `'${forEl.forId}-0-'+${it}`
el.children[0].key = `${forEl.forId}+'-0'+${it}`
return true
}
}
} else {
el.key = `'${forEl.forId}-'+${it}`
el.key = `${forEl.forId}+${it}`
}
}
}
......@@ -108,10 +131,18 @@ function hasOwn (obj, key) {
return hasOwnProperty.call(obj, key)
}
function traverseNode (el, parent, state) {
state.transformNode(el, parent, state)
el.children && el.children.forEach(child => traverseNode(child, el, state))
el.ifConditions && el.ifConditions.forEach((con, index) => {
index !== 0 && traverseNode(con.block, el, state)
})
el.scopedSlots && Object.values(el.scopedSlots).forEach(slot => traverseNode(slot, el, state))
}
module.exports = {
ID,
DATA_ROOT,
ITERATOR,
isVar,
hasOwn,
addAttr,
......@@ -119,5 +150,6 @@ module.exports = {
processForKey,
updateForEleId,
getBindingAttr,
getAndRemoveAttr
getAndRemoveAttr,
traverseNode
}
......@@ -4,22 +4,22 @@ const {
isVar,
getForEl,
updateForEleId,
processForKey
processForKey,
traverseNode
} = require('./util')
const parseTag = require('./tag-parser')
const parseText = require('./text-parser')
const parseEvent = require('./event-parser')
const parseComponent = require('./component-parser')
const parseTag = require('./parser/tag-parser')
const parseText = require('./parser/text-parser')
const parseEvent = require('./parser/event-parser')
const parseBlock = require('./parser/block-parser')
const parseComponent = require('./parser/component-parser')
const preTransformNode = require('./pre-transform-node')
const basePreTransformNode = require('./pre-transform-node')
function createGenVar (id) {
return function genVar (name, extra = '') {
if (/^\d+$/.test(id)) {
return `${DATA_ROOT}['${id}']['${name}']${extra}`
}
return `${DATA_ROOT}[${id}]['${name}']${extra}`
extra = extra ? (',' + extra) : ''
return `${DATA_ROOT}(${id},'${name}'${extra})`
}
}
......@@ -34,14 +34,6 @@ function processIfConditions (el) {
el.if = createGenVar(el.attrsMap[ID])('v-if')
}
el.children && el.children.forEach(child => {
processIfConditions(child)
})
el.scopedSlots && Object.values(el.scopedSlots).forEach(child => {
processIfConditions(child)
})
}
function processBinding (el, genVar) {
......@@ -63,14 +55,6 @@ function processFor (el, genVal) {
if (el.alias[0] === '{') {
el.alias = '$item'
}
// items 只有两种格式 [1,2,3],[{k0:'1-0',k1:'1-1'}]
// <div><li v-for="(item,key,index) in items"></li></div>
// =>
// <div><li v-for="(item,index) in items"></li></div>
if (el.iterator2) {
el.iterator1 = el.iterator2
delete el.iterator2
}
}
}
......@@ -97,8 +81,7 @@ function processKey (el) {
}
function processIf (el) {
// 因为时机问题,在最后处理根节点时,遍历处理 ifConditions
!el.parent && processIfConditions(el)
processIfConditions(el)
}
function processDirs (el, genVar) {
......@@ -128,12 +111,16 @@ function processText (el, parent) {
view: true,
genVar: createGenVar(parent.attrsMap[ID])
}
el.expression = parseText(el.text, false, state).expression
// fixed by xxxxxx 注意:保持平台一致性,trim 一下
el.expression = parseText(el.text.trim(), false, state).expression
}
function transformNode (el, parent) {
function transformNode (el, parent, state) {
parseBlock(el)
parseComponent(el)
parseEvent(el)
// 更新 id
updateForEleId(el)
updateForEleId(el, state)
if (el.type !== 1) {
return (el.type === 2 && processText(el, parent))
......@@ -151,20 +138,12 @@ function transformNode (el, parent) {
processProps(el, genVar)
}
function traverseNode (el, parent) {
transformNode(el, parent)
el.children && el.children.forEach(child => traverseNode(child, el))
el.scopedSlots && Object.values(el.scopedSlots).forEach(slot => traverseNode(slot, el))
}
function postTransformNode (el) {
// 需要提前处理的内容
parseComponent(el)
parseTag(el)
parseEvent(el)
if (!el.parent) { // 从根节点开始递归处理
traverseNode(el)
traverseNode(el, false, {
forIteratorId: 0,
transformNode
})
}
}
......@@ -207,6 +186,8 @@ function processEvents (events) {
}
function genData (el) {
delete el.$parentIterator3
if (el.model) {
el.model.callback = `function ($$v) {}`
}
......@@ -219,7 +200,10 @@ function genData (el) {
}
module.exports = {
preTransformNode,
preTransformNode: function (el, options) {
parseTag(el)
return basePreTransformNode(el, options)
},
postTransformNode,
genData
}
......@@ -8,7 +8,7 @@ const {
compileToFunctions,
ssrCompile,
ssrCompileToFunctions
} = require('vue-template-compiler')
} = require('../../vue-cli-plugin-uni/packages/vue-template-compiler')
const platforms = require('./platforms')
const traverseScript = require('./script/traverse')
......
......@@ -34,13 +34,11 @@ const v3 = {
// disable noEmitOnErrors
webpackConfig.optimization.noEmitOnErrors = false
const externals = {}
if (isAppService) { // service 层需要编译时注入 vue 内核
if (isAppService) {
webpackConfig.optimization.runtimeChunk = {
name: 'app-config'
}
} else if (isAppView) {
externals['vue'] = 'Vue'
webpackConfig.optimization.runtimeChunk = false
}
......@@ -48,6 +46,18 @@ const v3 = {
let devtool = false
const rules = []
if (isAppView) {
rules.push({ // 解析组件,css 等
resourceQuery: /vue&type=script/,
use: [{
loader: path.resolve(__dirname,
'../../packages/webpack-uni-app-loader/view/script')
}]
})
}
return {
devtool,
mode: process.env.NODE_ENV,
......@@ -84,7 +94,7 @@ const v3 = {
test: path.resolve(process.env.UNI_INPUT_DIR, getMainEntry()),
use: [{
loader: isAppService ? 'wrap-loader' : path.resolve(__dirname,
'../../packages/webpack-uni-view-main-loader'),
'../../packages/webpack-uni-app-loader/view/main.js'),
options: {
compiler: getPlatformCompiler(),
before: [
......@@ -92,7 +102,9 @@ const v3 = {
]
}
}]
}]
},
...rules
]
},
plugins: [
new webpack.ProvidePlugin(getProvides())
......@@ -114,9 +126,10 @@ const v3 = {
webpackConfig.module
.rule('vue')
.test([/\.vue$/, /\.nvue$/])
.use('vue-loader')// service 层移除 style 节点,view 层返回固定 script
.use('vue-loader') // service 层移除 style 节点,view 层返回固定 script
.loader(path.resolve(__dirname, '../../packages/vue-loader/lib'))
.tap(options => Object.assign(options, {
isAppService,
isAppView,
compiler: getPlatformCompiler(),
compilerOptions,
......@@ -132,6 +145,11 @@ const v3 = {
// .options({
// compiler: getPlatformCompiler()
// })
if (isAppView) {
if (process.env.NODE_ENV === 'production') {
require('../h5/cssnano-options')(webpackConfig)
}
}
webpackConfig.plugins.delete('hmr')
webpackConfig.plugins.delete('html')
......
const {
getPlatformCssnano
} = require('@dcloudio/uni-cli-shared')
module.exports = function initCssnanoOptions (webpackConfig) {
const module = webpackConfig.module
// TODO 临时 hack calc:false 看看 vue cli 后续是否开放 cssnano 的配置
const cssnanoOptions = {
sourceMap: false,
plugins: [require('cssnano')({
preset: ['default', getPlatformCssnano()]
})]
}
module.rule('css').oneOf('vue-modules').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('css').oneOf('vue').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('css').oneOf('normal-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('css').oneOf('normal').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('postcss').oneOf('vue-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('postcss').oneOf('vue').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('postcss').oneOf('normal-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('postcss').oneOf('normal').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('scss').oneOf('vue-modules').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('scss').oneOf('vue').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('scss').oneOf('normal-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('scss').oneOf('normal').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('sass').oneOf('vue-modules').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('sass').oneOf('vue').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('sass').oneOf('normal-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('sass').oneOf('normal').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('less').oneOf('vue-modules').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('less').oneOf('vue').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('less').oneOf('normal-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('less').oneOf('normal').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('stylus').oneOf('vue-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('stylus').oneOf('vue').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('stylus').oneOf('normal-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('stylus').oneOf('normal').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
}
......@@ -4,8 +4,7 @@ const path = require('path')
const {
getMainEntry,
getH5Options,
getPlatformCompiler,
getPlatformCssnano
getPlatformCompiler
} = require('@dcloudio/uni-cli-shared')
const WebpackHtmlAppendPlugin = require('../../packages/webpack-html-append-plugin')
......@@ -156,52 +155,7 @@ module.exports = {
.delete('cache-loader')
if (process.env.NODE_ENV === 'production') {
const module = webpackConfig.module
// TODO 临时 hack calc:false 看看 vue cli 后续是否开放 cssnano 的配置
const cssnanoOptions = {
sourceMap: false,
plugins: [require('cssnano')({
preset: ['default', getPlatformCssnano()]
})]
}
module.rule('css').oneOf('vue-modules').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('css').oneOf('vue').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('css').oneOf('normal-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('css').oneOf('normal').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('postcss').oneOf('vue-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('postcss').oneOf('vue').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('postcss').oneOf('normal-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('postcss').oneOf('normal').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('scss').oneOf('vue-modules').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('scss').oneOf('vue').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('scss').oneOf('normal-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('scss').oneOf('normal').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('sass').oneOf('vue-modules').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('sass').oneOf('vue').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('sass').oneOf('normal-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('sass').oneOf('normal').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('less').oneOf('vue-modules').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('less').oneOf('vue').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('less').oneOf('normal-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('less').oneOf('normal').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('stylus').oneOf('vue-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('stylus').oneOf('vue').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
module.rule('stylus').oneOf('normal-modules').use('cssnano').loader('postcss-loader').options(
cssnanoOptions)
module.rule('stylus').oneOf('normal').use('cssnano').loader('postcss-loader').options(cssnanoOptions)
require('./cssnano-options')(webpackConfig)
}
}
}
const path = require('path')
const loaderUtils = require('loader-utils')
module.exports = function(content) {
module.exports = function (content) {
this.cacheable && this.cacheable()
const vueLoaderOptions = this.loaders[0]
......
......@@ -25,7 +25,7 @@ if (process.env.UNI_USING_V3) {
return selectorParser(transformer).processSync(complexSelector)
}
const parseWord = function(node, opts) {
const parseWord = function (node, opts) {
const pair = unit(node.value)
if (pair) {
const num = Number(pair.number)
......@@ -51,13 +51,13 @@ if (process.env.UNI_USING_V3) {
}
}
const isInsideKeyframes = function(rule) {
const isInsideKeyframes = function (rule) {
return (
rule.parent && rule.parent.type === 'atrule' && /^(-\w+-)?keyframes$/.test(rule.parent.name)
)
}
const tranformValue = function(decl, opts) {
const tranformValue = function (decl, opts) {
return valueParser(decl.value)
.walk(node => {
if (node.type === 'word') {
......@@ -154,12 +154,12 @@ if (process.env.UNI_USING_V3) {
* 转换 upx
* 转换 px
*/
module.exports = postcss.plugin('postcss-uniapp-plugin', function(opts) {
module.exports = postcss.plugin('postcss-uniapp-plugin', function (opts) {
opts = {
...defaultOpts,
...opts
}
return function(root, result) {
return function (root, result) {
if (process.env.UNI_PLATFORM === 'h5') {
// Transform CSS AST here
......@@ -209,7 +209,7 @@ if (process.env.UNI_USING_V3) {
}
} else {
root.walkRules(rule => {
const selectors = transformSelector(rule.selectors.join(','), function(selectors) {
const selectors = transformSelector(rule.selectors.join(','), function (selectors) {
selectors.walkUniversals(node => {
node.parent.remove()
})
......@@ -240,8 +240,8 @@ if (process.env.UNI_USING_V3) {
const k = tag.value
const v = CSS_TAGS[k]
if (v) {
tag.value = v === 'r' ?
`._${k}` : v
tag.value = v === 'r'
? `._${k}` : v
}
})
})
......
......@@ -6,13 +6,13 @@ const TAGS = Object.keys(require('@dcloudio/uni-cli-shared').tags)
const transformSelector = (complexSelector, transformer) => {
return selectorParser(transformer).processSync(complexSelector)
}
const isInsideKeyframes = function(rule) {
const isInsideKeyframes = function (rule) {
return (
rule.parent && rule.parent.type === 'atrule' && /^(-\w+-)?keyframes$/.test(rule.parent.name)
)
}
module.exports = postcss.plugin('postcss-uniapp-plugin', function(opts) {
return function(root, result) {
module.exports = postcss.plugin('postcss-uniapp-plugin', function (opts) {
return function (root, result) {
root.walkRules(rule => {
// Transform each rule here
if (!isInsideKeyframes(rule)) {
......
......@@ -122,7 +122,7 @@ module.exports = function (source) {
// script
let scriptImport = `var script = {}`
if (descriptor.script) {
if (descriptor.script) {// fixed by xxxxxx view 层的 script 在 script-loader 中提取自定义组件信息
const src = descriptor.script.src || resourcePath
const attrsQuery = attrsToQuery(descriptor.script.attrs, 'js')
const query = `?vue&type=script${attrsQuery}${inheritQuery}`
......@@ -135,7 +135,7 @@ module.exports = function (source) {
// styles
let stylesCode = ``
if (options.isAppView && descriptor.styles.length) {
if (options.isAppView && descriptor.styles.length) {// fixed by xxxxxx 仅限 view 层
stylesCode = genStylesCode(
loaderContext,
descriptor.styles,
......
......@@ -255,8 +255,8 @@
/* */
var isUnaryTag = makeMap(
'area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +
var isUnaryTag = makeMap(// fixed by xxxxxx add image
'image,area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +
'link,meta,param,source,track,wbr'
);
......@@ -1036,7 +1036,13 @@
* directives subscribing to it.
*/
var Dep = function Dep () {
// fixed by xxxxxx (nvue vuex)
/* eslint-disable no-undef */
if(typeof SharedObject !== 'undefined'){
this.id = SharedObject.uid++;
} else {
this.id = uid++;
}
this.subs = [];
};
......@@ -1765,36 +1771,6 @@
/* */
function transformNode(el) {
var list = el.attrsList;
for (var i = list.length - 1; i >= 0; i--) {
var name = list[i].name;
if (name.indexOf(':change:') === 0 || name.indexOf('v-bind:change:') === 0) {
var nameArr = name.split(':');
var wxsProp = nameArr[nameArr.length - 1];
var wxsPropBinding = el.attrsMap[':' + wxsProp] || el.attrsMap['v-bind:' + wxsProp];
if (wxsPropBinding) {
(el.wxsPropBindings || (el.wxsPropBindings = {}))['change:' + wxsProp] = wxsPropBinding;
}
}
}
}
function genData(el) {
var data = '';
if (el.wxsPropBindings) {
data += "wxsProps:" + (JSON.stringify(el.wxsPropBindings)) + ",";
}
return data
}
var wxs = {
transformNode: transformNode,
genData: genData
};
/* */
var validDivisionCharRE = /[\w).+\-_$\]]/;
function parseFilters (exp) {
......@@ -2170,7 +2146,7 @@
/* */
function transformNode$1 (el, options) {
function transformNode (el, options) {
var warn = options.warn || baseWarn;
var staticClass = getAndRemoveAttr(el, 'class');
if (staticClass) {
......@@ -2194,7 +2170,7 @@
}
}
function genData$1 (el) {
function genData (el) {
var data = '';
if (el.staticClass) {
data += "staticClass:" + (el.staticClass) + ",";
......@@ -2207,8 +2183,8 @@
var klass = {
staticKeys: ['staticClass'],
transformNode: transformNode$1,
genData: genData$1
transformNode: transformNode,
genData: genData
};
/* */
......@@ -2228,7 +2204,7 @@
/* */
function transformNode$2 (el, options) {
function transformNode$1 (el, options) {
var warn = options.warn || baseWarn;
var staticStyle = getAndRemoveAttr(el, 'style');
if (staticStyle) {
......@@ -2254,7 +2230,7 @@
}
}
function genData$2 (el) {
function genData$1 (el) {
var data = '';
if (el.staticStyle) {
data += "staticStyle:" + (el.staticStyle) + ",";
......@@ -2267,8 +2243,8 @@
var style = {
staticKeys: ['staticStyle'],
transformNode: transformNode$2,
genData: genData$2
transformNode: transformNode$1,
genData: genData$1
};
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
......@@ -3783,6 +3759,36 @@
preTransformNode: preTransformNode
};
/* */
function transformNode$2(el) {
var list = el.attrsList;
for (var i = list.length - 1; i >= 0; i--) {
var name = list[i].name;
if (name.indexOf(':change:') === 0 || name.indexOf('v-bind:change:') === 0) {
var nameArr = name.split(':');
var wxsProp = nameArr[nameArr.length - 1];
var wxsPropBinding = el.attrsMap[':' + wxsProp] || el.attrsMap['v-bind:' + wxsProp];
if (wxsPropBinding) {
(el.wxsPropBindings || (el.wxsPropBindings = {}))['change:' + wxsProp] = wxsPropBinding;
}
}
}
}
function genData$2(el) {
var data = '';
if (el.wxsPropBindings) {
data += "wxsProps:" + (JSON.stringify(el.wxsPropBindings)) + ",";
}
return data
}
var wxs = {
transformNode: transformNode$2,
genData: genData$2
};
var modules = [
wxs,// fixed by xxxxxx
klass,
......@@ -4470,7 +4476,7 @@
var alias = el.alias;
var iterator1 = el.iterator1 ? ("," + (el.iterator1)) : '';
var iterator2 = el.iterator2 ? ("," + (el.iterator2)) : '';
var iterator3 = el.iterator3 ? ("," + (el.iterator3)) : ''; // fixed by xxxxxx
if (state.maybeComponent(el) &&
el.tag !== 'slot' &&
el.tag !== 'template' &&
......@@ -4487,7 +4493,7 @@
el.forProcessed = true; // avoid recursion
return (altHelper || '_l') + "((" + exp + ")," +
"function(" + alias + iterator1 + iterator2 + "){" +
"function(" + alias + iterator1 + iterator2 + iterator3 + "){" + // fixed by xxxxxx
"return " + ((altGen || genElement)(el, state)) +
'})'
}
......
......@@ -212,8 +212,8 @@ function genStaticKeys (modules) {
/* */
var isUnaryTag = makeMap(
'area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +
var isUnaryTag = makeMap(// fixed by xxxxxx add image
'image,area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +
'link,meta,param,source,track,wbr'
);
......@@ -994,7 +994,13 @@ var uid = 0;
* directives subscribing to it.
*/
var Dep = function Dep () {
// fixed by xxxxxx (nvue vuex)
/* eslint-disable no-undef */
if(typeof SharedObject !== 'undefined'){
this.id = SharedObject.uid++;
} else {
this.id = uid++;
}
this.subs = [];
};
......@@ -1730,36 +1736,6 @@ var isTextInputType = makeMap('text,number,password,search,email,tel,url');
/* */
function transformNode(el) {
var list = el.attrsList;
for (var i = list.length - 1; i >= 0; i--) {
var name = list[i].name;
if (name.indexOf(':change:') === 0 || name.indexOf('v-bind:change:') === 0) {
var nameArr = name.split(':');
var wxsProp = nameArr[nameArr.length - 1];
var wxsPropBinding = el.attrsMap[':' + wxsProp] || el.attrsMap['v-bind:' + wxsProp];
if (wxsPropBinding) {
(el.wxsPropBindings || (el.wxsPropBindings = {}))['change:' + wxsProp] = wxsPropBinding;
}
}
}
}
function genData(el) {
var data = '';
if (el.wxsPropBindings) {
data += "wxsProps:" + (JSON.stringify(el.wxsPropBindings)) + ",";
}
return data
}
var wxs = {
transformNode: transformNode,
genData: genData
};
/* */
var validDivisionCharRE = /[\w).+\-_$\]]/;
function parseFilters (exp) {
......@@ -2135,7 +2111,7 @@ function rangeSetItem (
/* */
function transformNode$1 (el, options) {
function transformNode (el, options) {
var warn = options.warn || baseWarn;
var staticClass = getAndRemoveAttr(el, 'class');
if (process.env.NODE_ENV !== 'production' && staticClass) {
......@@ -2159,7 +2135,7 @@ function transformNode$1 (el, options) {
}
}
function genData$1 (el) {
function genData (el) {
var data = '';
if (el.staticClass) {
data += "staticClass:" + (el.staticClass) + ",";
......@@ -2172,8 +2148,8 @@ function genData$1 (el) {
var klass = {
staticKeys: ['staticClass'],
transformNode: transformNode$1,
genData: genData$1
transformNode: transformNode,
genData: genData
};
/* */
......@@ -2193,7 +2169,7 @@ var parseStyleText = cached(function (cssText) {
/* */
function transformNode$2 (el, options) {
function transformNode$1 (el, options) {
var warn = options.warn || baseWarn;
var staticStyle = getAndRemoveAttr(el, 'style');
if (staticStyle) {
......@@ -2219,7 +2195,7 @@ function transformNode$2 (el, options) {
}
}
function genData$2 (el) {
function genData$1 (el) {
var data = '';
if (el.staticStyle) {
data += "staticStyle:" + (el.staticStyle) + ",";
......@@ -2232,8 +2208,8 @@ function genData$2 (el) {
var style = {
staticKeys: ['staticStyle'],
transformNode: transformNode$2,
genData: genData$2
transformNode: transformNode$1,
genData: genData$1
};
/* */
......@@ -3405,6 +3381,36 @@ var model = {
preTransformNode: preTransformNode
};
/* */
function transformNode$2(el) {
var list = el.attrsList;
for (var i = list.length - 1; i >= 0; i--) {
var name = list[i].name;
if (name.indexOf(':change:') === 0 || name.indexOf('v-bind:change:') === 0) {
var nameArr = name.split(':');
var wxsProp = nameArr[nameArr.length - 1];
var wxsPropBinding = el.attrsMap[':' + wxsProp] || el.attrsMap['v-bind:' + wxsProp];
if (wxsPropBinding) {
(el.wxsPropBindings || (el.wxsPropBindings = {}))['change:' + wxsProp] = wxsPropBinding;
}
}
}
}
function genData$2(el) {
var data = '';
if (el.wxsPropBindings) {
data += "wxsProps:" + (JSON.stringify(el.wxsPropBindings)) + ",";
}
return data
}
var wxs = {
transformNode: transformNode$2,
genData: genData$2
};
var modules = [
wxs,// fixed by xxxxxx
klass,
......@@ -4100,7 +4106,7 @@ function genFor (
var alias = el.alias;
var iterator1 = el.iterator1 ? ("," + (el.iterator1)) : '';
var iterator2 = el.iterator2 ? ("," + (el.iterator2)) : '';
var iterator3 = el.iterator3 ? ("," + (el.iterator3)) : ''; // fixed by xxxxxx
if (process.env.NODE_ENV !== 'production' &&
state.maybeComponent(el) &&
el.tag !== 'slot' &&
......@@ -4118,7 +4124,7 @@ function genFor (
el.forProcessed = true; // avoid recursion
return (altHelper || '_l') + "((" + exp + ")," +
"function(" + alias + iterator1 + iterator2 + "){" +
"function(" + alias + iterator1 + iterator2 + iterator3 + "){" + // fixed by xxxxxx
"return " + ((altGen || genElement)(el, state)) +
'})'
}
......
......@@ -14,8 +14,7 @@ const {
const FILTER_TAG = getPlatformFilterTag()
module.exports = function(source) {
module.exports = function (source) {
const loaderContext = this
const {
......@@ -38,11 +37,6 @@ module.exports = function(source) {
needMap: sourceMap
})
if (options.isAppService) { // 移除 styles
descriptor.styles.length = 0
return source
}
if (!descriptor.template || !FILTER_TAG) {
// delete customBlocks
descriptor.customBlocks.length = 0
......
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')
class WebpackHtmlAppendPlugin {
constructor(content) {
constructor (content) {
this.content = content || ''
}
apply(compiler) {
apply (compiler) {
compiler.hooks.compilation.tap('WebpackHtmlAppendPlugin', (compilation) => {
const beforeEmit = compilation.hooks.htmlWebpackPluginAfterHtmlProcessing ||
HtmlWebpackPlugin.getHooks(compilation).beforeEmit
......
......@@ -31,7 +31,7 @@ const TAGS = {
'css': 'style'
}
module.exports = function(content, map) {
module.exports = function (content, map) {
this.cacheable && this.cacheable()
let types = utils.getOptions(this).type || 'js'
......
......@@ -4,10 +4,9 @@ const isWin = /^win/.test(process.platform)
const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path)
module.exports = function(content) {
module.exports = function (content) {
this.cacheable && this.cacheable()
const resourcePath = normalizePath(this.resourcePath)
const inputPath = normalizePath(process.env.UNI_INPUT_DIR)
if (resourcePath !== normalizePath(path.resolve(process.env.UNI_INPUT_DIR, 'App.vue'))) {
return content.replace(/(<style\b[^><]*)>/ig, '$1 scoped>')
}
......
......@@ -3,8 +3,6 @@ const path = require('path')
const hash = require('hash-sum')
const loaderUtils = require('loader-utils')
const parser = require('@babel/parser')
const {
parse
} = require(require.resolve('@vue/component-compiler-utils', {
......@@ -13,29 +11,13 @@ const {
const traverse = require('@dcloudio/webpack-uni-mp-loader/lib/babel/global-component-traverse')
const genStylesCode = require('../vue-loader/lib/codegen/styleInjection')
const genStylesCode = require('../../vue-loader/lib/codegen/styleInjection')
function parseComponents(content) {
const {
state: {
components
}
} = traverse(parser.parse(content, {
sourceType: 'module',
plugins: [
'typescript',
['decorators', {
decoratorsBeforeExport: true
}],
'classProperties'
]
}), {
components: []
})
return components
}
const {
parseComponents
} = require('./util')
function getDefineComponents(components) {
function getDefineComponents (components) {
return components.map(({
name,
source
......@@ -44,7 +26,7 @@ function getDefineComponents(components) {
const appVueFilePath = path.resolve(process.env.UNI_INPUT_DIR, 'app.vue')
function getStylesCode(loaderContext) {
function getStylesCode (loaderContext) {
if (!fs.existsSync(appVueFilePath)) {
return
}
......@@ -89,9 +71,9 @@ function getStylesCode(loaderContext) {
const needsHotReload = false
const id = hash(
isProduction ?
(shortFilePath + '\n' + source) :
shortFilePath
isProduction
? (shortFilePath + '\n' + source)
: shortFilePath
)
stylesCode = genStylesCode(
......@@ -104,14 +86,14 @@ function getStylesCode(loaderContext) {
isServer || isShadow // needs explicit injection?
)
}
return stylesCode.replace(/main\.js/g,'App.vue')
return stylesCode.replace(/main\.js/g, 'App.vue')
}
module.exports = function(source, map) {
module.exports = function (source, map) {
// 解析自定义组件,及 App 样式
return `import 'uni-pages'
${getStylesCode(this)}
${getDefineComponents(parseComponents(source)).join('\n')}
${getDefineComponents(parseComponents(source, traverse)).join('\n')}
UniViewJSBridge.publishHandler('webviewReady')
`
}
const {
jsPreprocessOptions
} = require('@dcloudio/uni-cli-shared')
const preprocessor = require('@dcloudio/vue-cli-plugin-uni/packages/webpack-preprocess-loader/preprocess')
const traverse = require('@dcloudio/webpack-uni-mp-loader/lib/babel/scoped-component-traverse')
const {
parseComponents
} = require('./util')
function genComponentCode (components) {
const importCode = []
const componentsCode = []
components.forEach(({
name,
value,
source
}) => {
importCode.push(`import ${value} from '${source}'`)
componentsCode.push(`${name}: ${value}`)
})
return [importCode.join('\n'), componentsCode.join(',\n')]
}
function genCode (components, css = []) {
const [importComponentCode, componentsCode] = genComponentCode(components)
// TODO js 内引用 css
return `
${importComponentCode}
export default {
data(){
return {}
},
components:{
${componentsCode}
}
}
`
}
module.exports = function (content, map) {
this.cacheable && this.cacheable()
content = preprocessor.preprocess(content, jsPreprocessOptions.context, {
type: jsPreprocessOptions.type
})
return genCode(parseComponents(content, traverse))
}
const parser = require('@babel/parser')
function parseComponents (content, traverse) {
const {
state: {
components
}
} = traverse(parser.parse(content, {
sourceType: 'module',
plugins: [
'typescript',
['decorators', {
decoratorsBeforeExport: true
}],
'classProperties'
]
}), {
components: []
})
return components
}
module.exports = {
parseComponents
}
......@@ -7,7 +7,8 @@ const callbacks = {
pause: [],
resume: [],
start: [],
stop: []
stop: [],
error: []
}
class RecorderManager {
......
......@@ -8,3 +8,4 @@ export const APP_SERVICE_ID = '__uniapp__service'
export const WEBVIEW_READY = 'webviewReady'
export const WEBVIEW_UI_EVENT = 'webviewUIEvent'
export const VD_SYNC_CALLBACK = 'vdSyncCallback'
......@@ -12,7 +12,7 @@ export const getPageVueComponent = cached(function (pagePath) {
return pageFactory[pagePath]()
})
export function createPage (pagePath, pageId) {
export function createPage (pagePath, pageId, pageQuery, pageInstance) {
if (!pageFactory[pagePath]) {
console.error(`${pagePath} not found`)
}
......@@ -20,7 +20,9 @@ export function createPage (pagePath, pageId) {
const pageVm = new (getPageVueComponent(pagePath))({
mpType: 'page',
pageId,
pagePath
pagePath,
pageQuery,
pageInstance
})
if (process.env.NODE_ENV !== 'production') {
console.log(`new ${pagePath}`, Date.now() - startTime)
......
export function restoreGlobal(
export function restoreGlobal (
newWeex,
newPlus,
newSetTimeout,
......
......@@ -84,6 +84,9 @@ export function registerPage ({
const index = pages.findIndex(page => page === this)
if (index !== -1) {
pages.splice(index, 1)
if (!webview.nvue) {
this.$vm.$destroy()
}
if (process.env.NODE_ENV !== 'production') {
console.log(`[uni-app] removePage`, path, webview.id)
}
......@@ -115,9 +118,7 @@ export function registerPage ({
}
}, [pageId])
pageInstance.$vm = createPage(route, pageId)
pageInstance.$vm.$scope = pageInstance
pageInstance.$vm.$mount()
createPage(route, pageId, query, pageInstance).$mount()
}
}
......
......@@ -16,25 +16,47 @@ import {
diff
} from './diff'
export function initData (Vue) {
export function initData(Vue) {
Vue.prototype._$s = setData
Vue.prototype._$i = setIfData
Vue.prototype._$f = setForData
Vue.prototype._$e = setElseIfData
Vue.prototype._$setData = function setData (type, data) {
Vue.prototype._$setData = function setData(type, data) {
this._$vd.push(type, this._$id, data)
}
Vue.prototype._$mounted = function mounted() {
if (!this._$vd) {
return
}
diff(this._$newData, this._$data, this._$vdMountedData)
this._$data = JSON.parse(JSON.stringify(this._$newData))
console.log(`[${this._$id}] mounted ` + Date.now())
if (this.mpType === 'page') {
// 页面 mounted 之后,第一次同步数据
this._$vd.flush()
}
}
Vue.prototype._$updated = function updated() {
if (!this._$vd) {
return
}
diff(this._$newData, this._$data, this._$vdUpdatedData)
this._$data = JSON.parse(JSON.stringify(this._$newData))
console.log(`[${this._$id}] updated ` + Date.now())
this._$vd.initialized && this.$nextTick(this._$vd.flush.bind(this._$vd))
}
Object.defineProperty(Vue.prototype, '_$vd', {
get () {
get() {
return this.$root._$vdomSync
}
})
Vue.mixin({
beforeCreate () {
beforeCreate() {
if (this.$options.mpType) {
this.mpType = this.$options.mpType
}
......@@ -47,52 +69,34 @@ export function initData (Vue) {
if (this._$vd) {
this._$id = guid()
this._$vd.addVm(this)
this._$vdMountedData = Object.create(null)
this._$setData(MOUNTED_DATA, this._$vdMountedData)
console.log(`[${this._$id}] beforeCreate ` + Date.now())
// 目前全量采集做 diff(iOS 需要保留全量状态做 restore),理论上可以差量采集
this._$data = Object.create(null)
this._$newData = Object.create(null)
}
},
mounted () {
if (!this._$vd) {
return
}
const diffData = diff(this._$newData, this._$data)
this._$data = JSON.parse(JSON.stringify(this._$newData))
console.log(`[${this._$id}] mounted ` + Date.now())
this._$setData(MOUNTED_DATA, diffData)
if (this.mpType === 'page') {
// 页面 mounted 之后,第一次同步数据
this._$vd.flush()
}
},
beforeUpdate () {
beforeUpdate() {
if (!this._$vd) {
return
}
this._$vdUpdatedData = Object.create(null)
this._$setData(UPDATED_DATA, this._$vdUpdatedData)
console.log(`[${this._$id}] beforeUpdate ` + Date.now())
this._$newData = Object.create(null)
},
updated () {
if (!this._$vd) {
return
}
const diffData = diff(this._$newData, this._$data)
this._$data = JSON.parse(JSON.stringify(this._$newData))
console.log(`[${this._$id}] updated ` + Date.now())
this._$setData(UPDATED_DATA, diffData)
},
beforeDestroy () {
beforeDestroy() {
if (!this._$vd) {
return
}
this._$vd.removeVm(this)
this._$vdomSync && this._$vdomSync.destory()
this._$vdomSync && this._$vdomSync.destroy()
}
})
}
function setData (id, name, value) {
function setData(id, name, value) {
const diffData = this._$newData[id] || (this._$newData[id] = {})
if (typeof name !== 'string') {
......@@ -108,14 +112,19 @@ function setData (id, name, value) {
return (diffData[name] = value)
}
function setForData (id, value) {
function setForData(id, value) {
const diffData = this._$newData[id] || (this._$newData[id] = {})
const vForData = diffData['v-for'] || (diffData['v-for'] = [])
if (value.forItems) {
return value.forItems
}
const {
forIndex,
key
} = value
const diffData = this._$newData[id] || (this._$newData[id] = {})
const vForData = diffData['v-for'] || (diffData['v-for'] = [])
if (!hasOwn(value, 'keyIndex')) {
vForData[forIndex] = key
} else {
......@@ -124,10 +133,10 @@ function setForData (id, value) {
return key
}
function setIfData (id, value) {
function setIfData(id, value) {
return ((this._$newData[id] || (this._$newData[id] = {}))['v-if'] = value)
}
function setElseIfData (id, value) {
function setElseIfData(id, value) {
return ((this._$newData[id] || (this._$newData[id] = {}))['v-else-if'] = value)
}
......@@ -13,8 +13,7 @@ function diffObject (id, newObj, oldObj, result) {
}
}
export function diff (newData, oldData) {
const result = Object.create(null)
export function diff (newData, oldData, result) {
let id, cur, old
for (id in newData) {
cur = newData[id]
......
export {
lifecycleMixin as initLifecycle
import {
callPageHook
} from 'uni-core/service/plugins/util'
import {
lifecycleMixin
}
from 'uni-core/service/plugins/lifecycle'
export function initLifecycle (Vue) {
lifecycleMixin(Vue)
Vue.mixin({
beforeCreate () {
if (this.mpType === 'page') {
this.$scope = this.$options.pageInstance
this.$scope.$vm = this
delete this.$options.pageInstance
}
},
created () {
if (this.mpType === 'page') {
callPageHook(this.$scope, 'onLoad', this.$options.pageQuery)
callPageHook(this.$scope, 'onShow')
}
},
beforeDestroy () {
if (this.mpType === 'page') {
callPageHook(this.$scope, 'onUnload')
}
},
mounted () {
if (this.mpType === 'page') {
callPageHook(this.$scope, 'onReady')
}
}
})
}
import {
PAGE_CREATED
isFn
} from 'uni-shared'
import {
PAGE_CREATED,
VD_SYNC_CALLBACK
} from '../../../constants'
import {
......@@ -7,8 +12,12 @@ import {
registerWebviewUIEvent
} from '../subscribe-handlers'
function noop() {}
const callbacks = [] // 数据同步 callback
export class VDomSync {
constructor (pageId, pagePath) {
constructor(pageId, pagePath) {
this.pageId = pageId
this.pagePath = pagePath
this.batchData = []
......@@ -20,9 +29,19 @@ export class VDomSync {
this._init()
}
_init () {
_init() {
UniServiceJSBridge.subscribe(VD_SYNC_CALLBACK, () => {
const copies = callbacks.slice(0)
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
})
registerWebviewUIEvent(this.pageId, (cid, nid, event) => {
console.log(`[EVENT]`, cid, nid, event)
event.preventDefault = noop
event.stopPropagation = noop
if (
this.handlers[cid] &&
this.handlers[cid][nid] &&
......@@ -31,29 +50,49 @@ export class VDomSync {
this.handlers[cid][nid][event.type].forEach(handler => {
handler(event)
})
} else {
console.error(`event handler[${cid}][${nid}][${event.type}] not found`)
}
})
}
getVm (id) {
addMountedVm(vm) {
vm._$mounted() // 触发vd数据同步
this.addCallback(function mounted() {
vm.__call_hook('mounted')
})
}
addUpdatedVm(vm) {
vm._$updated() // 触发vd数据同步
this.addCallback(function mounted() {
vm.__call_hook('updated')
})
}
addCallback(callback) {
isFn(callback) && callbacks.push(callback)
}
getVm(id) {
return this.vms[id]
}
addVm (vm) {
addVm(vm) {
this.vms[vm._$id] = vm
}
removeVm (vm) {
removeVm(vm) {
delete this.vms[vm._$id]
}
addEvent (cid, nid, name, handler) {
addEvent(cid, nid, name, handler) {
const cHandlers = this.handlers[cid] || (this.handlers[cid] = Object.create(null))
const nHandlers = cHandlers[nid] || (cHandlers[nid] = Object.create(null));
(nHandlers[name] || (nHandlers[name] = [])).push(handler)
}
removeEvent (cid, nid, name, handler) {
removeEvent(cid, nid, name, handler) {
const cHandlers = this.handlers[cid] || (this.handlers[cid] = Object.create(null))
const nHandlers = cHandlers[nid] || (cHandlers[nid] = Object.create(null))
const eHandlers = nHandlers[name]
......@@ -65,11 +104,11 @@ export class VDomSync {
}
}
push (type, nodeId, data) {
push(type, nodeId, data) {
this.batchData.push([type, [nodeId, data]])
}
flush () {
flush() {
if (!this.initialized) {
this.initialized = true
this.batchData.push([PAGE_CREATED, [this.pageId, this.pagePath]])
......@@ -85,7 +124,7 @@ export class VDomSync {
}
}
destroy () {
destroy() {
this.batchData.length = 0
this.vms = Object.create(null)
this.initialized = false
......
import Vue from 'vue'
import {
hasOwn
}
from 'uni-shared'
import {
PAGE_CREATE,
MOUNTED_DATA,
UPDATED_DATA,
PAGE_CREATED
PAGE_CREATED,
VD_SYNC_CALLBACK
} from '../../../constants'
import {
......@@ -24,6 +32,7 @@ let PageVueComponent
const handleData = {
[PAGE_CREATE]: function onPageCreate (data) {
const [pageId, pagePath] = data
document.title = `${pagePath}[${pageId}]`
// 设置当前页面伪对象,方便其他地方使用 getCurrentPages 获取当前页面 id,route
setCurrentPage(pageId, pagePath)
// 初始化当前页面 VueComponent(生成页面样式代码)
......@@ -51,13 +60,36 @@ function vdSync ({
data,
options
}) {
let isVdCallback = true
data.forEach(data => {
if (data[0] === PAGE_CREATE) { // 页面创建无需触发 callback
isVdCallback = false
}
handleData[data[0]](data[1])
})
vd.flush()
isVdCallback && Vue.nextTick(() => {
UniViewJSBridge.publishHandler(VD_SYNC_CALLBACK)
})
}
function getData (id, name, isFallbackContent = false) {
const root = this.$r
if (hasOwn(root, id)) {
const vNodeData = root[id]
if (hasOwn(vNodeData, name)) {
return vNodeData[name]
} else {
!isFallbackContent && console.error(this.$options.__file + `:[${this._$id}]$r[${id}][${name}] is undefined`)
}
} else {
!isFallbackContent && console.error(this.$options.__file + `:[${this._$id}]$r[${id}] is undefined`)
}
}
export function initData (Vue) {
Vue.prototype._$g = getData
UniViewJSBridge.subscribe('vdSync', vdSync)
Object.defineProperty(Vue.prototype, '_$vd', {
......
......@@ -5,13 +5,10 @@ import {
export function initEvent (Vue) {
Vue.prototype.$handleViewEvent = function ($vueEvent, options) {
const $event = this.$handleEvent($vueEvent)
const cid = this._$id
const {
nid
} = $event.options
if (!nid) {
// 当自定义组件根节点触发事件时,nid 始终为 0
const nid = $vueEvent.currentTarget === this.$el ? 0 : $event.options.nid
if (typeof nid === 'undefined') {
return console.error(`[${cid}] nid not found`)
}
......
......@@ -19,7 +19,7 @@ export class VDomSync {
}
initVm (vm) {
const [nodeId, data] = this.addVDatas.pop()
const [nodeId, data] = this.addVDatas.shift()
if (!nodeId) {
vm._$id = guid()
console.error('nodeId unmatched', vm)
......@@ -37,7 +37,10 @@ export class VDomSync {
if (!vm) {
return console.error(`Not found ${nodeId}`)
}
Object.assign(vm.$r, data)
Object.keys(data).forEach(nodeId => {
Object.assign((vm.$r[nodeId] || (vm.$r[nodeId] = Object.create(null))), data[nodeId])
})
vm.$forceUpdate()
})
this.updateVDatas.length = 0
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册