useListItemClick.js
6.08 KB
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/**
* 统一的列表项点击处理 Composable
*
* @description 根据列表类型和上下文,智能处理列表项的点击行为
* 支持文件预览、页面跳转、弹窗显示等多种交互模式
*
* @author Claude Code
* @date 2026-01-31
*/
import { useGo } from '@/hooks/useGo'
import { useFileOperation } from './useFileOperation'
/**
* 列表类型枚举
*
* @description 定义不同列表的点击行为类型
* @enum {string}
*/
export const ListType = {
/** 文件列表 - 点击打开文件预览 */
FILE: 'file',
/** 产品列表 - 点击跳转产品详情 */
PRODUCT: 'product',
/** 搜索结果 - 根据类型智能路由 */
SEARCH: 'search',
/** 帮助中心 - 点击显示弹窗 */
HELP: 'help',
/** 收藏列表 - 点击打开文件 + 长按删除 */
FAVORITE: 'favorite'
}
/**
* 列表项点击处理 Hook
*
* @param {Object} options - 配置选项
* @param {string} options.listType - 列表类型(使用 ListType 枚举)
* @param {Function} [options.onBeforeClick] - 点击前的回调函数,返回 false 可阻止默认行为
* @param {Function} [options.onAfterClick] - 点击后的回调函数
* @returns {Object} 点击处理方法
*
* @example
* // 文件列表
* const { handleClick } = useListItemClick({ listType: ListType.FILE })
*
* // 产品列表
* const { handleClick } = useListItemClick({
* listType: ListType.PRODUCT,
* onAfterClick: (item) => console.log('Viewed product:', item.id)
* })
*
* // 自定义逻辑
* const { handleClick } = useListItemClick({
* listType: ListType.FILE,
* onBeforeClick: (item) => {
* if (!item.hasPermission) {
* Taro.showToast({ title: '无权限', icon: 'none' })
* return false
* }
* }
* })
*/
export function useListItemClick(options = {}) {
const { listType = ListType.FILE, onBeforeClick, onAfterClick } = options
const go = useGo()
const { viewFile } = useFileOperation()
/**
* 处理文件列表项点击
*
* @description 打开文件预览
* @async
* @param {Object} item - 列表项数据
* @param {string} item.downloadUrl - 文件下载地址
* @param {string} item.fileName - 文件名
*/
const handleFileClick = async (item) => {
await viewFile(item)
}
/**
* 处理产品列表项点击
*
* @description 跳转到产品详情页
* @param {Object} item - 列表项数据
* @param {number|string} item.id - 产品ID
*/
const handleProductClick = (item) => {
if (!item.id) {
console.warn('Product item missing id:', item)
return
}
go('/pages/product-detail/index', { id: item.id })
}
/**
* 处理搜索结果项点击
*
* @description 根据搜索结果类型智能路由
* @param {Object} item - 列表项数据
* @param {string} item.type - 结果类型(product/material/course等)
* @param {number|string} item.id - 资源ID
*/
const handleSearchClick = (item) => {
const { type, id } = item
if (!type) {
console.warn('Search item missing type:', item)
return
}
// 根据类型路由到不同页面
switch (type) {
case 'product':
if (id) go('/pages/product-detail/index', { id })
break
case 'material':
if (item.downloadUrl) {
viewFile(item)
} else if (id) {
go('/pages/material-detail/index', { id })
}
break
case 'course':
if (id) go('/pages/course-detail/index', { id })
break
default:
console.warn('Unknown search result type:', type)
}
}
/**
* 处理帮助中心项点击
*
* @description 显示帮助内容弹窗
* @param {Object} item - 列表项数据
* @param {string} item.title - 帮助标题
* @param {string} item.content - 帮助内容
*/
const handleHelpClick = (item) => {
if (!item.title && !item.content) {
console.warn('Help item missing content:', item)
return
}
// 这里需要引入 Taro 的 showModal
// 实际使用时从 @tarojs/taro 引入
import('@tarojs/taro').then(({ showModal }) => {
showModal({
title: item.title || '提示',
content: item.content || '暂无内容',
showCancel: false,
confirmText: '我知道了'
})
})
}
/**
* 统一的点击处理函数
*
* @description 根据列表类型分发到不同的处理逻辑
* @async
* @param {Object} item - 列表项数据
* @param {Object} [event] - 点击事件对象(可选,用于阻止事件冒泡)
*
* @example
* // 在模板中使用
* <view @click="handleClick(item)">点击我</view>
*
* // 阻止事件冒泡
* <view @click.stop="handleClick(item)">点击我</view>
*/
const handleClick = async (item, event) => {
// 执行点击前回调
if (onBeforeClick) {
const shouldContinue = await onBeforeClick(item)
if (shouldContinue === false) {
return
}
}
// 根据列表类型处理点击
switch (listType) {
case ListType.FILE:
await handleFileClick(item)
break
case ListType.PRODUCT:
handleProductClick(item)
break
case ListType.SEARCH:
handleSearchClick(item)
break
case ListType.HELP:
handleHelpClick(item)
break
case ListType.FAVORITE:
// 收藏列表默认也是打开文件
await handleFileClick(item)
break
default:
console.warn('Unknown list type:', listType)
}
// 执行点击后回调
if (onAfterClick) {
onAfterClick(item)
}
}
/**
* 处理收藏操作(独立的收藏功能)
*
* @description 用于列表项中的收藏按钮点击
* @param {Object} item - 列表项数据
* @param {boolean} item.collected - 是否已收藏
* @param {Function} [onToggle] - 自定义收藏切换回调
*/
const handleFavorite = (item, onToggle) => {
// 切换收藏状态
if (onToggle) {
onToggle(item)
} else {
// 默认行为:直接切换状态
item.collected = !item.collected
}
}
return {
handleClick,
handleFavorite
}
}