update at 2026-02-08 18:28:39
This commit is contained in:
144
miniprogram/pages/font-picker/index.js
Normal file
144
miniprogram/pages/font-picker/index.js
Normal file
@@ -0,0 +1,144 @@
|
||||
const { loadFontsManifest, listCategories } = require('../../utils/mp/font-loader')
|
||||
const { loadFavorites, saveFavorites } = require('../../utils/mp/storage')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
fonts: [],
|
||||
filteredFonts: [],
|
||||
categories: ['全部'],
|
||||
categoryIndex: 0,
|
||||
favoriteOnly: false,
|
||||
favorites: [],
|
||||
searchText: '',
|
||||
selectedFontId: '',
|
||||
},
|
||||
|
||||
async onLoad(options) {
|
||||
const selectedFontId = options && options.selected ? decodeURIComponent(options.selected) : ''
|
||||
this.setData({ selectedFontId })
|
||||
|
||||
wx.showLoading({ title: '加载字体中', mask: true })
|
||||
try {
|
||||
const favorites = loadFavorites()
|
||||
const fonts = await loadFontsManifest()
|
||||
const categories = listCategories(fonts)
|
||||
|
||||
this.fontMap = new Map(fonts.map((font) => [font.id, font]))
|
||||
|
||||
this.setData({
|
||||
fonts,
|
||||
categories,
|
||||
favorites,
|
||||
})
|
||||
|
||||
this.applyFilter()
|
||||
} catch (error) {
|
||||
wx.showToast({ title: '字体加载失败', icon: 'none' })
|
||||
} finally {
|
||||
wx.hideLoading()
|
||||
}
|
||||
},
|
||||
|
||||
applyFilter() {
|
||||
const {
|
||||
fonts,
|
||||
favorites,
|
||||
searchText,
|
||||
categories,
|
||||
categoryIndex,
|
||||
favoriteOnly,
|
||||
} = this.data
|
||||
|
||||
const keyword = String(searchText || '').trim().toLowerCase()
|
||||
const selectedCategory = categories[categoryIndex] || '全部'
|
||||
const favoriteSet = new Set(favorites)
|
||||
|
||||
const filteredFonts = fonts
|
||||
.filter((font) => {
|
||||
if (favoriteOnly && !favoriteSet.has(font.id)) {
|
||||
return false
|
||||
}
|
||||
if (selectedCategory !== '全部' && selectedCategory !== '收藏' && font.category !== selectedCategory) {
|
||||
return false
|
||||
}
|
||||
if (selectedCategory === '收藏' && !favoriteSet.has(font.id)) {
|
||||
return false
|
||||
}
|
||||
if (!keyword) {
|
||||
return true
|
||||
}
|
||||
return (
|
||||
String(font.name || '').toLowerCase().includes(keyword) ||
|
||||
String(font.category || '').toLowerCase().includes(keyword)
|
||||
)
|
||||
})
|
||||
.map((font) => ({
|
||||
...font,
|
||||
isFavorite: favoriteSet.has(font.id),
|
||||
}))
|
||||
|
||||
this.setData({ filteredFonts })
|
||||
},
|
||||
|
||||
onSearchInput(event) {
|
||||
this.setData({ searchText: event.detail.value || '' })
|
||||
this.applyFilter()
|
||||
},
|
||||
|
||||
onCategoryChange(event) {
|
||||
this.setData({ categoryIndex: Number(event.detail.value) || 0 })
|
||||
this.applyFilter()
|
||||
},
|
||||
|
||||
onToggleFavoriteOnly() {
|
||||
this.setData({ favoriteOnly: !this.data.favoriteOnly })
|
||||
this.applyFilter()
|
||||
},
|
||||
|
||||
onToggleFavorite(event) {
|
||||
const fontId = event.currentTarget.dataset.fontId
|
||||
if (!fontId) {
|
||||
return
|
||||
}
|
||||
|
||||
const next = new Set(this.data.favorites)
|
||||
if (next.has(fontId)) {
|
||||
next.delete(fontId)
|
||||
} else {
|
||||
next.add(fontId)
|
||||
}
|
||||
|
||||
const favorites = saveFavorites(Array.from(next))
|
||||
this.setData({ favorites })
|
||||
this.applyFilter()
|
||||
},
|
||||
|
||||
onSelectFont(event) {
|
||||
const fontId = event.currentTarget.dataset.fontId
|
||||
if (!fontId) {
|
||||
return
|
||||
}
|
||||
this.setData({ selectedFontId: fontId })
|
||||
},
|
||||
|
||||
onCancel() {
|
||||
wx.navigateBack()
|
||||
},
|
||||
|
||||
onConfirm() {
|
||||
const { selectedFontId } = this.data
|
||||
if (!selectedFontId) {
|
||||
wx.showToast({ title: '请选择字体', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
const font = this.fontMap ? this.fontMap.get(selectedFontId) : null
|
||||
const eventChannel = this.getOpenerEventChannel()
|
||||
eventChannel.emit('fontSelected', {
|
||||
fontId: selectedFontId,
|
||||
font,
|
||||
})
|
||||
|
||||
wx.navigateBack()
|
||||
},
|
||||
})
|
||||
3
miniprogram/pages/font-picker/index.json
Normal file
3
miniprogram/pages/font-picker/index.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"navigationBarTitleText": "选择字体"
|
||||
}
|
||||
53
miniprogram/pages/font-picker/index.wxml
Normal file
53
miniprogram/pages/font-picker/index.wxml
Normal file
@@ -0,0 +1,53 @@
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<input
|
||||
class="search-input"
|
||||
placeholder="搜索字体名称"
|
||||
value="{{searchText}}"
|
||||
bindinput="onSearchInput"
|
||||
/>
|
||||
|
||||
<view class="toolbar row space-between">
|
||||
<picker mode="selector" range="{{categories}}" value="{{categoryIndex}}" bindchange="onCategoryChange">
|
||||
<view class="picker-btn">分类:{{categories[categoryIndex]}}</view>
|
||||
</picker>
|
||||
<button class="mini-btn" size="mini" bindtap="onToggleFavoriteOnly">
|
||||
{{favoriteOnly ? '仅收藏中' : '全部字体'}}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card list-card">
|
||||
<view class="summary">共 {{filteredFonts.length}} 个字体</view>
|
||||
<scroll-view class="font-list" scroll-y>
|
||||
<view
|
||||
wx:for="{{filteredFonts}}"
|
||||
wx:key="id"
|
||||
class="font-item {{item.id === selectedFontId ? 'selected' : ''}}"
|
||||
bindtap="onSelectFont"
|
||||
data-font-id="{{item.id}}"
|
||||
>
|
||||
<view class="font-info">
|
||||
<view class="font-name">{{item.name}}</view>
|
||||
<view class="font-meta">{{item.category}}</view>
|
||||
</view>
|
||||
<view class="actions row">
|
||||
<view
|
||||
class="star"
|
||||
catchtap="onToggleFavorite"
|
||||
data-font-id="{{item.id}}"
|
||||
>
|
||||
{{item.isFavorite ? '★' : '☆'}}
|
||||
</view>
|
||||
<view wx:if="{{item.id === selectedFontId}}" class="selected-tag">已选</view>
|
||||
</view>
|
||||
</view>
|
||||
<view wx:if="{{!filteredFonts.length}}" class="empty">没有匹配字体</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<view class="footer row space-between">
|
||||
<button class="btn-secondary" bindtap="onCancel">取消</button>
|
||||
<button class="btn-primary" bindtap="onConfirm">使用该字体</button>
|
||||
</view>
|
||||
</view>
|
||||
102
miniprogram/pages/font-picker/index.wxss
Normal file
102
miniprogram/pages/font-picker/index.wxss
Normal file
@@ -0,0 +1,102 @@
|
||||
.search-input {
|
||||
background: #f6f8fc;
|
||||
border-radius: 12rpx;
|
||||
padding: 18rpx 20rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
.picker-btn {
|
||||
background: #f6f8fc;
|
||||
border-radius: 12rpx;
|
||||
padding: 14rpx 16rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.mini-btn {
|
||||
margin: 0;
|
||||
height: 56rpx;
|
||||
line-height: 56rpx;
|
||||
background: #edf2ff;
|
||||
color: #274c95;
|
||||
}
|
||||
|
||||
.list-card {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.summary {
|
||||
padding: 18rpx 22rpx;
|
||||
color: #6b7280;
|
||||
font-size: 24rpx;
|
||||
border-bottom: 1rpx solid #f0f2f7;
|
||||
}
|
||||
|
||||
.font-list {
|
||||
height: calc(100vh - 410rpx);
|
||||
}
|
||||
|
||||
.font-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 18rpx 22rpx;
|
||||
border-bottom: 1rpx solid #f2f3f8;
|
||||
}
|
||||
|
||||
.font-item.selected {
|
||||
background: #eef5ff;
|
||||
}
|
||||
|
||||
.font-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.font-meta {
|
||||
margin-top: 6rpx;
|
||||
font-size: 22rpx;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.actions {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.star {
|
||||
font-size: 36rpx;
|
||||
color: #f59e0b;
|
||||
width: 56rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.selected-tag {
|
||||
background: #1677ff;
|
||||
color: #fff;
|
||||
border-radius: 999rpx;
|
||||
font-size: 20rpx;
|
||||
padding: 6rpx 14rpx;
|
||||
}
|
||||
|
||||
.empty {
|
||||
color: #9ca3af;
|
||||
text-align: center;
|
||||
padding: 60rpx 0;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
left: 24rpx;
|
||||
right: 24rpx;
|
||||
bottom: 24rpx;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.footer button {
|
||||
flex: 1;
|
||||
height: 84rpx;
|
||||
line-height: 84rpx;
|
||||
}
|
||||
Reference in New Issue
Block a user