From 840995bbd8dff8b4664f31f251a79961d223e27d Mon Sep 17 00:00:00 2001 From: fxy060608 Date: Mon, 14 Oct 2019 18:53:58 +0800 Subject: [PATCH] feat(v3): v-for (view) --- packages/uni-app-plus/dist/index.v3.js | 33 ++++++++++----- .../uni-app-plus/dist/service.runtime.esm.js | 5 +++ ...s => compiler-app-plus-extra.view.spec.js} | 6 +-- .../compiler-app-plus.service.spec.js | 4 +- .../uni-template-compiler/__tests__/demo.js | 14 ++++--- .../lib/app/component-parser.js | 1 + .../uni-template-compiler/lib/app/service.js | 8 +++- .../uni-template-compiler/lib/app/util.js | 10 +++-- .../uni-template-compiler/lib/app/view.js | 40 ++++++++++++------- packages/uni-template-compiler/lib/index.js | 9 ++++- packages/uni-template-compiler/lib/util.js | 20 +++++++++- .../lib/platforms/app-plus/define-pages.js | 6 ++- src/core/helpers/promise.js | 2 +- src/platforms/app-plus/service/api/index.js | 2 +- .../service/api/plugin/register-plus.js | 9 ----- .../service/api/plugin/restore-global.js | 23 +++++++++++ .../app-plus/service/api/route/re-launch.js | 2 +- .../app-plus/service/framework/page.js | 5 +-- 18 files changed, 141 insertions(+), 58 deletions(-) rename packages/uni-template-compiler/__tests__/{compiler-app-plus-extra.view.js => compiler-app-plus-extra.view.spec.js} (54%) delete mode 100644 src/platforms/app-plus/service/api/plugin/register-plus.js create mode 100644 src/platforms/app-plus/service/api/plugin/restore-global.js diff --git a/packages/uni-app-plus/dist/index.v3.js b/packages/uni-app-plus/dist/index.v3.js index 11fdf38ae6..762701e08c 100644 --- a/packages/uni-app-plus/dist/index.v3.js +++ b/packages/uni-app-plus/dist/index.v3.js @@ -524,7 +524,7 @@ var serviceContext = (function () { }; const SYNC_API_RE = - /^\$|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; + /^\$|restoreGlobal|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; const CONTEXT_API_RE = /^create|Manager$/; @@ -5853,13 +5853,27 @@ var serviceContext = (function () { ); } - function registerPlus (newPlus) { - // 确保 plus 是 app-service 中的 + function restoreGlobal ( + newPlus, + newSetTimeout, + newClearTimeout, + newSetInterval, + newClearInterval + ) { + // 确保部分全局变量 是 app-service 中的 + // 若首页 nvue 初始化比 app-service 快,导致框架处于该 nvue 环境下 + // plus 如果不用 app-service,资源路径会出问题 + // 若首页 nvue 被销毁,如 redirectTo 或 reLaunch,则这些全局功能会损坏 if (plus !== newPlus) { if (process.env.NODE_ENV !== 'production') { - console.log(`[registerPlus][${Date.now()}]`); + console.log(`[restoreGlobal][${Date.now()}]`); } - plus = newPlus; + plus = newPlus; + /* eslint-disable no-global-assign */ + setTimeout = newSetTimeout; + clearTimeout = newClearTimeout; + setInterval = newSetInterval; + clearInterval = newClearInterval; } } @@ -6434,19 +6448,18 @@ var serviceContext = (function () { { if (!webview.nvue) { const pageId = webview.id; - const pagePath = path.slice(1); // 通知页面已开始创建 UniServiceJSBridge.publishHandler('vdSync', { data: [ - [PAGE_CREATE, [pageId, pagePath]] + [PAGE_CREATE, [pageId, route]] ], options: { timestamp: Date.now() } }, [pageId]); - pageInstance.$vm = createPage(pagePath, pageId); + pageInstance.$vm = createPage(route, pageId); pageInstance.$vm.$scope = pageInstance; pageInstance.$vm.$mount(); } @@ -6510,7 +6523,7 @@ var serviceContext = (function () { const routeOptions = __uniRoutes.find(route => route.path === path); if (routeOptions.meta.isTabBar) { - tabBar$1.switchTab(path); + tabBar$1.switchTab(path.slice(1)); } showWebview( @@ -7144,7 +7157,7 @@ var serviceContext = (function () { requireNativePlugin: requireNativePlugin$1, shareAppMessageDirectly: shareAppMessageDirectly, share: share, - registerPlus: registerPlus, + restoreGlobal: restoreGlobal, navigateBack: navigateBack$1, navigateTo: navigateTo$1, reLaunch: reLaunch$1, diff --git a/packages/uni-app-plus/dist/service.runtime.esm.js b/packages/uni-app-plus/dist/service.runtime.esm.js index 487d4cf108..a438cf5b37 100644 --- a/packages/uni-app-plus/dist/service.runtime.esm.js +++ b/packages/uni-app-plus/dist/service.runtime.esm.js @@ -6774,6 +6774,11 @@ function callHook$2(hook, args) { var plugin = { install: function install(Vue) { + + Vue.prototype._m = function renderStatic() { + return this._e() + }; + Vue.prototype.__call_hook = callHook$2; } }; diff --git a/packages/uni-template-compiler/__tests__/compiler-app-plus-extra.view.js b/packages/uni-template-compiler/__tests__/compiler-app-plus-extra.view.spec.js similarity index 54% rename from packages/uni-template-compiler/__tests__/compiler-app-plus-extra.view.js rename to packages/uni-template-compiler/__tests__/compiler-app-plus-extra.view.spec.js index 4fe9b00e19..f8d79afd40 100644 --- a/packages/uni-template-compiler/__tests__/compiler-app-plus-extra.view.js +++ b/packages/uni-template-compiler/__tests__/compiler-app-plus-extra.view.spec.js @@ -15,19 +15,19 @@ describe('codegen', () => { it('generate directive', () => { assertCodegen( '

', - `with(this){return _c('p',{directives:[{name:"custom1",rawName:"v-custom1:[arg1].modifier",value:($r['0']['v-custom1']),expression:"$r['0']['v-custom1']",arg:$r['0']['v-custom1-arg'],modifiers:{"modifier":true}},{name:"custom2",rawName:"v-custom2"}],attrs:{"_i":0}})}` + `with(this){return _c('v-uni-view',{directives:[{name:"custom1",rawName:"v-custom1:[arg1].modifier",value:($r['0']['v-custom1']),expression:"$r['0']['v-custom1']",arg:$r['0']['v-custom1-arg'],modifiers:{"modifier":true}},{name:"custom2",rawName:"v-custom2"}],attrs:{"_i":0}})}` ) }) it('generate v-for directive', () => { assertCodegen( '
', - `with(this){return _c('div',{attrs:{"_i":0}},[_l(($r['1']['v-for']),function(item,$i){return [_c('div',{key:item['k0'],attrs:{"_i":("2-"+$i)}}),_c('div',{key:item['k1'],attrs:{"_i":("3-"+$i)}})]})],2)}` + `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)}` ) }) it('generate events with multiple statements', () => { assertCodegen( '
A{{ d | e | f }}B{{text}}C
', - `with(this){return _c('div',{attrs:{"_i":0}},[_v("A"+($r['0']['t-0'])+"B"+($r['0']['t-1'])+"C")])}` + `with(this){return _c('v-uni-view',{attrs:{"_i":0}},[_v("A"+($r['0']['t0'])+"B"+($r['0']['t1'])+"C")])}` ) }) }) diff --git a/packages/uni-template-compiler/__tests__/compiler-app-plus.service.spec.js b/packages/uni-template-compiler/__tests__/compiler-app-plus.service.spec.js index c487472655..5ab5a4341f 100644 --- a/packages/uni-template-compiler/__tests__/compiler-app-plus.service.spec.js +++ b/packages/uni-template-compiler/__tests__/compiler-app-plus.service.spec.js @@ -558,14 +558,14 @@ describe('codegen', () => { it('generate component', () => { assertCodegen( '
hi
', - `with(this){return _c('my-component',{attrs:{"msg":msg,"_i":0},on:{"notify":onNotify}},[_c('div',{attrs:{"_i":1}})])}` + `with(this){return _c('my-component',{attrs:{"name":"mycomponent1","msg":msg,"_i":0},on:{"notify":onNotify}},[_c('div',{attrs:{"_i":1}})])}` ) }) it('generate svg component with children', () => { assertCodegen( '', - `with(this){return _c('svg',{attrs:{"_i":0}},[_c('my-comp',{attrs:{"_i":1}},[_c('circle',{attrs:{"_i":2}})])],1)}` + `with(this){return _c('svg',{attrs:{"_i":0}},[_c('my-comp',{attrs:{"_i":1}},[_c('circle',{attrs:{"r":10,"_i":2}})],1)],1)}` ) }) diff --git a/packages/uni-template-compiler/__tests__/demo.js b/packages/uni-template-compiler/__tests__/demo.js index d83baf8038..213b3df1c4 100644 --- a/packages/uni-template-compiler/__tests__/demo.js +++ b/packages/uni-template-compiler/__tests__/demo.js @@ -1,16 +1,20 @@ const compiler = require('../lib') const res = compiler.compile( ` - - - +

{{hello}}

`, { resourcePath: '/User/fxy/Documents/test.wxml', + isReservedTag: function (tag) { + return true + }, + getTagNamespace () { + return false + }, mp: { platform: 'app-plus' }, - service: true - // view: true + // service: true + view: true }) console.log(require('util').inspect(res, { colors: true, diff --git a/packages/uni-template-compiler/lib/app/component-parser.js b/packages/uni-template-compiler/lib/app/component-parser.js index 17bfaf6d6f..2898681f9e 100644 --- a/packages/uni-template-compiler/lib/app/component-parser.js +++ b/packages/uni-template-compiler/lib/app/component-parser.js @@ -14,6 +14,7 @@ module.exports = function parseComponent (el) { // TODO 需要把自定义组件的 attrs, props 全干掉 el.tag = getTagName(el.tag) if (!hasOwn(tags, el.tag)) { + // 仅保留 ID el.attrs = el.attrs.filter(attr => attr.name === ID) } } diff --git a/packages/uni-template-compiler/lib/app/service.js b/packages/uni-template-compiler/lib/app/service.js index fcc057d438..8c40b7cf42 100644 --- a/packages/uni-template-compiler/lib/app/service.js +++ b/packages/uni-template-compiler/lib/app/service.js @@ -7,6 +7,10 @@ const { updateForEleId } = require('./util') +const { + isComponent +} = require('../util') + const parseText = require('./text-parser') const parseEvent = require('./event-parser') @@ -265,7 +269,9 @@ function processText (el) { } function processAttrs (el) { - el.attrs = el.attrs.filter(attr => attr.name === ID || isVar(attr.value)) + if (!isComponent(el.tag)) { // 自定义组件,不能移除静态 attr + el.attrs = el.attrs.filter(attr => attr.name === ID || isVar(attr.value)) + } } function postTransformNode (el) { diff --git a/packages/uni-template-compiler/lib/app/util.js b/packages/uni-template-compiler/lib/app/util.js index 81919d3279..1306171154 100644 --- a/packages/uni-template-compiler/lib/app/util.js +++ b/packages/uni-template-compiler/lib/app/util.js @@ -104,18 +104,20 @@ function processForKey (el) { } } +function hasOwn (obj, key) { + return hasOwnProperty.call(obj, key) +} + module.exports = { ID, DATA_ROOT, ITERATOR, isVar, + hasOwn, addAttr, getForEl, processForKey, updateForEleId, getBindingAttr, - getAndRemoveAttr, - hasOwn: function (obj, key) { - return hasOwnProperty.call(obj, key) - } + getAndRemoveAttr } diff --git a/packages/uni-template-compiler/lib/app/view.js b/packages/uni-template-compiler/lib/app/view.js index adf2053c7b..eb7b1c7d6e 100644 --- a/packages/uni-template-compiler/lib/app/view.js +++ b/packages/uni-template-compiler/lib/app/view.js @@ -122,27 +122,23 @@ function processProps (el, genVar) { }) } -function processText (el, genVar) { +function processText (el, parent) { const state = { index: 0, view: true, - genVar + genVar: createGenVar(parent.attrsMap[ID]) } - - el.children.forEach(child => { - if (child.type === 2) { // ASTExpression - child.expression = parseText(child.text, false, state).expression - } - }) + el.expression = parseText(el.text, false, state).expression } -function postTransformNode (el) { - parseComponent(el) - parseTag(el) - parseEvent(el) - +function transformNode (el, parent) { + // 更新 id updateForEleId(el) + if (el.type !== 1) { + return (el.type === 2 && processText(el, parent)) + } + const id = el.attrsMap[ID] const genVar = createGenVar(id) @@ -153,7 +149,23 @@ function postTransformNode (el) { processDirs(el, genVar) processAttrs(el, genVar) processProps(el, genVar) - processText(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) + } } function processEvents (events) { diff --git a/packages/uni-template-compiler/lib/index.js b/packages/uni-template-compiler/lib/index.js index 9911e8220a..a8c0389f7f 100644 --- a/packages/uni-template-compiler/lib/index.js +++ b/packages/uni-template-compiler/lib/index.js @@ -22,13 +22,20 @@ const compilerAlipayModule = require('./module-alipay') const generateCodeFrame = require('./codeframe') +const { + isComponent +} = require('./util') + module.exports = { - compile (source, options = {}) { + compile (source, options = {}) { if (options.service) { (options.modules || (options.modules = [])).push(require('./app/service')) options.optimize = true // 启用 staticRenderFns // domProps => attrs options.mustUseProp = () => false + options.isReservedTag = (tagName) => !isComponent(tagName) // 非组件均为内置 + options.getTagNamespace = () => false + // clear staticRenderFns const compiled = compile(source, options) compiled.staticRenderFns.length = 0 diff --git a/packages/uni-template-compiler/lib/util.js b/packages/uni-template-compiler/lib/util.js index 40bf03c8b6..79ba4eaa96 100644 --- a/packages/uni-template-compiler/lib/util.js +++ b/packages/uni-template-compiler/lib/util.js @@ -172,7 +172,25 @@ function processMemberExpression (element, state) { return element } +function hasOwn (obj, key) { + return hasOwnProperty.call(obj, key) +} + +const tags = require('../../uni-cli-shared/lib/tags') + +const { + getTagName +} = require('./h5') + +function isComponent (tagName) { + if (tagName === 'block' || tagName === 'template') { + return false + } + return !hasOwn(tags, getTagName(tagName)) +} + module.exports = { + isComponent, genCode, getCode, camelize, @@ -196,4 +214,4 @@ module.exports = { }), processMemberExpression, getForIndexIdentifier -} +} diff --git a/packages/webpack-uni-pages-loader/lib/platforms/app-plus/define-pages.js b/packages/webpack-uni-pages-loader/lib/platforms/app-plus/define-pages.js index 84bf72f9d3..5eb7ece22e 100644 --- a/packages/webpack-uni-pages-loader/lib/platforms/app-plus/define-pages.js +++ b/packages/webpack-uni-pages-loader/lib/platforms/app-plus/define-pages.js @@ -10,8 +10,10 @@ function generatePageCode (pages, pageOptions) { module.exports = function definePages (appJson) { return { name: 'define-pages.js', - content: ` -uni.registerPlus && uni.registerPlus(typeof plus !== 'undefined' && plus) + content: ` +if(uni.restoreGlobal){ + uni.restoreGlobal(plus,setTimeout,clearTimeout,setInterval,clearInterval) +} ${generatePageCode(appJson.pages, appJson.page)} ` } diff --git a/src/core/helpers/promise.js b/src/core/helpers/promise.js index b4d947939e..0071f75c4b 100644 --- a/src/core/helpers/promise.js +++ b/src/core/helpers/promise.js @@ -8,7 +8,7 @@ import { } from './interceptor' const SYNC_API_RE = - /^\$|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/ + /^\$|restoreGlobal|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/ const CONTEXT_API_RE = /^create|Manager$/ diff --git a/src/platforms/app-plus/service/api/index.js b/src/platforms/app-plus/service/api/index.js index 6ed797a91f..9b1693b2ea 100644 --- a/src/platforms/app-plus/service/api/index.js +++ b/src/platforms/app-plus/service/api/index.js @@ -42,7 +42,7 @@ export * from './plugin/payment' export * from './plugin/push' export * from './plugin/require-native-plugin' export * from './plugin/share' -export * from './plugin/register-plus' +export * from './plugin/restore-global' export * from './route/navigate-back' export * from './route/navigate-to' diff --git a/src/platforms/app-plus/service/api/plugin/register-plus.js b/src/platforms/app-plus/service/api/plugin/register-plus.js deleted file mode 100644 index 0981704c9a..0000000000 --- a/src/platforms/app-plus/service/api/plugin/register-plus.js +++ /dev/null @@ -1,9 +0,0 @@ -export function registerPlus (newPlus) { - // 确保 plus 是 app-service 中的 - if (plus !== newPlus) { - if (process.env.NODE_ENV !== 'production') { - console.log(`[registerPlus][${Date.now()}]`) - } - plus = newPlus - } -} diff --git a/src/platforms/app-plus/service/api/plugin/restore-global.js b/src/platforms/app-plus/service/api/plugin/restore-global.js new file mode 100644 index 0000000000..7fe42ab30f --- /dev/null +++ b/src/platforms/app-plus/service/api/plugin/restore-global.js @@ -0,0 +1,23 @@ +export function restoreGlobal ( + newPlus, + newSetTimeout, + newClearTimeout, + newSetInterval, + newClearInterval +) { + // 确保部分全局变量 是 app-service 中的 + // 若首页 nvue 初始化比 app-service 快,导致框架处于该 nvue 环境下 + // plus 如果不用 app-service,资源路径会出问题 + // 若首页 nvue 被销毁,如 redirectTo 或 reLaunch,则这些全局功能会损坏 + if (plus !== newPlus) { + if (process.env.NODE_ENV !== 'production') { + console.log(`[restoreGlobal][${Date.now()}]`) + } + plus = newPlus + /* eslint-disable no-global-assign */ + setTimeout = newSetTimeout + clearTimeout = newClearTimeout + setInterval = newSetInterval + clearInterval = newClearInterval + } +} diff --git a/src/platforms/app-plus/service/api/route/re-launch.js b/src/platforms/app-plus/service/api/route/re-launch.js index 16ec11aaa3..2ec2ada00f 100644 --- a/src/platforms/app-plus/service/api/route/re-launch.js +++ b/src/platforms/app-plus/service/api/route/re-launch.js @@ -30,7 +30,7 @@ function _reLaunch ({ const routeOptions = __uniRoutes.find(route => route.path === path) if (routeOptions.meta.isTabBar) { - tabBar.switchTab(path) + tabBar.switchTab(path.slice(1)) } showWebview( diff --git a/src/platforms/app-plus/service/framework/page.js b/src/platforms/app-plus/service/framework/page.js index a3bdfc797b..3f5372c98f 100644 --- a/src/platforms/app-plus/service/framework/page.js +++ b/src/platforms/app-plus/service/framework/page.js @@ -104,19 +104,18 @@ export function registerPage ({ if (__PLATFORM__ === 'app-plus') { if (!webview.nvue) { const pageId = webview.id - const pagePath = path.slice(1) // 通知页面已开始创建 UniServiceJSBridge.publishHandler('vdSync', { data: [ - [PAGE_CREATE, [pageId, pagePath]] + [PAGE_CREATE, [pageId, route]] ], options: { timestamp: Date.now() } }, [pageId]) - pageInstance.$vm = createPage(pagePath, pageId) + pageInstance.$vm = createPage(route, pageId) pageInstance.$vm.$scope = pageInstance pageInstance.$vm.$mount() } -- GitLab