123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- /* @flow */
- /**
- * Cross-platform code generation for component v-model
- */
- export function genComponentModel (
- el: ASTElement,
- value: string,
- modifiers: ?ASTModifiers
- ): ?boolean {
- const { number, trim } = modifiers || {}
- const baseValueExpression = '$$v'
- let valueExpression = baseValueExpression
- if (trim) {
- valueExpression =
- `(typeof ${baseValueExpression} === 'string'` +
- `? ${baseValueExpression}.trim()` +
- `: ${baseValueExpression})`
- }
- if (number) {
- valueExpression = `_n(${valueExpression})`
- }
- const assignment = genAssignmentCode(value, valueExpression)
- el.model = {
- value: `(${value})`,
- expression: JSON.stringify(value),
- callback: `function (${baseValueExpression}) {${assignment}}`
- }
- }
- /**
- * Cross-platform codegen helper for generating v-model value assignment code.
- */
- export function genAssignmentCode (
- value: string,
- assignment: string
- ): string {
- const res = parseModel(value)
- if (res.key === null) {
- return `${value}=${assignment}`
- } else {
- return `$set(${res.exp}, ${res.key}, ${assignment})`
- }
- }
- /**
- * Parse a v-model expression into a base path and a final key segment.
- * Handles both dot-path and possible square brackets.
- *
- * Possible cases:
- *
- * - test
- * - test[key]
- * - test[test1[key]]
- * - test["a"][key]
- * - xxx.test[a[a].test1[key]]
- * - test.xxx.a["asa"][test1[key]]
- *
- */
- let len, str, chr, index, expressionPos, expressionEndPos
- type ModelParseResult = {
- exp: string,
- key: string | null
- }
- export function parseModel (val: string): ModelParseResult {
- // Fix https://github.com/vuejs/vue/pull/7730
- // allow v-model="obj.val " (trailing whitespace)
- val = val.trim()
- len = val.length
- if (val.indexOf('[') < 0 || val.lastIndexOf(']') < len - 1) {
- index = val.lastIndexOf('.')
- if (index > -1) {
- return {
- exp: val.slice(0, index),
- key: '"' + val.slice(index + 1) + '"'
- }
- } else {
- return {
- exp: val,
- key: null
- }
- }
- }
- str = val
- index = expressionPos = expressionEndPos = 0
- while (!eof()) {
- chr = next()
- /* istanbul ignore if */
- if (isStringStart(chr)) {
- parseString(chr)
- } else if (chr === 0x5B) {
- parseBracket(chr)
- }
- }
- return {
- exp: val.slice(0, expressionPos),
- key: val.slice(expressionPos + 1, expressionEndPos)
- }
- }
- function next (): number {
- return str.charCodeAt(++index)
- }
- function eof (): boolean {
- return index >= len
- }
- function isStringStart (chr: number): boolean {
- return chr === 0x22 || chr === 0x27
- }
- function parseBracket (chr: number): void {
- let inBracket = 1
- expressionPos = index
- while (!eof()) {
- chr = next()
- if (isStringStart(chr)) {
- parseString(chr)
- continue
- }
- if (chr === 0x5B) inBracket++
- if (chr === 0x5D) inBracket--
- if (inBracket === 0) {
- expressionEndPos = index
- break
- }
- }
- }
- function parseString (chr: number): void {
- const stringQuote = chr
- while (!eof()) {
- chr = next()
- if (chr === stringQuote) {
- break
- }
- }
- }
|