index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. <template>
  2. <view class="content">
  3. <!-- 标题区域 -->
  4. <view class="demo-header">
  5. <text class="demo-title">自定义选择器演示</text>
  6. <text class="demo-subtitle">CustomPicker Component Examples</text>
  7. </view>
  8. <!-- 演示按钮区域 -->
  9. <view class="demo-buttons">
  10. <view class="button-row">
  11. <button class="demo-btn primary" @tap="showCityPicker">
  12. <text class="btn-icon">🏙️</text>
  13. <text class="btn-text">城市选择(单选)</text>
  14. </button>
  15. <button class="demo-btn success" @tap="showHobbyPicker">
  16. <text class="btn-icon">🎯</text>
  17. <text class="btn-text">兴趣选择(多选)</text>
  18. </button>
  19. </view>
  20. <view class="button-row">
  21. <button class="demo-btn info" @tap="showUserPicker">
  22. <text class="btn-icon">👤</text>
  23. <text class="btn-text">用户选择(自定义字段)</text>
  24. </button>
  25. <button class="demo-btn warning" @tap="showSimplePicker">
  26. <text class="btn-icon">✅</text>
  27. <text class="btn-text">简单选择(无搜索)</text>
  28. </button>
  29. </view>
  30. </view>
  31. <!-- 结果显示区域 -->
  32. <view class="result-container" v-if="lastResult">
  33. <view class="result-header">
  34. <text class="result-title">最新选择结果</text>
  35. <text class="result-type">[{{ currentPickerType }}]</text>
  36. </view>
  37. <view class="result-content">
  38. <text class="result-text">{{ formatResult(lastResult) }}</text>
  39. </view>
  40. </view>
  41. <!-- 自定义选择器组件 -->
  42. <customPicker
  43. :visible="pickerVisible"
  44. :title="pickerConfig.title"
  45. :options="pickerConfig.options"
  46. :displayKey="pickerConfig.displayKey"
  47. :valueKey="pickerConfig.valueKey"
  48. :multiple="pickerConfig.multiple"
  49. :searchable="pickerConfig.searchable"
  50. :value="pickerConfig.value"
  51. @confirm="handleConfirm"
  52. @cancel="handleCancel"
  53. />
  54. </view>
  55. </template>
  56. <script>
  57. import customPicker from './customPicker.vue'
  58. export default {
  59. components:{
  60. customPicker
  61. },
  62. data() {
  63. return {
  64. // 选择器显示状态
  65. pickerVisible: false,
  66. // 当前选择器类型
  67. currentPickerType: '',
  68. // 最新选择结果
  69. lastResult: null,
  70. // 选择器配置
  71. pickerConfig: {
  72. title: '请选择',
  73. options: [],
  74. displayKey: 'label',
  75. valueKey: 'value',
  76. multiple: false,
  77. searchable: true,
  78. value: ''
  79. },
  80. // 城市选项数据
  81. cityOptions: [
  82. { label: '北京', value: 'beijing', code: 'BJ' },
  83. { label: '上海', value: 'shanghai', code: 'SH' },
  84. { label: '深圳', value: 'shenzhen', code: 'SZ' },
  85. { label: '广州', value: 'guangzhou', code: 'GZ' },
  86. { label: '杭州', value: 'hangzhou', code: 'HZ' },
  87. { label: '成都', value: 'chengdu', code: 'CD' },
  88. { label: '西安', value: 'xian', code: 'XA' },
  89. { label: '武汉', value: 'wuhan', code: 'WH' },
  90. { label: '南京', value: 'nanjing', code: 'NJ' },
  91. { label: '重庆', value: 'chongqing', code: 'CQ' }
  92. ],
  93. // 兴趣爱好选项数据
  94. hobbyOptions: [
  95. { label: '阅读', value: 'reading' },
  96. { label: '旅行', value: 'travel' },
  97. { label: '摄影', value: 'photography' },
  98. { label: '音乐', value: 'music' },
  99. { label: '运动', value: 'sports' },
  100. { label: '绘画', value: 'painting' },
  101. { label: '烹饪', value: 'cooking' },
  102. { label: '游戏', value: 'gaming' },
  103. { label: '电影', value: 'movies' },
  104. { label: '编程', value: 'programming' }
  105. ],
  106. // 用户选项数据(自定义字段)
  107. userOptions: [
  108. { name: '张三', id: 'user001', department: '技术部', email: 'zhangsan@example.com' },
  109. { name: '李四', id: 'user002', department: '产品部', email: 'lisi@example.com' },
  110. { name: '王五', id: 'user003', department: '设计部', email: 'wangwu@example.com' },
  111. { name: '赵六', id: 'user004', department: '运营部', email: 'zhaoliu@example.com' },
  112. { name: '钱七', id: 'user005', department: '市场部', email: 'qianqi@example.com' }
  113. ],
  114. // 简单选项数据
  115. simpleOptions: [
  116. { label: '是', value: true },
  117. { label: '否', value: false }
  118. ]
  119. }
  120. },
  121. methods: {
  122. // 显示城市选择器
  123. showCityPicker() {
  124. this.currentPickerType = '城市选择'
  125. this.pickerConfig = {
  126. title: '选择城市',
  127. options: this.cityOptions,
  128. displayKey: 'label',
  129. valueKey: 'value',
  130. multiple: false,
  131. searchable: true,
  132. value: ''
  133. }
  134. this.pickerVisible = true
  135. },
  136. // 显示兴趣爱好选择器(多选)
  137. showHobbyPicker() {
  138. this.currentPickerType = '兴趣选择'
  139. this.pickerConfig = {
  140. title: '选择兴趣爱好',
  141. options: this.hobbyOptions,
  142. displayKey: 'label',
  143. valueKey: 'value',
  144. multiple: true,
  145. searchable: true,
  146. value: []
  147. }
  148. this.pickerVisible = true
  149. },
  150. // 显示用户选择器(自定义字段)
  151. showUserPicker() {
  152. this.currentPickerType = '用户选择'
  153. this.pickerConfig = {
  154. title: '选择用户',
  155. options: this.userOptions,
  156. displayKey: 'name',
  157. valueKey: 'id',
  158. multiple: false,
  159. searchable: true,
  160. value: ''
  161. }
  162. this.pickerVisible = true
  163. },
  164. // 显示简单选择器(无搜索)
  165. showSimplePicker() {
  166. this.currentPickerType = '简单选择'
  167. this.pickerConfig = {
  168. title: '确认操作',
  169. options: this.simpleOptions,
  170. displayKey: 'label',
  171. valueKey: 'value',
  172. multiple: false,
  173. searchable: false,
  174. value: ''
  175. }
  176. this.pickerVisible = true
  177. },
  178. // 处理确认选择
  179. handleConfirm(result) {
  180. this.lastResult = result
  181. console.log(`${this.currentPickerType}结果:`, result)
  182. this.pickerVisible = false
  183. },
  184. // 处理取消选择
  185. handleCancel() {
  186. console.log('取消选择')
  187. this.pickerVisible = false
  188. },
  189. // 格式化结果显示
  190. formatResult(result) {
  191. if (!result) return ''
  192. if (result.selectedItems) {
  193. // 多选结果
  194. const items = result.selectedItems.map(item =>
  195. item[this.pickerConfig.displayKey] || item.label || item.name || item
  196. ).join('、')
  197. return `已选择 ${result.selectedItems.length} 项:${items}`
  198. } else {
  199. // 单选结果
  200. const itemText = result.selectedItem
  201. ? (result.selectedItem[this.pickerConfig.displayKey] || result.selectedItem.label || result.selectedItem.name || result.selectedItem)
  202. : result.selectedValue
  203. return `已选择:${itemText}`
  204. }
  205. }
  206. }
  207. }
  208. </script>
  209. <style lang="scss">
  210. .content {
  211. display: flex;
  212. flex-direction: column;
  213. align-items: center;
  214. justify-content: flex-start;
  215. min-height: 100vh;
  216. background: #11998e;
  217. padding: 40rpx 30rpx;
  218. }
  219. // 演示标题区域
  220. .demo-header {
  221. text-align: center;
  222. margin-bottom: 60rpx;
  223. .demo-title {
  224. display: block;
  225. font-size: 48rpx;
  226. font-weight: 700;
  227. color: #fff;
  228. margin-bottom: 16rpx;
  229. text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.2);
  230. }
  231. .demo-subtitle {
  232. display: block;
  233. font-size: 24rpx;
  234. color: rgba(255, 255, 255, 0.8);
  235. letter-spacing: 2rpx;
  236. }
  237. }
  238. // 按钮区域
  239. .demo-buttons {
  240. width: 100%;
  241. max-width: 680rpx;
  242. margin-bottom: 60rpx;
  243. .button-row {
  244. display: flex;
  245. justify-content: space-between;
  246. margin-bottom: 30rpx;
  247. gap: 20rpx;
  248. &:last-child {
  249. margin-bottom: 0;
  250. }
  251. }
  252. .demo-btn {
  253. flex: 1;
  254. background: #fff;
  255. border: none;
  256. border-radius: 24rpx;
  257. padding: 40rpx 20rpx;
  258. display: flex;
  259. flex-direction: column;
  260. align-items: center;
  261. justify-content: center;
  262. box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.15);
  263. transition: all 0.3s ease;
  264. min-height: 160rpx;
  265. position: relative;
  266. overflow: hidden;
  267. &::before {
  268. content: '';
  269. position: absolute;
  270. top: 0;
  271. left: 0;
  272. right: 0;
  273. bottom: 0;
  274. background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.1), transparent);
  275. transform: translateX(-100%);
  276. transition: transform 0.6s ease;
  277. }
  278. &:active {
  279. transform: translateY(2rpx);
  280. box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.2);
  281. &::before {
  282. transform: translateX(100%);
  283. }
  284. }
  285. .btn-icon {
  286. font-size: 40rpx;
  287. margin-bottom: 16rpx;
  288. display: block;
  289. }
  290. .btn-text {
  291. font-size: 24rpx;
  292. color: #333;
  293. font-weight: 500;
  294. text-align: center;
  295. line-height: 1.4;
  296. }
  297. &.primary {
  298. background: linear-gradient(135deg, #667eea, #764ba2);
  299. .btn-text {
  300. color: #fff;
  301. }
  302. }
  303. &.success {
  304. background: linear-gradient(135deg, #11998e, #38ef7d);
  305. .btn-text {
  306. color: #fff;
  307. }
  308. }
  309. &.info {
  310. background: linear-gradient(135deg, #3498db, #2980b9);
  311. .btn-text {
  312. color: #fff;
  313. }
  314. }
  315. &.warning {
  316. background: linear-gradient(135deg, #f39c12, #d35400);
  317. .btn-text {
  318. color: #fff;
  319. }
  320. }
  321. }
  322. }
  323. // 结果显示区域
  324. .result-container {
  325. width: 100%;
  326. max-width: 680rpx;
  327. background: #fff;
  328. border-radius: 24rpx;
  329. padding: 40rpx;
  330. box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.15);
  331. margin-bottom: 40rpx;
  332. .result-header {
  333. display: flex;
  334. align-items: center;
  335. justify-content: space-between;
  336. margin-bottom: 24rpx;
  337. .result-title {
  338. font-size: 32rpx;
  339. font-weight: 600;
  340. color: #333;
  341. }
  342. .result-type {
  343. font-size: 24rpx;
  344. color: #12b792;
  345. background: rgba(18, 183, 146, 0.1);
  346. padding: 8rpx 16rpx;
  347. border-radius: 12rpx;
  348. font-weight: 500;
  349. }
  350. }
  351. .result-content {
  352. .result-text {
  353. font-size: 28rpx;
  354. color: #666;
  355. line-height: 1.6;
  356. display: block;
  357. }
  358. }
  359. }
  360. // 移除原有的不必要样式
  361. .logo {
  362. display: none;
  363. }
  364. .text-area {
  365. display: none;
  366. }
  367. .title {
  368. display: none;
  369. }
  370. </style>