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

feat(v3): v-for (view)

上级 49caf73a
......@@ -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,
......
......@@ -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;
}
};
......
......@@ -15,19 +15,19 @@ describe('codegen', () => {
it('generate directive', () => {
assertCodegen(
'<p v-custom1:[arg1].modifier="value1" v-custom2></p>',
`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(
'<div><template v-for="item in items"><div></div><div></div></template></div>',
`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(
'<div>A{{ d | e | f }}B{{text}}C</div>',
`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")])}`
)
})
})
......
......@@ -558,14 +558,14 @@ describe('codegen', () => {
it('generate component', () => {
assertCodegen(
'<my-component name="mycomponent1" :msg="msg" @notify="onNotify"><div>hi</div></my-component>',
`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(
'<svg><my-comp><circle :r="10"></circle></my-comp></svg>',
`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)}`
)
})
......
const compiler = require('../lib')
const res = compiler.compile(
`
<view>
<image src="aaaa" :a="b"/>
</view>
<p slot="one">{{hello}}</p>
`, {
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,
......
......@@ -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)
}
}
......@@ -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) {
......
......@@ -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
}
......@@ -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) {
......
......@@ -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
......
......@@ -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
}
}
......@@ -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)}
`
}
......
......@@ -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$/
......
......@@ -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'
......
export function registerPlus (newPlus) {
// 确保 plus 是 app-service 中的
if (plus !== newPlus) {
if (process.env.NODE_ENV !== 'production') {
console.log(`[registerPlus][${Date.now()}]`)
}
plus = newPlus
}
}
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
}
}
......@@ -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(
......
......@@ -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()
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册