@mpxjs/webpack-plugin 2.6.113 → 2.6.114-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/lib/config.js +14 -0
  2. package/lib/dependency/AddEntryDependency.js +24 -0
  3. package/lib/dependency/ResolveDependency.js +4 -0
  4. package/lib/index.js +44 -3
  5. package/lib/json-compiler/index.js +3 -0
  6. package/lib/loader.js +43 -2
  7. package/lib/path-loader.js +4 -1
  8. package/lib/platform/template/wx/component-config/button.js +14 -2
  9. package/lib/platform/template/wx/component-config/image.js +4 -0
  10. package/lib/platform/template/wx/component-config/input.js +4 -0
  11. package/lib/platform/template/wx/component-config/rich-text.js +4 -0
  12. package/lib/platform/template/wx/component-config/scroll-view.js +4 -0
  13. package/lib/platform/template/wx/component-config/switch.js +4 -0
  14. package/lib/platform/template/wx/component-config/text.js +4 -0
  15. package/lib/platform/template/wx/component-config/textarea.js +5 -0
  16. package/lib/platform/template/wx/component-config/view.js +4 -0
  17. package/lib/platform/template/wx/index.js +114 -1
  18. package/lib/runtime/components/tenon/filterTag.js +402 -0
  19. package/lib/runtime/components/tenon/getInnerListeners.js +292 -0
  20. package/lib/runtime/components/tenon/tenon-button.vue +305 -0
  21. package/lib/runtime/components/tenon/tenon-image.vue +61 -0
  22. package/lib/runtime/components/tenon/tenon-input.vue +95 -0
  23. package/lib/runtime/components/tenon/tenon-rich-text.vue +30 -0
  24. package/lib/runtime/components/tenon/tenon-scroll-view.vue +118 -0
  25. package/lib/runtime/components/tenon/tenon-switch.vue +91 -0
  26. package/lib/runtime/components/tenon/tenon-text-area.vue +64 -0
  27. package/lib/runtime/components/tenon/tenon-text.vue +64 -0
  28. package/lib/runtime/components/tenon/tenon-view.vue +89 -0
  29. package/lib/runtime/components/tenon/util.js +44 -0
  30. package/lib/runtime/optionProcessor.tenon.js +386 -0
  31. package/lib/template-compiler/compiler.js +11 -2
  32. package/lib/template-compiler/trans-dynamic-class-expr.js +1 -1
  33. package/lib/tenon/index.js +108 -0
  34. package/lib/tenon/processJSON.js +361 -0
  35. package/lib/tenon/processScript.js +260 -0
  36. package/lib/tenon/processStyles.js +21 -0
  37. package/lib/tenon/processTemplate.js +133 -0
  38. package/lib/utils/get-relative-path.js +24 -0
  39. package/package.json +7 -3
@@ -0,0 +1,402 @@
1
+ // eslint-disable-next-line
2
+ const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/ // useless escape
3
+ const ncname = `[a-zA-Z_][\\w\\-\\.]*`
4
+ const qname = `((?:${ncname}\\:)?${ncname})`
5
+ const startTagOpen = new RegExp(`^<${qname}`)
6
+ const startTagClose = /^\s*(\/?)>/
7
+ const endTag = new RegExp(`^<\\/${qname}[^>]*>`)
8
+ // eslint-disable-next-line
9
+ const comment = /^<!\--/
10
+ // eslint-disable-next-line
11
+ const invalidAttributeRE = /[\s"'<>\/=]/
12
+ // 当前节点的parent
13
+ let currentParent
14
+
15
+ function makeMap (str, expectsLowerCase) {
16
+ const map = Object.create(null)
17
+ const list = str.split(',')
18
+ for (let i = 0; i < list.length; i++) {
19
+ map[list[i]] = true
20
+ }
21
+ return expectsLowerCase
22
+ ? val => map[val.toLowerCase()]
23
+ : val => map[val]
24
+ }
25
+
26
+ const isTenonTag = makeMap('h1,h2,h3,h4,h5,h6,i,small,span,strong,image,a')
27
+
28
+ const isTenonTextTag = makeMap('h1,h2,h3,h4,h5,h6,i,small,span,strong')
29
+
30
+ const isTextAttrs = makeMap('color,backgroundColor,fontFamily,fontSize,fontWeight,fontStyle,textDecoration')
31
+
32
+ const isImageAttrs = makeMap('image,imageWidth,imageHeight,imageAlign')
33
+
34
+ const isAAttrs = makeMap('href,hrefColor')
35
+
36
+ const isUnaryTag = makeMap(
37
+ 'area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +
38
+ 'link,meta,param,source,track,wbr'
39
+ )
40
+ // const isSpace = makeMap('ensp,emsp,nbsp')
41
+
42
+ function makeAttrsMap (attrs) {
43
+ const map = {}
44
+ for (let i = 0, l = attrs.length; i < l; i++) {
45
+ map[attrs[i].name] = attrs[i].value
46
+ }
47
+ return map
48
+ }
49
+
50
+ function createASTElement (
51
+ tag,
52
+ attrs
53
+ ) {
54
+ return {
55
+ name: tag,
56
+ attrs: makeAttrsMap(attrs),
57
+ children: []
58
+ }
59
+ }
60
+
61
+ function parseHTML (html, options) {
62
+ const stack = []
63
+ let index = 0
64
+ // let last
65
+ while (html) {
66
+ // last = html
67
+ // Make sure we're not in a plaintext content element like script/style
68
+ // if (!lastTag) {
69
+ let textEnd = html.indexOf('<')
70
+ if (textEnd === 0) {
71
+ // 如果是注释节点
72
+ if (comment.test(html)) {
73
+ const commentEnd = html.indexOf('-->')
74
+
75
+ if (commentEnd >= 0) {
76
+ options.comment(html.substring(4, commentEnd))
77
+ advance(commentEnd + 3)
78
+ continue
79
+ }
80
+ }
81
+ // 如果是结束标签
82
+ const endTagMatch = html.match(endTag)
83
+ if (endTagMatch) {
84
+ const curIndex = index
85
+ advance(endTagMatch[0].length)
86
+ parseEndTag(endTagMatch[1], curIndex, index)
87
+ continue
88
+ }
89
+ // 如果是开始的开标签
90
+ const start = html.match(startTagOpen)
91
+ if (start) {
92
+ const match = {
93
+ tagName: start[1],
94
+ attrs: [],
95
+ start: index
96
+ }
97
+ advance(start[0].length)
98
+ let end, attr
99
+ while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
100
+ attr.start = index
101
+ advance(attr[0].length)
102
+ attr.end = index
103
+ match.attrs.push(attr)
104
+ }
105
+ if (end) {
106
+ match.unarySlash = end[1]
107
+ advance(end[0].length)
108
+ match.end = index
109
+ handleStartTag(match)
110
+ }
111
+ }
112
+ }
113
+ let text, rest, next
114
+
115
+ if (textEnd >= 0) {
116
+ // 获取剩下的部分
117
+ rest = html.slice(textEnd)
118
+ // 当不是结束标签 开始的开标签 注释标签时
119
+ while (
120
+ !endTag.test(rest) &&
121
+ !startTagOpen.test(rest) &&
122
+ !comment.test(rest)
123
+ ) {
124
+ // < in plain text, be forgiving and treat it as text
125
+ // 找下一个对应的<
126
+ next = rest.indexOf('<', 1)
127
+ if (next < 0) break
128
+ textEnd += next
129
+ rest = html.slice(textEnd)
130
+ }
131
+ // 将text截取出来 可能是没找到的
132
+ text = html.substring(0, textEnd)
133
+ }
134
+ // 没有找到<
135
+ if (textEnd < 0) {
136
+ text = html
137
+ }
138
+
139
+ if (text) {
140
+ advance(text.length)
141
+ }
142
+ if (options.chars && text) {
143
+ // 处理字符串
144
+ options.chars(text)
145
+ }
146
+ // }
147
+ }
148
+ parseEndTag()
149
+ function advance (n) {
150
+ index += n
151
+ html = html.substring(n)
152
+ }
153
+
154
+ function parseEndTag (tagName, start, end) {
155
+ let pos, lowerCasedTagName
156
+ if (start == null) start = index
157
+ if (end == null) end = index
158
+ // Find the closest opened tag of the same type
159
+ if (tagName) {
160
+ lowerCasedTagName = tagName.toLowerCase()
161
+ for (pos = stack.length - 1; pos >= 0; pos--) {
162
+ if (stack[pos].lowerCasedTag === lowerCasedTagName) {
163
+ break
164
+ }
165
+ }
166
+ } else {
167
+ // If no tag name is provided, clean shop
168
+ pos = 0
169
+ }
170
+ if (pos >= 0) {
171
+ // Close all the open elements, up the stack
172
+ for (let i = stack.length - 1; i >= pos; i--) {
173
+ if (i > pos || !tagName) {
174
+ console.warn(`tag <${stack[i].tag}> has no matching end tag.`,
175
+ { start: stack[i].start, end: stack[i].end })
176
+ }
177
+ if (options.end) {
178
+ options.end()
179
+ }
180
+ }
181
+
182
+ // Remove the open elements from the stack
183
+ stack.length = pos
184
+ }
185
+ }
186
+
187
+ function handleStartTag (match) {
188
+ const tagName = match.tagName.toLowerCase()
189
+ const unarySlash = match.unarySlash
190
+
191
+ const unary = isUnaryTag(tagName) || !!unarySlash
192
+
193
+ const l = match.attrs.length
194
+ const attrs = new Array(l)
195
+ for (let i = 0; i < l; i++) {
196
+ const args = match.attrs[i]
197
+ const value = args[3] || args[4] || args[5] || ''
198
+ attrs[i] = {
199
+ name: args[1],
200
+ value: value
201
+ }
202
+ }
203
+
204
+ if (!unary) {
205
+ stack.push({ tag: tagName, lowerCasedTag: tagName.toLowerCase(), attrs: attrs, start: match.start, end: match.end })
206
+ // lastTag = tagName
207
+ }
208
+
209
+ if (options.start) {
210
+ options.start(tagName, attrs, unary)
211
+ }
212
+ }
213
+ }
214
+
215
+ export function parse (template) {
216
+ let nodes = []
217
+ const stack = []
218
+ let root
219
+ function pushChild (currentParent, child) {
220
+ if (currentParent) {
221
+ currentParent.children.push(child)
222
+ } else {
223
+ nodes.push(child)
224
+ }
225
+ }
226
+ parseHTML(template, {
227
+ start (tag, attrs, unary) {
228
+ let element = createASTElement(tag, attrs, currentParent)
229
+ if (!unary && !stack.length) {
230
+ root = element
231
+ }
232
+ if (!unary) {
233
+ currentParent = element
234
+ stack.push(element)
235
+ } else if (isUnaryTag(tag)) {
236
+ pushChild(currentParent, element)
237
+ }
238
+ attrs.forEach(attr => {
239
+ if (invalidAttributeRE.test(attr.name)) {
240
+ console.warn(`Invalid dynamic argument expression: attribute names cannot contain ` +
241
+ `spaces, quotes, <, >, / or =.`, {
242
+ start: attr.start + attr.name.indexOf(`[`),
243
+ end: attr.start + attr.name.length
244
+ })
245
+ }
246
+ })
247
+ },
248
+ end () {
249
+ const element = stack[stack.length - 1]
250
+ // pop stack
251
+ stack.length -= 1
252
+ currentParent = stack[stack.length - 1]
253
+ currentParent && currentParent.children.push(element)
254
+ if (!stack.length) {
255
+ nodes.push(root)
256
+ }
257
+ },
258
+ chars (text) {
259
+ const child = {
260
+ type: 'text',
261
+ text
262
+ }
263
+ pushChild(currentParent, child)
264
+ },
265
+ comment (text) {
266
+ const child = {
267
+ type: 'comment',
268
+ text
269
+ }
270
+ pushChild(currentParent, child)
271
+ }
272
+ })
273
+ if (stack.length) {
274
+ let last
275
+ for (let i = stack.length - 1; i >= 0; i--) {
276
+ if (last) {
277
+ stack[i].children.push(last)
278
+ }
279
+ last = stack[i]
280
+ }
281
+ nodes.push(last)
282
+ }
283
+ return nodes
284
+ }
285
+
286
+ // function spaceTran (str, space) {
287
+ // const sReg = /( |&emsp;|&ensp;|&nbsp;){1}/g
288
+ // const setSpace = `&${space};`
289
+ // return str.replace(sReg, setSpace)
290
+ // }
291
+ function TenonTagCreater (tagName) {
292
+ if (this instanceof TenonTagCreater) {
293
+ return new this[tagName]()
294
+ }
295
+ return new TenonTagCreater(tagName)
296
+ }
297
+
298
+ TenonTagCreater.prototype = {
299
+ h1: function () {
300
+ return {
301
+ fontWeight: 'bold',
302
+ fontSize: 28
303
+ }
304
+ },
305
+ h2: function () {
306
+ return {
307
+ fontWeight: 'bold',
308
+ fontSize: 21
309
+ }
310
+ },
311
+ h3: function () {
312
+ return {
313
+ fontWeight: 'bold',
314
+ fontSize: 16.38
315
+ }
316
+ },
317
+ h4: function () {
318
+ return {
319
+ fontWeight: 'bold'
320
+ }
321
+ },
322
+ h5: function () {
323
+ return {
324
+ fontWeight: 'bold',
325
+ fontSize: 11.62
326
+ }
327
+ },
328
+ h6: function () {
329
+ return {
330
+ fontWeight: 'bold',
331
+ fontSize: 10.5
332
+ }
333
+ },
334
+ i: function () {
335
+ return {
336
+ fontStyle: 'italic'
337
+ }
338
+ },
339
+ small: function () {
340
+ return {
341
+ fontSize: 11.62
342
+ }
343
+ },
344
+ span: function () {
345
+ return {
346
+
347
+ }
348
+ },
349
+ strong: function () {
350
+ return {
351
+ fontWeight: 'bold'
352
+ }
353
+ },
354
+ image: function () {
355
+ return {
356
+
357
+ }
358
+ },
359
+ a: function () {
360
+ return {
361
+
362
+ }
363
+ }
364
+ }
365
+
366
+ export function htmlTranStr (template, space, parentNode) {
367
+ // 只能解析最外层的
368
+ let richTextArray = []
369
+ template.forEach(item => {
370
+ const name = item.name
371
+
372
+ if (item.type === 'text') {
373
+ // hummer不支持 暂时注释
374
+ // parentNode.text = isSpace(space) ? spaceTran(item.text, space) : item.text
375
+ parentNode.text = item.text
376
+ }
377
+ if (item.type === 'comment') {
378
+ console.warn(`the rich-text nonsupport ${item.type} tag`)
379
+ }
380
+ // 改造判断tenon支持的标签 根据默认样式 然后组合设置的样式
381
+ if (name && isTenonTag(name)) {
382
+ let node = new TenonTagCreater(name)
383
+
384
+ if (item.attrs) {
385
+ const attrs = item.attrs
386
+ for (const key in attrs) {
387
+ const isUnEffAttr = (isTenonTextTag(name) && !isTextAttrs(key)) || (name === 'image' && !isImageAttrs(key)) || (name === 'a' && !isAAttrs(key))
388
+ if (isUnEffAttr) {
389
+ console.warn(`This ${key} attribute is not supported for ${name} tags contained in rich-text`)
390
+ } else {
391
+ node[key] = attrs[key]
392
+ }
393
+ }
394
+ }
395
+ item.children.length && htmlTranStr(item.children, space, node)
396
+ richTextArray.push(node)
397
+ } else {
398
+ console.warn(`the rich-text is not support ${name} tag`)
399
+ }
400
+ })
401
+ return richTextArray
402
+ }
@@ -0,0 +1,292 @@
1
+ import { isEmptyObject } from './util'
2
+
3
+ const tapEvents = [
4
+ 'onTouchstart',
5
+ 'onTouchmove',
6
+ 'onTouchcancel',
7
+ 'onTouchend',
8
+ 'onLongtap'
9
+ ]
10
+
11
+ function createTouch (context, hasLongTap, __mpxTapInfo) {
12
+ return ({
13
+ onTouch (e) {
14
+ // 用touch模拟longtap
15
+ switch (e.state) {
16
+ case 1:
17
+ context.$emit('touchstart', e)
18
+ __mpxTapInfo.detail = {
19
+ x: e.position.x,
20
+ y: e.position.y
21
+ }
22
+ __mpxTapInfo.startTimer = null
23
+
24
+ if (hasLongTap) {
25
+ __mpxTapInfo.startTimer = setTimeout(() => {
26
+ if (hasLongTap) {
27
+ const re = inheritEvent(
28
+ 'longtap',
29
+ e,
30
+ __mpxTapInfo.detail
31
+ )
32
+ context.$emit('longtap', re)
33
+ __mpxTapInfo.startTimer = null
34
+ }
35
+ }, 350)
36
+ }
37
+
38
+ break
39
+ case 2:
40
+ context.$emit('touchmove', e)
41
+ const tapDetailInfo = __mpxTapInfo.detail || {}
42
+ const currentPageX = e.position.x
43
+ const currentPageY = e.position.y
44
+ if (
45
+ Math.abs(currentPageX - tapDetailInfo.x) > 1 ||
46
+ Math.abs(currentPageY - tapDetailInfo.y) > 1
47
+ ) {
48
+ __mpxTapInfo.startTimer &&
49
+ clearTimeout(__mpxTapInfo.startTimer)
50
+ __mpxTapInfo.startTimer = null
51
+ }
52
+ break
53
+ case 3:
54
+ context.$emit('touchend', e)
55
+ __mpxTapInfo.startTimer &&
56
+ clearTimeout(__mpxTapInfo.startTimer)
57
+ __mpxTapInfo.startTimer = null
58
+ break
59
+ case 4:
60
+ context.$emit('touchcancel', e)
61
+ break
62
+ }
63
+ }
64
+ })
65
+ }
66
+
67
+ function processModel (listeners, context) {
68
+ // 该函数只有wx:model的情况下才调用,而且默认e.detail.value有值
69
+ // 该函数必须在产生merge前执行
70
+ // todo 此处对于$attrs的访问会导致父组件更新时子组件必然更新,暂时用短路效应避免影响,待优化
71
+ // todo 访问$listeners也会导致上述现象,但是为了事件代理还必须访问$listeners,待后续思考处理
72
+
73
+ const modelEvent = context.$attrs.mpxModelEvent
74
+ if (modelEvent) {
75
+ // 对于modelEvent,内部获得时间后向外部转发,触发外部listener的同时转发为mpxModel事件
76
+ listeners[modelEvent] = function (e) {
77
+ context.$emit(modelEvent, e)
78
+ context.$emit('mpxModel', e)
79
+ }
80
+ // 内部listener不需要mpxModel
81
+ delete listeners.mpxModel
82
+ }
83
+ }
84
+
85
+ function mergeListeners (listeners, otherListeners, options = {}, context, __mpxTapInfo) {
86
+ if (!otherListeners) {
87
+ return
88
+ }
89
+ // "onTouchstart",
90
+ // "onTouchmove",
91
+ // "onTouchcancel",
92
+ // "onTouchend",
93
+ // "onLongtap",
94
+
95
+ // 都依赖touch事件 如果listener没有touch事件 如果是force需要强行添加一个touch事件 longTap需要根据context
96
+ // 特殊处理
97
+ const listenerMap = {}
98
+ tapEvents.forEach((eventName) => {
99
+ if (listeners[eventName]) {
100
+ listenerMap[eventName] = true
101
+ delete listeners[eventName]
102
+ }
103
+ })
104
+ // const otherListenerKeys = Object.keys(otherListeners)
105
+ // for (let key of otherListenerKeys) {
106
+
107
+ // }
108
+
109
+ Object.keys(otherListeners).forEach((key) => {
110
+ const listener = otherListeners[key]
111
+ let rawListener
112
+ if (tapEvents.includes(key)) {
113
+ // 判断onTouch是否存在 若存在 则直接处理
114
+ rawListener = listeners['onTouch']
115
+
116
+ if (!rawListener && !options.force) {
117
+ return
118
+ } else if (!rawListener && options.force) {
119
+ // 创建一个touh事件 并赋值
120
+ listeners['onTouch'] = createTouch(context, listenerMap.onLongtap, __mpxTapInfo).onTouch
121
+ rawListener = listeners['onTouch']
122
+ }
123
+ // 事件处理 onTouchstart 1 onTouchmove 2 onTouchend 3 onTouchcancel 4
124
+ listeners['onTouch'] = function (e) {
125
+ // const thatKey = key
126
+ let timer = null
127
+ if (key === 'onLongtap') {
128
+ if (e.state === 1) {
129
+ // start
130
+ timer = setTimeout(
131
+ () => {
132
+ listener.call(this, e)
133
+ },
134
+ options.before ? 340 : 360
135
+ )
136
+ } else if (e.state === 3) {
137
+ timer && clearTimeout(timer)
138
+ timer = null
139
+ }
140
+ } else {
141
+ if (options.before) {
142
+ if (key === 'onTouchstart' && e.state === 1) {
143
+ listener.call(this, e)
144
+ } else if (key === 'onTouchmove' && e.state === 2) {
145
+ listener.call(this, e)
146
+ } else if (key === 'onTouchend' && e.state === 3) {
147
+ listener.call(this, e)
148
+ } else if (key === 'onTouchcancel' && e.state === 4) {
149
+ listener.call(this, e)
150
+ }
151
+ rawListener.call(this, e)
152
+ } else {
153
+ rawListener.call(this, e)
154
+ if (key === 'onTouchstart' && e.state === 1) {
155
+ listener.call(this, e)
156
+ } else if (key === 'onTouchmove' && e.state === 2) {
157
+ listener.call(this, e)
158
+ } else if (key === 'onTouchend' && e.state === 3) {
159
+ listener.call(this, e)
160
+ } else if (key === 'onTouchcancel' && e.state === 4) {
161
+ listener.call(this, e)
162
+ }
163
+ }
164
+ }
165
+ }
166
+ } else {
167
+ rawListener = listeners[key]
168
+
169
+ if (!rawListener) {
170
+ if (options.force) {
171
+ listeners[key] = listener
172
+ }
173
+ } else {
174
+ listeners[key] = function (e) {
175
+ if (options.before) {
176
+ listener.call(this, e)
177
+ rawListener.call(this, e)
178
+ } else {
179
+ rawListener.call(this, e)
180
+ listener.call(this, e)
181
+ }
182
+ }
183
+ }
184
+ }
185
+ })
186
+ }
187
+ // 没有tap 用touch模拟 touchstart touchmove touchcancel touchend tap longpress langtap
188
+ function processTouchAndLtap (listeners, context, __mpxTapInfo) {
189
+ const listenerMap = {}
190
+ tapEvents.forEach((eventName) => {
191
+ if (listeners[eventName]) {
192
+ listenerMap[eventName] = true
193
+ delete listeners[eventName]
194
+ }
195
+ })
196
+ if (isEmptyObject(listenerMap)) return
197
+ let events = createTouch(context, listenerMap.onLongtap, __mpxTapInfo)
198
+ mergeListeners(
199
+ listeners,
200
+ events,
201
+ {
202
+ force: true
203
+ },
204
+ context,
205
+ __mpxTapInfo
206
+ )
207
+ }
208
+
209
+ export function extendEvent (e, extendObj = {}) {
210
+ Object.keys(extendObj).forEach((key) => {
211
+ Object.defineProperty(e, key, {
212
+ value: extendObj[key],
213
+ enumerable: true,
214
+ configurable: true,
215
+ writable: true
216
+ })
217
+ })
218
+ }
219
+
220
+ export function inheritEvent (type, oe, detail = {}) {
221
+ detail = Object.assign({}, oe.detail, detail)
222
+ const ne = getCustomEvent(type, detail)
223
+ extendEvent(ne, {
224
+ timeStamp: oe.timeStamp,
225
+ target: oe.target,
226
+ currentTarget: oe.currentTarget,
227
+ stopPropagation: oe.stopPropagation.bind(oe),
228
+ preventDefault: oe.preventDefault.bind(oe)
229
+ })
230
+ return ne
231
+ }
232
+
233
+ export function getCustomEvent (type, detail = {}, target = null) {
234
+ return {
235
+ type,
236
+ detail,
237
+ target,
238
+ timeStamp: new Date().valueOf()
239
+ }
240
+ }
241
+
242
+ function noop () {}
243
+
244
+ function getListeners (context) {
245
+ let attrs = context.$attrs
246
+ let listeners = {}
247
+ Object.keys(attrs).forEach((v) => {
248
+ if (/^on[A-Z]/.test(v)) {
249
+ listeners[v] = attrs[v]
250
+ }
251
+ })
252
+ return listeners
253
+ }
254
+
255
+ export default function getInnerListeners (context, options = {}) {
256
+ let {
257
+ mergeBefore = {},
258
+ mergeAfter = {},
259
+ defaultListeners = [],
260
+ ignoredListeners = []
261
+ } = options
262
+ let __mpxTapInfo = {}
263
+ // 从attrs里面拿到以on开头的所有绑定的事件
264
+ const listeners = Object.assign({}, getListeners(context))
265
+ defaultListeners.forEach((key) => {
266
+ if (!listeners[key]) listeners[key] = noop
267
+ })
268
+ const mergeBeforeOptions = {
269
+ before: true
270
+ }
271
+ const mergeAfterOptions = {
272
+ before: false
273
+ }
274
+
275
+ if (mergeBefore.listeners) {
276
+ mergeBeforeOptions.force = mergeBefore.force
277
+ mergeBefore = mergeBefore.listeners
278
+ }
279
+
280
+ if (mergeAfter.listeners) {
281
+ mergeAfterOptions.force = mergeAfter.force
282
+ mergeAfter = mergeAfter.listeners
283
+ }
284
+ processModel(listeners, context)
285
+ processTouchAndLtap(listeners, context, __mpxTapInfo)
286
+ mergeListeners(listeners, mergeBefore, mergeBeforeOptions, context, __mpxTapInfo)
287
+ mergeListeners(listeners, mergeAfter, mergeAfterOptions, context, __mpxTapInfo)
288
+ ignoredListeners.forEach((key) => {
289
+ delete listeners[key]
290
+ })
291
+ return listeners
292
+ }