@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.
- package/lib/config.js +14 -0
- package/lib/dependency/AddEntryDependency.js +24 -0
- package/lib/dependency/ResolveDependency.js +4 -0
- package/lib/index.js +44 -3
- package/lib/json-compiler/index.js +3 -0
- package/lib/loader.js +43 -2
- package/lib/path-loader.js +4 -1
- package/lib/platform/template/wx/component-config/button.js +14 -2
- package/lib/platform/template/wx/component-config/image.js +4 -0
- package/lib/platform/template/wx/component-config/input.js +4 -0
- package/lib/platform/template/wx/component-config/rich-text.js +4 -0
- package/lib/platform/template/wx/component-config/scroll-view.js +4 -0
- package/lib/platform/template/wx/component-config/switch.js +4 -0
- package/lib/platform/template/wx/component-config/text.js +4 -0
- package/lib/platform/template/wx/component-config/textarea.js +5 -0
- package/lib/platform/template/wx/component-config/view.js +4 -0
- package/lib/platform/template/wx/index.js +114 -1
- package/lib/runtime/components/tenon/filterTag.js +402 -0
- package/lib/runtime/components/tenon/getInnerListeners.js +292 -0
- package/lib/runtime/components/tenon/tenon-button.vue +305 -0
- package/lib/runtime/components/tenon/tenon-image.vue +61 -0
- package/lib/runtime/components/tenon/tenon-input.vue +95 -0
- package/lib/runtime/components/tenon/tenon-rich-text.vue +30 -0
- package/lib/runtime/components/tenon/tenon-scroll-view.vue +118 -0
- package/lib/runtime/components/tenon/tenon-switch.vue +91 -0
- package/lib/runtime/components/tenon/tenon-text-area.vue +64 -0
- package/lib/runtime/components/tenon/tenon-text.vue +64 -0
- package/lib/runtime/components/tenon/tenon-view.vue +89 -0
- package/lib/runtime/components/tenon/util.js +44 -0
- package/lib/runtime/optionProcessor.tenon.js +386 -0
- package/lib/template-compiler/compiler.js +11 -2
- package/lib/template-compiler/trans-dynamic-class-expr.js +1 -1
- package/lib/tenon/index.js +108 -0
- package/lib/tenon/processJSON.js +361 -0
- package/lib/tenon/processScript.js +260 -0
- package/lib/tenon/processStyles.js +21 -0
- package/lib/tenon/processTemplate.js +133 -0
- package/lib/utils/get-relative-path.js +24 -0
- 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 = /( | | | ){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
|
+
}
|