提交 e8f14edc 编写于 作者: Q qiang

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

上级 f32384bf
......@@ -15,6 +15,11 @@ describe('wxml:compiler', () => {
`<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>`
)
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', () => {
assertCodegen(
......@@ -63,5 +68,27 @@ describe('wxml:compiler', () => {
'<slot></slot>',
`<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 importTemplate = require('./import-template')
function transformScript(content, route, code) {
function transformScript (content, route, code) {
return `${code}
global['__wxRoute'] = '${route}'
${content}
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 = {
transformScript,
transformScriptFile(filepath, code, options, deps) {
let content = ''
if (options.components.length) {
code = genJsCode(options.components, code, options)
}
if (!fs.existsSync(filepath)) {
content = `
Component({})
......
......@@ -3,6 +3,12 @@ const generate = require('./generate')
module.exports = function transform(ast, options) {
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)
}
const {
parse
} = require('mustache')
const recast = require('recast')
const TAGS = [
'ad',
......@@ -163,8 +164,12 @@ function transformEvent(name, value, attribs, state) {
event = transformEventName(name.replace(captureCatchRE, ''), state) + '.stop.prevent.capture'
}
if (event !== name) {
let newValue = parseMustache(value, true)
if (newValue !== value) {
// 模板 <template name> 中用到的方法在其父组件
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)`
}
attribs[event] = newValue
......@@ -201,9 +206,11 @@ function transformAttrs(node, state) {
}
transformFor(attribs)
const isComponent = !TAGS.includes(node.name)
const isTemplate = state.templates.length
Object.keys(attribs).forEach(name => {
transformAttr(name, attribs[name], attribs, {
isComponent
isComponent,
isTemplate
})
})
}
......@@ -212,7 +219,40 @@ function transformChildren(node, 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) {
if (node.name === 'import') {
state.components.push(node)
return false
}
if (node.name === 'template') {
transformTemplate(node, state)
}
if (node.name === 'wxs') {
state.wxs.push(node)
return false
......
......@@ -25,6 +25,7 @@
"commander": "^4.0.1",
"fs-extra": "^8.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.
先完成此消息的编辑!
想要评论请 注册