提交 e8f14edc 编写于 作者: Q qiang

fix: 小程序组件支持 import、template 标签

上级 f32384bf
...@@ -15,6 +15,11 @@ describe('wxml:compiler', () => { ...@@ -15,6 +15,11 @@ describe('wxml:compiler', () => {
`<uni-transition bind:click="click" bindtouchstart="startDrag" catchtouchmove="{{ catchMove ? 'noop' : '' }}"/>`, `<uni-transition bind:click="click" bindtouchstart="startDrag" catchtouchmove="{{ catchMove ? 'noop' : '' }}"/>`,
`<uni-shadow-root><uni-transition @click="click" @touchstart.native="startDrag" @touchmove.native.stop.prevent="_$self[(catchMove ? 'noop' : '')||'_$noop']($event)"></uni-transition></uni-shadow-root>` `<uni-shadow-root><uni-transition @click="click" @touchstart.native="startDrag" @touchmove.native.stop.prevent="_$self[(catchMove ? 'noop' : '')||'_$noop']($event)"></uni-transition></uni-shadow-root>`
) )
assertCodegen(
'<template name="toolbar"><view bindtap="emit"></view></template>',
// `<view @click="_$self.$parent[(emit)||'_$noop']($event)"></view>`
`<uni-shadow-root><template v-if="wxTemplateName === 'toolbar'"><view @click="_$self.$parent[('emit')]($event)"></view></template></uni-shadow-root>`
)
}) })
it('generate class', () => { it('generate class', () => {
assertCodegen( assertCodegen(
...@@ -63,5 +68,27 @@ describe('wxml:compiler', () => { ...@@ -63,5 +68,27 @@ describe('wxml:compiler', () => {
'<slot></slot>', '<slot></slot>',
`<uni-shadow-root><slot></slot></uni-shadow-root>` `<uni-shadow-root><slot></slot></uni-shadow-root>`
) )
assertCodegen(
`<import src="./toolbar.wxml" /><view></view>
<wxs></wxs>`,
`<uni-shadow-root><view></view></uni-shadow-root>`
)
assertCodegen(
'<view><template is="toolbar" data="{{ showToolbar, cancelButtonText, title, confirmButtonText }}"></template></view>',
`<uni-shadow-root><view><toolbar v-bind="{showToolbar, cancelButtonText, title, confirmButtonText}" wx-template-name="toolbar"></toolbar></view></uni-shadow-root>`
)
assertCodegen(
'<template name="toolbar"><view></view></template>',
// `<view></view>`
`<uni-shadow-root><template v-if="wxTemplateName === 'toolbar'"><view></view></template></uni-shadow-root>`
)
assertCodegen(
'<template name="toolbar1"><view></view></template><template name="toolbar2"><view></view></template>',
`<uni-shadow-root><template v-if="wxTemplateName === 'toolbar1'"><view></view></template><template v-if="wxTemplateName === 'toolbar2'"><view></view></template></uni-shadow-root>`
)
}) })
}) })
const fs = require('fs')
const path = require('path')
const parse = require('./template-transformer/parser')
function getTemplate (content) {
const template = []
const node = parse(content)
node.children.forEach(node => {
if (node.name === 'template') {
const name = node.attribs.name
if (name) {
template.push(name)
}
}
})
return template
}
module.exports = function (filepath, options) {
filepath = path.join(path.dirname(options.filepath), filepath)
return getTemplate(fs.readFileSync(filepath, 'utf8').toString().trim())
}
\ No newline at end of file
const fs = require('fs') const fs = require('fs')
const importTemplate = require('./import-template')
function transformScript(content, route, code) { function transformScript (content, route, code) {
return `${code} return `${code}
global['__wxRoute'] = '${route}' global['__wxRoute'] = '${route}'
${content} ${content}
export default global['__wxComponents']['${route}']` export default global['__wxComponents']['${route}']`
} }
function genJsCode(components, code, state) {
const wxTemplateComponentProps = '__wxTemplateComponentProps'
const props = state.props
const importCode = []
const propsCode = []
const componentsCode = []
components.forEach((node, index) => {
const src = node.attribs.src
const templates = importTemplate(src, state)
const identifier = `__wxTemplateComponent${index}`
importCode.push(`import ${identifier} from '${src.replace(/.wxml$/, '.vue')}'`)
templates.forEach(template => {
// TODO 改为在 template 编译时静态分析
propsCode.push(`${wxTemplateComponentProps}['${template}'] && ${wxTemplateComponentProps}['${template}'].forEach(prop => ${identifier}.props[prop] = {type: null})`)
componentsCode.push(`'${template}' : ${identifier}`)
})
})
return components.length ? `
const ${wxTemplateComponentProps} = ${JSON.stringify(props)}
${importCode.join('\n')}
${propsCode.join('\n')}
${code.trim().replace(/\}\}$/, '')},${componentsCode.join(',')}}}
`: code
}
module.exports = { module.exports = {
transformScript, transformScript,
transformScriptFile(filepath, code, options, deps) { transformScriptFile(filepath, code, options, deps) {
let content = '' let content = ''
if (options.components.length) {
code = genJsCode(options.components, code, options)
}
if (!fs.existsSync(filepath)) { if (!fs.existsSync(filepath)) {
content = ` content = `
Component({}) Component({})
......
...@@ -3,6 +3,12 @@ const generate = require('./generate') ...@@ -3,6 +3,12 @@ const generate = require('./generate')
module.exports = function transform(ast, options) { module.exports = function transform(ast, options) {
options.wxs = [] options.wxs = []
options.shouldWrapper = options.shouldWrapper || function noop() {} // wxml 中使用 import 导入的组件
options.components = []
// wxml 中使用 <template name> 声明的模板
options.templates = []
// wxml 中 <template is> 分析得到的 props
options.props = {}
options.shouldWrapper = options.shouldWrapper || function noop () { }
return generate(traverse(ast, options), options) return generate(traverse(ast, options), options)
} }
const { const {
parse parse
} = require('mustache') } = require('mustache')
const recast = require('recast')
const TAGS = [ const TAGS = [
'ad', 'ad',
...@@ -163,8 +164,12 @@ function transformEvent(name, value, attribs, state) { ...@@ -163,8 +164,12 @@ function transformEvent(name, value, attribs, state) {
event = transformEventName(name.replace(captureCatchRE, ''), state) + '.stop.prevent.capture' event = transformEventName(name.replace(captureCatchRE, ''), state) + '.stop.prevent.capture'
} }
if (event !== name) { if (event !== name) {
let newValue = parseMustache(value, true) // 模板 <template name> 中用到的方法在其父组件
if (newValue !== value) { let newValue = parseMustache(value, !state.isTemplate)
if (state.isTemplate) {
// TODO 改为运行时判断
newValue = `_$self.$parent${process.env.UNI_PLATFORM === 'h5' ? '.$parent' : ''}[(${newValue})]($event)`
} else if (newValue !== value) {
newValue = `_$self[(${newValue})||'_$noop']($event)` newValue = `_$self[(${newValue})||'_$noop']($event)`
} }
attribs[event] = newValue attribs[event] = newValue
...@@ -201,9 +206,11 @@ function transformAttrs(node, state) { ...@@ -201,9 +206,11 @@ function transformAttrs(node, state) {
} }
transformFor(attribs) transformFor(attribs)
const isComponent = !TAGS.includes(node.name) const isComponent = !TAGS.includes(node.name)
const isTemplate = state.templates.length
Object.keys(attribs).forEach(name => { Object.keys(attribs).forEach(name => {
transformAttr(name, attribs[name], attribs, { transformAttr(name, attribs[name], attribs, {
isComponent isComponent,
isTemplate
}) })
}) })
} }
...@@ -212,7 +219,40 @@ function transformChildren(node, state) { ...@@ -212,7 +219,40 @@ function transformChildren(node, state) {
node.children = node.children.filter(childNode => transformNode(childNode, state)) node.children = node.children.filter(childNode => transformNode(childNode, state))
} }
function transformTemplate(node, state) {
const attribs = node.attribs
if (attribs.name) {
const name = attribs.name
// 用于处理一个 wxml 文件内包含多个 template
attribs['v-if'] = `wxTemplateName === '${name}'`
delete attribs.name
state.templates.push(name)
} else if (attribs.is) {
const name = attribs.is
delete attribs.is
node.name = name
attribs['wx-template-name'] = name
const data = attribs.data
if (data && data.indexOf('{{') !== -1) {
const object = `{${parseMustache(data)}}`
attribs['v-bind'] = object
const ast = recast.parse(`const object = ${object}`)
const props = state.props[name] || ['wxTemplateName']
ast.program.body[0].declarations[0].init.properties.forEach(property => props.push(property.key.name))
state.props[name] = [...new Set(props)]
delete attribs.data
}
}
}
function transformNode(node, state) { function transformNode(node, state) {
if (node.name === 'import') {
state.components.push(node)
return false
}
if (node.name === 'template') {
transformTemplate(node, state)
}
if (node.name === 'wxs') { if (node.name === 'wxs') {
state.wxs.push(node) state.wxs.push(node)
return false return false
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"commander": "^4.0.1", "commander": "^4.0.1",
"fs-extra": "^8.1.0", "fs-extra": "^8.1.0",
"mustache": "^3.1.0", "mustache": "^3.1.0",
"stricter-htmlparser2": "^3.9.6" "stricter-htmlparser2": "^3.9.6",
"recast": "*"
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册