Skip to content

Commit

Permalink
feat(weex): generate "@render" function for weex recycle-list (#6987)
Browse files Browse the repository at this point in the history
* feat($compiler): support to generate @render function for weex recycle-list

Compile the template twice with different options for weex platform if
the “recyclable” flag is passed. Generate both normal render function
and “@render” function for recycle-list.

Adjust function names and arguments in recycle-list compiler.

* test(weex): add test cases for <recycle-list>
  • Loading branch information
Hanks10100 authored and yyx990803 committed Dec 19, 2017
1 parent 305ef28 commit 0c11aa8
Show file tree
Hide file tree
Showing 28 changed files with 588 additions and 30 deletions.
4 changes: 4 additions & 0 deletions flow/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ declare type CompilerOptions = {
shouldDecodeNewlines?: boolean;
shouldDecodeNewlinesForHref?: boolean;

// support <recycle-list> in weex
recyclable?: boolean;

// for ssr optimization compiler
scopeId?: string;

Expand All @@ -30,6 +33,7 @@ declare type CompilerOptions = {
declare type CompiledResult = {
ast: ?ASTElement;
render: string;
'@render'?: string;
staticRenderFns: Array<string>;
stringRenderFns?: Array<string>;
errors?: Array<string>;
Expand Down
18 changes: 12 additions & 6 deletions src/compiler/codegen/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,18 @@ export function genHandlers (

// Generate handler code with binding params on Weex
function genWeexHandler (params: Array<any>, handlerCode: string) {
const wrapperArgs = params.filter(exp => simplePathRE.test(exp) && exp !== '$event')
const handlerParams = wrapperArgs.map(exp => ({ '@binding': exp }))
wrapperArgs.push('$event')
return '{' +
`handler:function(${wrapperArgs.join(',')}){${handlerCode}},\n` +
`params:${JSON.stringify(handlerParams)}` +
let innerHandlerCode = handlerCode
const exps = params.filter(exp => simplePathRE.test(exp) && exp !== '$event')
const bindings = exps.map(exp => ({ '@binding': exp }))
const args = exps.map((exp, i) => {
const key = `$_${i + 1}`
innerHandlerCode = innerHandlerCode.replace(exp, key)
return key
})
args.push('$event')
return '{\n' +
`handler:function(${args.join(',')}){${innerHandlerCode}},\n` +
`params:${JSON.stringify(bindings)}\n` +
'}'
}

Expand Down
24 changes: 22 additions & 2 deletions src/platforms/weex/compiler/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,28 @@ export const baseOptions: CompilerOptions = {
isReservedTag,
getTagNamespace,
preserveWhitespace: false,
recyclable: false,
staticKeys: genStaticKeys(modules)
}

const { compile, compileToFunctions } = createCompiler(baseOptions)
export { compile, compileToFunctions }
const compiler = createCompiler(baseOptions)

export function compile (
template: string,
options?: CompilerOptions
): CompiledResult {
let generateAltRender = false
if (options && options.recyclable === true) {
generateAltRender = true
options.recyclable = false
}
const result = compiler.compile(template, options)

// generate @render function for <recycle-list>
if (options && generateAltRender) {
options.recyclable = true
const { render } = compiler.compile(template, options)
result['@render'] = render
}
return result
}
36 changes: 20 additions & 16 deletions src/platforms/weex/compiler/modules/recycle-list/index.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,42 @@
/* @flow */

import { transformText } from './text'
import { transformVBind } from './v-bind'
import { transformVIf } from './v-if'
import { transformVFor } from './v-for'
import { postTransformText } from './text'
import { preTransformVBind } from './v-bind'
import { preTransformVIf } from './v-if'
import { preTransformVFor } from './v-for'
import { postTransformVOn } from './v-on'

let currentRecycleList = null

function shouldCompile (el: ASTElement, options: CompilerOptions) {
return options.recyclable ||
(currentRecycleList && el !== currentRecycleList)
}

function preTransformNode (el: ASTElement, options: CompilerOptions) {
if (el.tag === 'recycle-list') {
currentRecycleList = el
}
if (currentRecycleList) {
// TODO
transformVBind(el)
transformVIf(el, options) // and v-else-if and v-else
transformVFor(el, options)
if (shouldCompile(el, options)) {
preTransformVBind(el, options)
preTransformVIf(el, options) // also v-else-if and v-else
preTransformVFor(el, options)
}
}

function transformNode (el: ASTElement) {
if (currentRecycleList) {
// TODO
function transformNode (el: ASTElement, options: CompilerOptions) {
if (shouldCompile(el, options)) {
// do nothing yet
}
}

function postTransformNode (el: ASTElement) {
if (currentRecycleList) {
function postTransformNode (el: ASTElement, options: CompilerOptions) {
if (shouldCompile(el, options)) {
// <text>: transform children text into value attr
if (el.tag === 'text') {
transformText(el)
postTransformText(el, options)
}
postTransformVOn(el)
postTransformVOn(el, options)
}
if (el === currentRecycleList) {
currentRecycleList = null
Expand Down
2 changes: 1 addition & 1 deletion src/platforms/weex/compiler/modules/recycle-list/text.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function genText (node: ASTNode) {
return JSON.stringify(value)
}

export function transformText (el: ASTElement) {
export function postTransformText (el: ASTElement, options: CompilerOptions) {
// weex <text> can only contain text, so the parser
// always generates a single child.
if (el.children.length) {
Expand Down
2 changes: 1 addition & 1 deletion src/platforms/weex/compiler/modules/recycle-list/v-bind.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function parseAttrName (name: string): string {
return camelize(name.replace(bindRE, ''))
}

export function transformVBind (el: ASTElement) {
export function preTransformVBind (el: ASTElement, options: CompilerOptions) {
for (const attr in el.attrsMap) {
if (bindRE.test(attr)) {
const name: string = parseAttrName(attr)
Expand Down
2 changes: 1 addition & 1 deletion src/platforms/weex/compiler/modules/recycle-list/v-for.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { forAliasRE, forIteratorRE } from 'compiler/parser/index'
import { getAndRemoveAttr } from 'compiler/helpers'

export function transformVFor (el: ASTElement, options: CompilerOptions) {
export function preTransformVFor (el: ASTElement, options: CompilerOptions) {
const exp = getAndRemoveAttr(el, 'v-for')
if (!exp) {
return
Expand Down
2 changes: 1 addition & 1 deletion src/platforms/weex/compiler/modules/recycle-list/v-if.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function getPrevMatch (el: ASTElement): any {
}
}

export function transformVIf (el: ASTElement, options: CompilerOptions) {
export function preTransformVIf (el: ASTElement, options: CompilerOptions) {
if (hasConditionDirective(el)) {
let exp
const ifExp = getAndRemoveAttr(el, 'v-if')
Expand Down
4 changes: 2 additions & 2 deletions src/platforms/weex/compiler/modules/recycle-list/v-on.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* @flow */

const inlineStatementRE = /^\s*([A-Za-z_$0-9\.]+)*\s*\(\s*(([A-Za-z_$0-9\'\"]+)?(\s*,\s*([A-Za-z_$0-9\'\"]+))*)\s*\)$/
const inlineStatementRE = /^\s*([A-Za-z_$0-9\['\."\]]+)*\s*\(\s*(([A-Za-z_$0-9\['\."\]]+)?(\s*,\s*([A-Za-z_$0-9\['\."\]]+))*)\s*\)$/

function parseHandlerParams (handler: ASTElementHandler) {
const res = inlineStatementRE.exec(handler.value)
Expand All @@ -9,7 +9,7 @@ function parseHandlerParams (handler: ASTElementHandler) {
}
}

export function postTransformVOn (el: ASTElement) {
export function postTransformVOn (el: ASTElement, options: CompilerOptions) {
const events: ASTElementHandlers | void = el.events
if (!events) {
return
Expand Down
12 changes: 12 additions & 0 deletions test/weex/cases/cases.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,17 @@ describe('Usage', () => {
describe('event', () => {
it('click', createEventTestCase('event/click'))
})

describe('recycle-list', () => {
it('text node', createRenderTestCase('recycle-list/text-node'))
it('attributes', createRenderTestCase('recycle-list/attrs'))
it('v-if', createRenderTestCase('recycle-list/v-if'))
it('v-else', createRenderTestCase('recycle-list/v-else'))
it('v-else-if', createRenderTestCase('recycle-list/v-else-if'))
it('v-for', createRenderTestCase('recycle-list/v-for'))
it('v-for-iterator', createRenderTestCase('recycle-list/v-for-iterator'))
it('v-on', createRenderTestCase('recycle-list/v-on'))
it('v-on-inline', createRenderTestCase('recycle-list/v-on-inline'))
})
})

33 changes: 33 additions & 0 deletions test/weex/cases/recycle-list/attrs.vdom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
({
type: 'recycle-list',
attr: {
listData: [
{ type: 'A', count: 1, source: 'http://whatever.com/x.png' },
{ type: 'A', count: 2, source: 'http://whatever.com/y.png' },
{ type: 'A', count: 3, source: 'http://whatever.com/z.png' }
],
templateKey: 'type',
alias: 'item'
},
children: [{
type: 'cell-slot',
attr: { templateType: 'A' },
children: [{
type: 'image',
attr: {
resize: 'cover',
src: {
'@binding': 'item.source'
}
}
}, {
type: 'text',
attr: {
lines: '3',
count: {
'@binding': 'item.count'
}
}
}]
}]
})
23 changes: 23 additions & 0 deletions test/weex/cases/recycle-list/attrs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<recycle-list :list-data="longList" template-key="type" alias="item">
<cell-slot template-type="A">
<image resize="cover" :src="item.source">
<text lines="3" v-bind:count="item.count"></text>
</cell-slot>
</recycle-list>
</template>

<script>
module.exports = {
data () {
return {
longList: [
{ type: 'A', count: 1, source: 'http://whatever.com/x.png' },
{ type: 'A', count: 2, source: 'http://whatever.com/y.png' },
{ type: 'A', count: 3, source: 'http://whatever.com/z.png' }
]
}
}
}
</script>

37 changes: 37 additions & 0 deletions test/weex/cases/recycle-list/text-node.vdom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
({
type: 'recycle-list',
attr: {
listData: [
{ type: 'A', dynamic: 'decimal', two: '2', four: '4' },
{ type: 'A', dynamic: 'binary', two: '10', four: '100' }
],
templateKey: 'type',
alias: 'item'
},
children: [{
type: 'cell-slot',
attr: { templateType: 'A' },
children: [{
type: 'text',
attr: {
value: 'static'
}
}, {
type: 'text',
attr: {
value: { '@binding': 'item.dynamic' }
}
}, {
type: 'text',
attr: {
value: [
'one ',
{ '@binding': 'item.two' },
' three ',
{ '@binding': 'item.four' },
' five'
]
}
}]
}]
})
23 changes: 23 additions & 0 deletions test/weex/cases/recycle-list/text-node.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<recycle-list :list-data="longList" template-key="type" alias="item">
<cell-slot template-type="A">
<text>static</text>
<text>{{item.dynamic}}</text>
<text>one {{item.two}} three {{ item.four }} five</text>
</cell-slot>
</recycle-list>
</template>

<script>
module.exports = {
data () {
return {
longList: [
{ type: 'A', dynamic: 'decimal', two: '2', four: '4' },
{ type: 'A', dynamic: 'binary', two: '10', four: '100' }
]
}
}
}
</script>

34 changes: 34 additions & 0 deletions test/weex/cases/recycle-list/v-else-if.vdom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
({
type: 'recycle-list',
attr: {
listData: [
{ type: 'A' },
{ type: 'A' }
],
templateKey: 'type',
alias: 'item'
},
children: [{
type: 'cell-slot',
attr: { templateType: 'A' },
children: [{
type: 'image',
attr: {
'[[match]]': 'item.sourceA',
src: { '@binding': 'item.sourceA' }
}
}, {
type: 'image',
attr: {
'[[match]]': '!(item.sourceA) && (item.sourceB)',
src: { '@binding': 'item.sourceB' }
}
}, {
type: 'image',
attr: {
'[[match]]': '!(!(item.sourceA) && (item.sourceB))',
src: { '@binding': 'item.placeholder' }
}
}]
}]
})
23 changes: 23 additions & 0 deletions test/weex/cases/recycle-list/v-else-if.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<recycle-list :list-data="longList" template-key="type" alias="item">
<cell-slot template-type="A">
<image v-if="item.sourceA" :src="item.sourceA"></image>
<image v-else-if="item.sourceB" :src="item.sourceB"></image>
<image v-else :src="item.placeholder"></image>
</cell-slot>
</recycle-list>
</template>

<script>
module.exports = {
data () {
return {
longList: [
{ type: 'A' },
{ type: 'A' }
]
}
}
}
</script>

0 comments on commit 0c11aa8

Please sign in to comment.