mh-two-thousand-and-two
2024-04-12 3d2ec2fd0578d3ba0a414b0cc4e4a2ae60878596
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
const path = require('path')
const t = require('@babel/types')
const uniI18n = require('@dcloudio/uni-cli-i18n')
 
function generateJsCode (properties = '{}') {
  return `
wx.createComponent({
    generic:true,
    props: ${properties},
    render: function(){}
})
`
}
 
function generateCssCode (filename) {
  return `
@import "./${filename}"
`
}
 
function hasOwn (obj, key) {
  return Object.prototype.hasOwnProperty.call(obj, key)
}
 
module.exports = {
  directive: 'wx:',
  createScopedSlots (slotName, props, state) {
    const componentName = 'scoped-slots-' + slotName
    if (!state.componentGenerics) {
      state.componentGenerics = Object.create(null)
    }
    state.componentGenerics[componentName] = true
    const attr = props || {}
    if (state.options.platform.name === 'mp-weixin') {
      attr.class = 'scoped-ref'
    }
    // 返回多个节点,支持作用域插槽当作普通插槽使用
    return [{
      type: 'slot',
      attr: {
        name: slotName
      },
      children: []
    },
    {
      type: componentName,
      attr,
      children: []
    }
    ]
  },
  resolveScopedSlots (slotName, {
    genCode,
    generate,
    ownerName,
    parentName,
    parentNode,
    resourcePath,
    paramExprNode,
    returnExprNodes,
    traverseExpr
  }, state) {
    if (!state.scopedSlots) {
      state.scopedSlots = {}
    }
    const baseName = `${ownerName}-${parentName}-${slotName}`
    let componentName = baseName
    if (!hasOwn(state.scopedSlots, baseName)) {
      state.scopedSlots[baseName] = 0
    }
    if (state.scopedSlots[baseName]) {
      componentName = baseName + state.scopedSlots[baseName]
    }
    state.scopedSlots[baseName]++
    parentNode.attr['generic:scoped-slots-' + slotName] = componentName
    if (state.options.platform.name === 'mp-weixin') {
      parentNode.attr['data-vue-generic'] = 'scoped'
    }
    if (!parentNode.attr.generic) {
      parentNode.attr.generic = {}
    }
    parentNode.attr.generic[slotName] = true
 
    // 生成 scopedSlots 文件,包括 json,js,wxml,wxss,还需要更新 owner 的 usingComponents
    if (!state.files) {
      state.files = {}
    }
    const extname = path.extname(resourcePath)
 
    // TODO 需要存储 resourcePath 相关 json
 
    const templateFile = resourcePath.replace(ownerName + extname, componentName + extname)
    const templateContent = generate(traverseExpr(returnExprNodes, state), state)
 
    state.files[templateFile] = templateContent
 
    const jsFile = resourcePath.replace(ownerName + extname, componentName + '.js')
 
    const objectProperties = []
 
    if (t.isObjectPattern(paramExprNode)) {
      paramExprNode.properties.forEach(property => {
        const key = property.key
        const value = property.value
        const valueObjectProperties = [
          t.objectProperty(t.identifier('type'), t.nullLiteral())
        ]
        if (t.isIdentifier(value)) {
          if (value.name !== key.name) {
            state.errors.add(uniI18n.__('mpWeChat.slotPropNoSupportReanme', { 0: key.name, 1: value.name }))
          }
        } else if (t.isAssignmentPattern(value)) {
          valueObjectProperties.push(t.objectProperty(t.identifier('default'), value.right))
        }
        objectProperties.push(t.objectProperty(key, t.objectExpression(valueObjectProperties)))
      })
    } else {
      state.errors.add(uniI18n.__('mpWeChat.onlySupportDestructuringSlot', { 0: paramExprNode.name, 1: 'v-slot="{ user }"' }))
    }
    const jsContent = generateJsCode(genCode(t.objectExpression(objectProperties), true))
    state.files[jsFile] = jsContent
 
    try {
      // TODO 使用 getPlatformExts 在单元测试报错,改从 state.options.platform 判断
      const {
        getPlatformExts
      } = require('@dcloudio/uni-cli-shared')
      const styleExtname = getPlatformExts().style
      const styleFile = resourcePath.replace(ownerName + extname, componentName + styleExtname)
      const styleContent = generateCssCode(ownerName + styleExtname)
 
      state.files[styleFile] = styleContent
    } catch (error) {}
 
    if (!state.generic) {
      state.generic = []
    }
    // 存储,方便后续生成 json
    state.generic.push(componentName)
 
    return ''
  }
}