create-weapp-vite 1.3.3 → 1.3.5

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 (31) hide show
  1. package/dist/{chunk-KDUDSVZ5.js → chunk-4YYMSJFM.js} +2 -2
  2. package/dist/cli.cjs +2 -2
  3. package/dist/cli.js +1 -1
  4. package/dist/index.cjs +2 -2
  5. package/dist/index.js +1 -1
  6. package/package.json +2 -2
  7. package/templates/wevu/tsconfig.app.json +2 -1
  8. package/templates/wevu-tdesign/.vscode/settings.json +5 -0
  9. package/templates/wevu-tdesign/components.d.ts +240 -240
  10. package/templates/wevu-tdesign/mini-program.html-data.json +6728 -0
  11. package/templates/wevu-tdesign/public/tabbar/ability-active.png +0 -0
  12. package/templates/wevu-tdesign/public/tabbar/ability.png +0 -0
  13. package/templates/wevu-tdesign/public/tabbar/data-active.png +0 -0
  14. package/templates/wevu-tdesign/public/tabbar/data.png +0 -0
  15. package/templates/wevu-tdesign/public/tabbar/form-active.png +0 -0
  16. package/templates/wevu-tdesign/public/tabbar/form.png +0 -0
  17. package/templates/wevu-tdesign/public/tabbar/home-active.png +0 -0
  18. package/templates/wevu-tdesign/public/tabbar/home.png +0 -0
  19. package/templates/wevu-tdesign/public/tabbar/list-active.png +0 -0
  20. package/templates/wevu-tdesign/public/tabbar/list.png +0 -0
  21. package/templates/wevu-tdesign/src/app.vue +1 -1
  22. package/templates/wevu-tdesign/src/components/KpiBoard/index.vue +13 -13
  23. package/templates/wevu-tdesign/src/pages/ability/index.vue +2 -1
  24. package/templates/wevu-tdesign/src/pages/form/index.vue +34 -19
  25. package/templates/wevu-tdesign/src/pages/index/index.vue +51 -0
  26. package/templates/wevu-tdesign/src/subpackages/lab/class-binding/index.vue +236 -0
  27. package/templates/wevu-tdesign/src/subpackages/lab/index.vue +14 -0
  28. package/templates/wevu-tdesign/src/vite-env.d.ts +0 -1
  29. package/templates/wevu-tdesign/tsconfig.app.json +6 -4
  30. package/templates/wevu-tdesign/typed-components.d.ts +1 -2
  31. package/templates/wevu-tdesign/vite.config.ts +2 -0
@@ -56,7 +56,7 @@ defineAppJson({
56
56
  subPackages: [
57
57
  {
58
58
  root: 'subpackages/lab',
59
- pages: ['index'],
59
+ pages: ['index', 'class-binding/index'],
60
60
  },
61
61
  {
62
62
  root: 'subpackages/ability',
@@ -34,19 +34,6 @@ export interface KpiItem {
34
34
  footnote?: string
35
35
  }
36
36
 
37
- const cards = computed(() => {
38
- const source = Array.isArray(props.items) ? props.items : []
39
- return source.map((item, index) => ({
40
- key: item.key ?? String(index),
41
- item,
42
- index,
43
- tone: resolveTone(item.delta),
44
- isLeading: index === 0,
45
- }))
46
- })
47
-
48
- const gridClass = computed(() => (props.columns === 3 ? 'grid-cols-3' : 'grid-cols-2'))
49
-
50
37
  function resolveTone(delta?: number): KpiTone {
51
38
  if (delta === undefined || Number.isNaN(delta)) {
52
39
  return 'neutral'
@@ -60,6 +47,19 @@ function resolveTone(delta?: number): KpiTone {
60
47
  return 'neutral'
61
48
  }
62
49
 
50
+ const cards = computed(() => {
51
+ const source = Array.isArray(props.items) ? props.items : []
52
+ return source.map((item, index) => ({
53
+ key: item.key ?? String(index),
54
+ item,
55
+ index,
56
+ tone: resolveTone(item.delta),
57
+ isLeading: index === 0,
58
+ }))
59
+ })
60
+
61
+ const gridClass = computed(() => (props.columns === 3 ? 'grid-cols-3' : 'grid-cols-2'))
62
+
63
63
  function formatDelta(delta?: number, unit = '') {
64
64
  if (delta === undefined || Number.isNaN(delta)) {
65
65
  return '--'
@@ -111,7 +111,7 @@ function requestSubscribe() {
111
111
  Dialog.alert({
112
112
  selector: '#t-dialog',
113
113
  title: '订阅消息',
114
- message: '请在 ability 页面配置订阅模板 ID 后再试。',
114
+ content: '请在 ability 页面配置订阅模板 ID 后再试。',
115
115
  context: mpContext as any,
116
116
  confirmBtn: '知道了',
117
117
  })
@@ -166,6 +166,7 @@ function navigateTo(url: string) {
166
166
  <view class="mt-[12rpx]">
167
167
  <t-cell-group>
168
168
  <t-cell title="组件实验室" note="subpackages/lab" arrow @tap="navigateTo('/subpackages/lab/index')" />
169
+ <t-cell title="Class 绑定实验室" note="subpackages/lab/class-binding" arrow @tap="navigateTo('/subpackages/lab/class-binding/index')" />
169
170
  <t-cell title="API 场景页" note="subpackages/ability" arrow @tap="navigateTo('/subpackages/ability/index')" />
170
171
  </t-cell-group>
171
172
  </view>
@@ -1,7 +1,9 @@
1
1
  <script setup lang="ts">
2
+ import type { UploadFile } from 'tdesign-miniprogram/upload/type'
3
+ import type { ModelBindingOptions, ModelBindingPayload } from 'wevu'
2
4
  import Toast from 'tdesign-miniprogram/toast/index'
3
5
 
4
- import { computed, getCurrentInstance, reactive, ref, watch } from 'wevu'
6
+ import { computed, getCurrentInstance, reactive, ref, useBindModel, watch } from 'wevu'
5
7
 
6
8
  import FormRow from '@/components/FormRow/index.vue'
7
9
  import FormStep from '@/components/FormStep/index.vue'
@@ -14,6 +16,11 @@ definePageJson({
14
16
  })
15
17
 
16
18
  const mpContext = getCurrentInstance()
19
+ const bindModel = useBindModel()
20
+
21
+ function changeModel<T, ValueProp extends string = 'value', Formatted = T>(path: string, options?: ModelBindingOptions<T, 'change', ValueProp, Formatted>): ModelBindingPayload<T, 'change', ValueProp, Formatted> {
22
+ return bindModel(path).model({ event: 'change', ...options })
23
+ }
17
24
 
18
25
  const steps = [
19
26
  { key: 'basic', title: '基础信息', subtitle: '业务基本配置' },
@@ -32,7 +39,7 @@ const formState = reactive({
32
39
  budget: 30,
33
40
  pace: 'balanced',
34
41
  description: '',
35
- attachments: [] as Array<{ url: string, name: string }>,
42
+ attachments: [] as UploadFile[],
36
43
  })
37
44
 
38
45
  const categories = [
@@ -85,6 +92,18 @@ watch(
85
92
  },
86
93
  )
87
94
 
95
+ const nameModel = changeModel<string>('formState.name')
96
+ const ownerModel = changeModel<string>('formState.owner')
97
+ const categoryModel = changeModel<string>('formState.category')
98
+ const urgentModel = changeModel<boolean>('formState.urgent')
99
+ const budgetModel = changeModel<number>('formState.budget')
100
+ const paceModel = changeModel<string>('formState.pace')
101
+ const descriptionModel = changeModel<string>('formState.description')
102
+ const attachmentsModel = changeModel<UploadFile[], 'files'>('formState.attachments', {
103
+ valueProp: 'files',
104
+ parser: event => event?.detail?.files ?? [],
105
+ })
106
+
88
107
  function showToast(message: string, theme: 'success' | 'warning' = 'success') {
89
108
  if (!mpContext) {
90
109
  return
@@ -118,10 +137,6 @@ function submit() {
118
137
  submitted.value = true
119
138
  showToast('提交成功')
120
139
  }
121
-
122
- function onUploadChange(e: WechatMiniprogram.CustomEvent<{ files: Array<{ url: string, name: string }> }>) {
123
- formState.attachments = e.detail.files
124
- }
125
140
  </script>
126
141
 
127
142
  <template>
@@ -147,24 +162,24 @@ function onUploadChange(e: WechatMiniprogram.CustomEvent<{ files: Array<{ url: s
147
162
  <FormRow label="项目名称">
148
163
  <t-input
149
164
  placeholder="例如:新客增长计划"
150
- :value="formState.name"
151
- @change="(e) => (formState.name = e.detail.value)"
165
+ :value="nameModel.value"
166
+ @change="nameModel.onChange"
152
167
  />
153
168
  </FormRow>
154
169
  <FormRow label="负责人">
155
170
  <t-input
156
171
  placeholder="例如:王凯"
157
- :value="formState.owner"
158
- @change="(e) => (formState.owner = e.detail.value)"
172
+ :value="ownerModel.value"
173
+ @change="ownerModel.onChange"
159
174
  />
160
175
  </FormRow>
161
176
  <FormRow label="类型">
162
- <t-radio-group :value="formState.category" @change="(e) => (formState.category = e.detail.value)">
177
+ <t-radio-group :value="categoryModel.value" @change="categoryModel.onChange">
163
178
  <t-radio v-for="item in categories" :key="item.value" :value="item.value" :label="item.label" />
164
179
  </t-radio-group>
165
180
  </FormRow>
166
181
  <FormRow label="加急">
167
- <t-switch :value="formState.urgent" @change="(e) => (formState.urgent = e.detail.value)" />
182
+ <t-switch :value="urgentModel.value" @change="urgentModel.onChange" />
168
183
  </FormRow>
169
184
  </view>
170
185
  </FormStep>
@@ -180,10 +195,10 @@ function onUploadChange(e: WechatMiniprogram.CustomEvent<{ files: Array<{ url: s
180
195
  <FormRow label="预算规模" description="10-100 万">
181
196
  <view class="flex items-center gap-[12rpx]">
182
197
  <t-slider
183
- :value="formState.budget"
198
+ :value="budgetModel.value"
184
199
  :min="10"
185
200
  :max="100"
186
- @change="(e) => (formState.budget = e.detail.value)"
201
+ @change="budgetModel.onChange"
187
202
  />
188
203
  <text class="text-[22rpx] text-[#5c5b7a]">
189
204
  {{ formState.budget }} 万
@@ -191,23 +206,23 @@ function onUploadChange(e: WechatMiniprogram.CustomEvent<{ files: Array<{ url: s
191
206
  </view>
192
207
  </FormRow>
193
208
  <FormRow label="推进节奏">
194
- <t-radio-group :value="formState.pace" @change="(e) => (formState.pace = e.detail.value)">
209
+ <t-radio-group :value="paceModel.value" @change="paceModel.onChange">
195
210
  <t-radio v-for="item in paceOptions" :key="item.value" :value="item.value" :label="item.label" />
196
211
  </t-radio-group>
197
212
  </FormRow>
198
213
  <FormRow label="补充说明">
199
214
  <t-textarea
200
215
  placeholder="描述目标与资源安排"
201
- :value="formState.description"
216
+ :value="descriptionModel.value"
202
217
  :maxlength="140"
203
- @change="(e) => (formState.description = e.detail.value)"
218
+ @change="descriptionModel.onChange"
204
219
  />
205
220
  </FormRow>
206
221
  <FormRow label="附件">
207
222
  <t-upload
208
- :files="formState.attachments"
223
+ :files="attachmentsModel.files"
209
224
  :max="3"
210
- @change="onUploadChange"
225
+ @change="attachmentsModel.onChange"
211
226
  />
212
227
  </FormRow>
213
228
  </view>
@@ -107,6 +107,16 @@ const quickActions = ref([
107
107
  path: '/subpackages/lab/index',
108
108
  type: 'sub',
109
109
  },
110
+ {
111
+ key: 'class-binding',
112
+ title: 'Class 绑定',
113
+ description: '对象/数组语法',
114
+ icon: 'grid-view',
115
+ tag: 'Vue',
116
+ tone: 'brand',
117
+ path: '/subpackages/lab/class-binding/index',
118
+ type: 'sub',
119
+ },
110
120
  {
111
121
  key: 'ability-lab',
112
122
  title: 'API 场景',
@@ -249,6 +259,47 @@ function onQuickAction(action: { path?: string, type?: 'tab' | 'sub', title: str
249
259
  />
250
260
  </view>
251
261
 
262
+ <view class="mt-[20rpx] rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
263
+ <view class="flex items-center justify-between">
264
+ <text class="text-[26rpx] font-semibold text-[#1f1a3f]">
265
+ Class 绑定示例
266
+ </text>
267
+ <t-tag size="small" theme="primary" variant="light">
268
+ 模板
269
+ </t-tag>
270
+ </view>
271
+ <view class="mt-[12rpx] flex flex-col gap-[12rpx]">
272
+ <view
273
+ class="rounded-[16rpx] px-[16rpx] py-[12rpx] text-[20rpx]"
274
+ :class="{
275
+ 'bg-[#eef2ff]': refreshSeed % 2 === 0,
276
+ 'text-[#1f1a3f]': refreshSeed % 2 === 0,
277
+ 'bg-[#fff7ed]': refreshSeed % 2 !== 0,
278
+ 'text-[#92400e]': refreshSeed % 2 !== 0,
279
+ 'ring-2 ring-[#6366f1]': refreshSeed % 3 === 0,
280
+ }"
281
+ >
282
+ 对象语法:根据刷新次数切换配色与高亮
283
+ </view>
284
+ <view
285
+ class="rounded-[16rpx] px-[16rpx] py-[12rpx] text-[20rpx]" :class="[
286
+ refreshSeed % 2 === 0 ? 'bg-[#ecfeff] text-[#0f766e]' : 'bg-[#fef2f2] text-[#991b1b]',
287
+ refreshSeed % 4 === 0
288
+ ? 'shadow-[0_10rpx_18rpx_rgba(15,118,110,0.18)]'
289
+ : 'shadow-[0_10rpx_18rpx_rgba(153,27,27,0.18)]',
290
+ ]"
291
+ >
292
+ 数组语法:组合静态与条件 class
293
+ </view>
294
+ <view
295
+ class="rounded-[16rpx] border border-[#e2e8f0] px-[16rpx] py-[12rpx] text-[20rpx]"
296
+ :class="refreshSeed % 2 === 0 ? 'bg-[#f8fafc] text-[#334155]' : 'bg-[#111827] text-white'"
297
+ >
298
+ class + :class 合并:静态边框叠加动态背景
299
+ </view>
300
+ </view>
301
+ </view>
302
+
252
303
  <view class="mt-[20rpx] rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
253
304
  <view class="flex items-center justify-between">
254
305
  <text class="text-[26rpx] font-semibold text-[#1f1a3f]">
@@ -0,0 +1,236 @@
1
+ <script setup lang="ts">
2
+ import { computed, reactive, ref, watch } from 'wevu'
3
+
4
+ import SectionTitle from '@/components/SectionTitle/index.vue'
5
+
6
+ definePageJson({
7
+ navigationBarTitleText: 'Class 绑定',
8
+ backgroundColor: '#f6f7fb',
9
+ })
10
+
11
+ const isActive = ref(true)
12
+ const hasError = ref(false)
13
+ const isRound = ref(false)
14
+ const isGhost = ref(false)
15
+
16
+ const classObject = reactive({
17
+ 'demo-active': true,
18
+ 'text-danger': false,
19
+ 'demo-round': false,
20
+ 'demo-ghost': false,
21
+ })
22
+
23
+ watch([isActive, hasError, isRound, isGhost], ([active, error, round, ghost]) => {
24
+ classObject['demo-active'] = active
25
+ classObject['text-danger'] = error
26
+ classObject['demo-round'] = round
27
+ classObject['demo-ghost'] = ghost
28
+ }, { immediate: true })
29
+
30
+ const activeClass = ref('demo-active')
31
+ const errorClass = ref('text-danger')
32
+ const roundClass = ref('demo-round')
33
+ const ghostClass = ref('demo-ghost')
34
+
35
+ const activeClassIf = computed(() => (isActive.value ? activeClass.value : ''))
36
+ const errorClassIf = computed(() => (hasError.value ? errorClass.value : ''))
37
+ const roundClassIf = computed(() => (isRound.value ? roundClass.value : ''))
38
+ const ghostClassIf = computed(() => (isGhost.value ? ghostClass.value : ''))
39
+ const dynamicKeyClass = computed(() => ({ [activeClass.value]: isActive.value }))
40
+ </script>
41
+
42
+ <template>
43
+ <view class="min-h-screen bg-[#f6f7fb] px-[28rpx] pb-[88rpx] pt-[24rpx] text-[#1c1c3c]">
44
+ <view class="rounded-[28rpx] bg-gradient-to-br from-[#eef2ff] via-[#ffffff] to-[#e0f2fe] p-[20rpx]">
45
+ <SectionTitle title="Class 绑定实验室" subtitle="切换状态观察 Vue 3 class 绑定效果" />
46
+ </view>
47
+
48
+ <view class="mt-[18rpx] rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
49
+ <SectionTitle title="状态控制" subtitle="开关影响所有示例" />
50
+ <view class="mt-[12rpx] grid grid-cols-2 gap-[12rpx]">
51
+ <view class="rounded-[16rpx] bg-[#f8fafc] p-[12rpx]">
52
+ <view class="flex items-center justify-between">
53
+ <text class="text-[22rpx] text-[#5c5b7a]">
54
+ Active
55
+ </text>
56
+ <t-switch :value="isActive" @change="(e) => (isActive = e.detail.value)" />
57
+ </view>
58
+ </view>
59
+ <view class="rounded-[16rpx] bg-[#f8fafc] p-[12rpx]">
60
+ <view class="flex items-center justify-between">
61
+ <text class="text-[22rpx] text-[#5c5b7a]">
62
+ Error
63
+ </text>
64
+ <t-switch :value="hasError" @change="(e) => (hasError = e.detail.value)" />
65
+ </view>
66
+ </view>
67
+ <view class="rounded-[16rpx] bg-[#f8fafc] p-[12rpx]">
68
+ <view class="flex items-center justify-between">
69
+ <text class="text-[22rpx] text-[#5c5b7a]">
70
+ Round
71
+ </text>
72
+ <t-switch :value="isRound" @change="(e) => (isRound = e.detail.value)" />
73
+ </view>
74
+ </view>
75
+ <view class="rounded-[16rpx] bg-[#f8fafc] p-[12rpx]">
76
+ <view class="flex items-center justify-between">
77
+ <text class="text-[22rpx] text-[#5c5b7a]">
78
+ Ghost
79
+ </text>
80
+ <t-switch :value="isGhost" @change="(e) => (isGhost = e.detail.value)" />
81
+ </view>
82
+ </view>
83
+ </view>
84
+ </view>
85
+
86
+ <view class="mt-[18rpx] space-y-[14rpx]">
87
+ <view class="rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
88
+ <SectionTitle title="对象语法" subtitle="状态驱动 class" />
89
+ <view class="mt-[12rpx] demo-block" :class="{ 'demo-active': isActive }">
90
+ <view>
91
+ <text class="block text-[24rpx] font-semibold">
92
+ Object Syntax
93
+ </text>
94
+ <text class="mt-[6rpx] block text-[20rpx] text-[#6f6b8a]">
95
+ active 触发高亮
96
+ </text>
97
+ </view>
98
+ <view class="demo-chip">
99
+ Obj
100
+ </view>
101
+ </view>
102
+ </view>
103
+
104
+ <view class="rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
105
+ <SectionTitle title="静态 + 对象" subtitle="静态 class + 动态对象" />
106
+ <view class="mt-[12rpx] demo-block demo-ghost" :class="{ 'demo-active': isActive, 'text-danger': hasError }">
107
+ <view>
108
+ <text class="block text-[24rpx] font-semibold">
109
+ Static + Object
110
+ </text>
111
+ <text class="mt-[6rpx] block text-[20rpx] text-[#6f6b8a]">
112
+ error 显示警示色
113
+ </text>
114
+ </view>
115
+ <view class="demo-chip">
116
+ Mix
117
+ </view>
118
+ </view>
119
+ </view>
120
+
121
+ <view class="rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
122
+ <SectionTitle title="响应式对象" subtitle="reactive classObject" />
123
+ <view class="mt-[12rpx] demo-block" :class="classObject">
124
+ <view>
125
+ <text class="block text-[24rpx] font-semibold">
126
+ Reactive Object
127
+ </text>
128
+ <text class="mt-[6rpx] block text-[20rpx] text-[#6f6b8a]">
129
+ 多状态合并控制
130
+ </text>
131
+ </view>
132
+ <view class="demo-chip">
133
+ Obj+
134
+ </view>
135
+ </view>
136
+ </view>
137
+
138
+ <view class="rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
139
+ <SectionTitle title="数组语法" subtitle="数组传入多个 class" />
140
+ <view class="mt-[12rpx] demo-block" :class="[activeClassIf, errorClassIf, roundClassIf]">
141
+ <view>
142
+ <text class="block text-[24rpx] font-semibold">
143
+ Array Syntax
144
+ </text>
145
+ <text class="mt-[6rpx] block text-[20rpx] text-[#6f6b8a]">
146
+ 组合多个 class
147
+ </text>
148
+ </view>
149
+ <view class="demo-chip">
150
+ Arr
151
+ </view>
152
+ </view>
153
+ </view>
154
+
155
+ <view class="rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
156
+ <SectionTitle title="数组条件" subtitle="条件判断决定 class" />
157
+ <view class="mt-[12rpx] demo-block" :class="[isActive ? activeClass : '', errorClassIf]">
158
+ <view>
159
+ <text class="block text-[24rpx] font-semibold">
160
+ Conditional Array
161
+ </text>
162
+ <text class="mt-[6rpx] block text-[20rpx] text-[#6f6b8a]">
163
+ 条件表达式返回 class
164
+ </text>
165
+ </view>
166
+ <view class="demo-chip">
167
+ Cond
168
+ </view>
169
+ </view>
170
+ </view>
171
+
172
+ <view class="rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
173
+ <SectionTitle title="数组 + 动态 key" subtitle="对象 + 字符串混合" />
174
+ <view class="mt-[12rpx] demo-block" :class="[dynamicKeyClass, errorClassIf, ghostClassIf]">
175
+ <view>
176
+ <text class="block text-[24rpx] font-semibold">
177
+ Array + Key
178
+ </text>
179
+ <text class="mt-[6rpx] block text-[20rpx] text-[#6f6b8a]">
180
+ 支持计算属性 key
181
+ </text>
182
+ </view>
183
+ <view class="demo-chip">
184
+ Key
185
+ </view>
186
+ </view>
187
+ </view>
188
+ </view>
189
+ </view>
190
+ </template>
191
+
192
+ <style scoped>
193
+ .demo-block {
194
+ display: flex;
195
+ align-items: center;
196
+ justify-content: space-between;
197
+ padding: 20rpx;
198
+ border: 2rpx solid #d7d9f2;
199
+ background: #ffffff;
200
+ color: #1f1a3f;
201
+ border-radius: 18rpx;
202
+ transition: all 0.2s ease;
203
+ }
204
+
205
+ .demo-chip {
206
+ padding: 6rpx 16rpx;
207
+ border-radius: 999rpx;
208
+ font-size: 18rpx;
209
+ border: 2rpx solid currentColor;
210
+ letter-spacing: 0.5rpx;
211
+ }
212
+
213
+ .demo-ghost {
214
+ background: #f8fafc;
215
+ border-style: dashed;
216
+ }
217
+
218
+ .demo-round {
219
+ border-radius: 999rpx;
220
+ }
221
+
222
+ .demo-active {
223
+ background: linear-gradient(135deg, #2563eb, #6366f1);
224
+ border-color: #1e40af;
225
+ color: #ffffff;
226
+ box-shadow: 0 18rpx 32rpx rgba(37, 99, 235, 0.35);
227
+ transform: translateY(-4rpx);
228
+ }
229
+
230
+ .text-danger {
231
+ background: #fff1f2;
232
+ border-color: #ef4444;
233
+ color: #b91c1c;
234
+ box-shadow: 0 18rpx 32rpx rgba(239, 68, 68, 0.2);
235
+ }
236
+ </style>
@@ -21,6 +21,12 @@ const tabs = [
21
21
  { value: 'feedback', label: '反馈' },
22
22
  { value: 'display', label: '展示' },
23
23
  ]
24
+
25
+ function navigateTo(url: string) {
26
+ wx.navigateTo({
27
+ url,
28
+ })
29
+ }
24
30
  </script>
25
31
 
26
32
  <template>
@@ -69,6 +75,14 @@ const tabs = [
69
75
  <t-avatar>U4</t-avatar>
70
76
  </t-avatar-group>
71
77
  </view>
78
+ <view class="rounded-[18rpx] bg-[#f7f7fb] p-[16rpx]">
79
+ <SectionTitle title="Vue 模板语法" subtitle="class 绑定、对象/数组语法" />
80
+ <view class="mt-[8rpx]">
81
+ <t-cell-group>
82
+ <t-cell title="Class 绑定实验室" note="子包:/subpackages/lab/class-binding" arrow @tap="navigateTo('/subpackages/lab/class-binding/index')" />
83
+ </t-cell-group>
84
+ </view>
85
+ </view>
72
86
  </view>
73
87
 
74
88
  <view v-else-if="activeTab === 'feedback'" class="space-y-[14rpx]">
@@ -1,5 +1,4 @@
1
1
  /// <reference types="weapp-vite/client" />
2
- /// <reference types="@vue/runtime-core" />
3
2
  /// <reference types="wevu" />
4
3
  /// <reference path="../components.d.ts" />
5
4
  /// <reference path="../typed-components.d.ts" />
@@ -16,6 +16,9 @@
16
16
  "@/*": [
17
17
  "./src/*"
18
18
  ],
19
+ "weapp-vite/typed-components": [
20
+ "./typed-components.d.ts"
21
+ ],
19
22
  "tdesign-miniprogram/miniprogram_dist/*": [
20
23
  "./node_modules/tdesign-miniprogram/miniprogram_dist/*"
21
24
  ],
@@ -25,9 +28,7 @@
25
28
  },
26
29
  "resolveJsonModule": true,
27
30
  "types": [
28
- "miniprogram-api-typings",
29
- "vue",
30
- "@vue/runtime-core"
31
+ "miniprogram-api-typings"
31
32
  ],
32
33
  "allowImportingTsExtensions": true,
33
34
  "allowJs": true,
@@ -47,7 +48,8 @@
47
48
  "vueCompilerOptions": {
48
49
  "plugins": [
49
50
  "weapp-vite/volar"
50
- ]
51
+ ],
52
+ "lib": "wevu"
51
53
  },
52
54
  "include": [
53
55
  "src/**/*.ts",
@@ -935,9 +935,8 @@ declare module 'weapp-vite/typed-components' {
935
935
  readonly y?: number;
936
936
  readonly zIndex?: number;
937
937
  };
938
- [component: string]: Record<string, any>;
939
938
  }
940
939
  export type ComponentPropName = keyof ComponentProps;
941
- export type ComponentProp<Name extends ComponentPropName> = ComponentProps[Name];
940
+ export type ComponentProp<Name extends string> = Name extends ComponentPropName ? ComponentProps[Name] : Record<string, any>;
942
941
  export const componentProps: ComponentProps;
943
942
  }
@@ -7,8 +7,10 @@ export default defineConfig({
7
7
  srcRoot: 'src',
8
8
  autoImportComponents: {
9
9
  resolvers: [TDesignResolver()],
10
+ htmlCustomData: true,
10
11
  typedComponents: true,
11
12
  vueComponents: true,
13
+ vueComponentsModule: 'wevu',
12
14
  },
13
15
  wevu: {
14
16
  defaults: {