馃攳缁欐垜鐨勫皬绋嬪簭鍔犱簡涓笣婊戠殑鎼滅储鍔熻兘锛岃俯鍧戣〃鎯呭寘闀垮害闂 oil娆у摕 2024-12-10 343 闃呰8鍒嗛挓 鍓嶈█ 鏈�杩戝湪鐢ㄨ嚜宸辩殑鍗$洅灏忕▼搴忕殑鏃跺�欙紝鍙戠幇鍗$墖瓒婃潵瓒婂锛屾湁鏃跺�欒鎵惧埌鏌愪竴寮犳潵鐪嬬湅绗旇瑕佹壘鍗婂ぉ锛屼簬鏄嚜宸卞仛浜嗕竴涓悳绱㈠姛鑳斤紝鍏堢湅鏁堟灉锛�/p> 鎬庝箞鏍凤紝鏄笉鏄繕鎸轰笉閿欑殑锛岄偅涔堣繖绡囨枃绔犲氨璁茶杩欐牱涓�涓悳绱㈠睍绀虹殑鍔熻兘鏄浣曞疄鐜扮殑銆�/p> 浠g爜瀹炵幇 棣栧厛鎴戜滑鍒嗘瀽杩欎釜鎼滅储鍔熻兘鍖呭惈鍝簺闇�瑕佸疄鐜扮殑鐐癸細 杈撳叆鍏抽敭瀛楋紝鍖归厤瀵瑰簲鐨勫崱鐗囧睍绀�/li> 鍖归厤鐨勫崱鐗囦笂闈紝瑕佹妸绗﹀悎鎼滅储鏉′欢鐨勬墍鏈夎瘝缁欓珮浜睍绀哄嚭鏉ワ紝涓嶇劧鏂囨湰澶氱殑鏃跺�欏鏄撶湅鑺变簡銆�/li> 鐐瑰嚮鍖归厤鍒扮殑鍗$墖锛岃璺宠浆鍒板崱鐗囩殑浣嶇疆锛屽苟涓旈棯鐑佷袱涓嬶紝杩欐牱涓�鐪嬪氨鐭ラ亾瑕佹壘鍗$墖鍦ㄥ摢浜嗐��/li> 鍒嗘瀽瀹屾垚鍚庯紝鎴戜滑涓�鐐逛竴鐐瑰疄鐜般��/p> 鍖归厤鍏抽敭瀛�/h3> 鎴戠殑灏忕▼搴忕洰鍓嶆槸绾墠绔悳绱㈢殑锛屽彧鏄洰鍓嶆槸杩欐牱锛屾墍浠ユ悳绱㈤�昏緫涔熸槸鍦ㄥ墠绔疄鐜般�傛悳绱㈤�昏緫濡傛灉绠�鍗曞疄鐜扮殑璇濆氨鏄皢鎼滅储妗嗙殑鍐呭涓庡垪琛ㄤ腑鐨勬瘡涓�椤硅繘琛屽姣旓紝鐪嬬湅鍐呭涓湁娌℃湁鍖呭惈杩欎釜瀛楃涓茬殑锛屽鏋滄湁灏辨妸杩欎釜椤圭粰杩斿洖鍥炲幓銆�/p> 鍏堢湅浠g爜锛�/p> const onSearch = () => { // 妫�鏌ユ悳绱㈡枃鏈鏄惁鏈夊��/span> if (searchText.value) { // 鍒涘缓涓�涓鍒欒〃杈惧紡瀵硅薄锛岀敤浜庡湪鍗$墖鍐呭涓悳绱㈡枃鏈�/span> // 'giu' 鏍囧織琛ㄧず鍏ㄥ眬鎼滅储銆佷笉鍖哄垎澶у皬鍐欏拰鏀寔 Unicode const searchTextRegex = new RegExp(searchText.value, 'giu') // 閬嶅巻鎵�鏈夌殑鍗$墖鐩掑瓙 const matchCardBox = cardDataStore.cardBoxList.map((cardBox) => { // 瀵规瘡涓崱鐗囩洅瀛愶紝鍒涘缓涓�涓柊瀵硅薄锛屽寘鍚師濮嬪睘鎬у拰淇敼鍚庣殑鍗$墖椤圭洰 return { ...cardBox, // 鏄犲皠骞惰繃婊ゅ崱鐗囬」鐩紝鍙繚鐣欏尮閰嶆悳绱㈡枃鏈殑椤圭洰 cardItems: cardBox.cardItems .map((cardItem) => { // 鍒濆鍖栧墠闈㈠拰鑳岄潰鍐呭鐨勫尮閰嶆暟缁�/span> const frontMatches = [] const backMatches = [] let match // 鍦ㄥ崱鐗囧墠闈㈠唴瀹逛腑鎼滅储鍖归厤椤�/span> while ((match = searchTextRegex.exec(cardItem.frontContent)) !== null) { // 璁板綍姣忎釜鍖归厤椤圭殑璧峰鍜岀粨鏉熺储寮�/span> frontMatches.push({ startIndex: match.index, endIndex: match.index + match[0].length, }) } // 閲嶇疆姝e垯琛ㄨ揪寮忕殑 lastIndex 灞炴�э紝浠ヤ究閲嶆柊鎼滅储 searchTextRegex.lastIndex = 0 // 鍦ㄥ崱鐗囪儗闈㈠唴瀹逛腑鎼滅储鍖归厤椤�/span> while ((match = searchTextRegex.exec(cardItem.backContent)) !== null) { // 璁板綍姣忎釜鍖归厤椤圭殑璧峰鍜岀粨鏉熺储寮�/span> backMatches.push({ startIndex: match.index, endIndex: match.index + match[0].length, }) } // 妫�鏌ユ槸鍚︽湁鍖归厤椤癸紙鍓嶉潰鎴栬儗闈級 const isMatched = frontMatches.length > 0 || backMatches.length > 0 // 杩斿洖涓�涓柊鐨勫崱鐗囬」鐩璞★紝鍖呭惈鏄惁鍖归厤鍜屽尮閰嶉」鐨勪綅缃�/span> return { ...cardItem, isMatched, frontMatches, backMatches, } }) // 杩囨护鎺変笉鍖归厤鐨勯」鐩�/span> .filter((item) => item.isMatched), } }) // 杩囨护鎺夋病鏈夊尮閰嶉」鐩殑鍗$墖鐩掑瓙 filteredCards.value = matchCardBox.filter((cardBox) => cardBox.cardItems.length > 0) } else { // 濡傛灉娌℃湁鎼滅储鏂囨湰锛屽垯娓呯┖杩囨护鍚庣殑鍗$墖鍒楄〃 filteredCards.value = [] } } 1. 鍒涘缓姝e垯琛ㄨ揪寮�/h4> const searchTextRegex = new RegExp(searchText.value, 'giu') searchText.value锛氳繖鏄敤鎴疯緭鍏ョ殑鎼滅储鏂囨湰銆�/li> new RegExp(...) 锛氶�氳繃浼犲叆鐨勬悳绱㈡枃鏈拰鏍囧織锛�'giu'锛夊垱寤轰竴涓柊鐨勬鍒欒〃杈惧紡瀵硅薄銆�/li> g锛氬叏灞�鎼滅储鏍囧織锛岃〃绀烘悳绱㈡暣涓瓧绗︿覆涓殑鎵�鏈夊尮閰嶉」锛岃�屼笉鏄湪鎵惧埌绗竴涓尮閰嶉」鍚庡仠姝€��/li> i锛氫笉鍖哄垎澶у皬鍐欐爣蹇楋紝琛ㄧず鎼滅储鏃跺拷鐣ュぇ灏忓啓宸紓銆� - u锛歎nicode 鏍囧織锛岃〃绀哄惎鐢� Unicode 瀹屾暣鍖归厤妯″紡锛岃繖瀵逛簬澶勭悊闈� ASCII 瀛楃寰堥噸瑕併��/li> 2. 鎼滅储鍖归厤椤�/h4> let match let match锛氬0鏄庝竴涓彉閲� match锛屽畠灏嗙敤浜庡瓨鍌� RegExp.exec() 鏂规硶鎵惧埌鐨勫尮閰嶉」銆�/li> while ((match = searchTextRegex.exec(cardItem.frontContent)) !== null) { // ... } searchTextRegex.exec(cardItem.frontContent) 锛氬湪 cardItem.frontContent 锛堝崱鐗囩殑姝i潰鍐呭锛変腑鎵ц姝e垯琛ㄨ揪寮忔悳绱€��/li> 濡傛灉鎵惧埌鍖归厤椤癸紝exec() 鏂规硶杩斿洖涓�涓暟缁勶紝鍏朵腑绗竴涓厓绱狅紙match[0]锛夋槸鎵惧埌鐨勫尮閰嶆枃鏈紝index 灞炴�ф槸鍖归厤椤瑰湪瀛楃涓蹭腑鐨勮捣濮嬩綅缃��/li> 濡傛灉娌℃湁鎵惧埌鍖归厤椤癸紝exec() 鏂规硶杩斿洖 null銆� - while 寰幆锛氱户缁墽琛岋紝鐩村埌 exec() 鏂规硶杩斿洖 null锛岃〃绀烘病鏈夋洿澶氱殑鍖归厤椤广��/li> 3. 璁板綍鍖归厤椤圭殑绱㈠紩 frontMatches.push({ startIndex: match.index, endIndex: match.index + match[0].length, }) 鍦ㄦ瘡娆″惊鐜凯浠d腑锛岄兘浼氭壘鍒颁竴涓尮閰嶉」銆�/li> startIndex锛氬尮閰嶉」鍦� cardItem.frontContent 涓殑璧峰浣嶇疆銆�/li> endIndex锛氬尮閰嶉」鍦� cardItem.frontContent 涓殑缁撴潫浣嶇疆锛堝嵆璧峰浣嶇疆鍔犱笂鍖归厤鏂囨湰鐨勯暱搴︼級銆�/li> frontMatches.push(...)锛氬皢鍖呭惈璧峰鍜岀粨鏉熺储寮曠殑瀵硅薄娣诲姞鍒� frontMatches 鏁扮粍涓��/li> 缁忚繃杩欎箞涓�鐣搷浣滐紝鎴戜滑灏卞彲浠ヨ幏寰椾竴涓瓫閫夊悗鐨勬暟缁勶紝鍏朵腑鍖呭惈浜嗘墍鏈夊尮閰嶇殑椤癸紝姣忎釜椤硅繕鏈変竴涓簩缁存暟缁勭敤鏉ヨ褰曞尮閰嶄綅缃紑澶寸粨灏剧殑绱㈠紩锛�/p> cardItems: (CardItem & { id: string frontMatches?: { startIndex: number; endIndex: number }[] backMatches?: { startIndex: number; endIndex: number }[] })[] 涓轰粈涔堣澶ц垂鍛ㄧ珷鐨勮褰曡繖涓储寮曞憿锛岄偅鏄洜涓轰笅涓�姝ラ渶瑕佺敤鍒帮紝鎺ヤ笅鏉ヨ璇村叧閿瘝楂樹寒鐨勫睍绀猴細 鍏抽敭璇嶉珮浜�/h3> 鍏抽敭璇嶉珮浜渶瑕佸湪瀛楃涓茬殑鏌愬嚑涓瓧绗︿腑鏇存敼瀹冪殑鏍峰紡锛屽洜姝ゆ垜浠笂涓�姝ユ墠闇�瑕佽褰曚竴涓嬮渶瑕侀珮浜殑瀛楃涓插紑濮嬪拰缁撴潫鐨勪綅缃紝濡傛涓�鏉ユ垜浠仛杩欎釜楂樹寒鐨勭粍浠跺氨涓嶇敤鍐嶆墽琛屼竴娆″尮閰嶄簡銆傞偅涔堣繖涓牱寮忚濡備綍瀹炵幇鍛紝鎴戜滑闇�瑕侀亶鍘嗚繖涓瓧绗︿覆锛屽湪闇�瑕侀珮浜殑瀛楀鍔犻澶栫殑鏍峰紡锛屾渶鍚庡啀閲嶆柊鎷兼帴鎴愪竴涓瓧绗︿覆銆�/p> // Highlight.vue <template> <view class="flex flex-wrap"> <view v-for="(charWithStyle, index) in styledText" class="text-sm" :key="index" :class="charWithStyle.isMatched ? 'text-indigo-500 font-semibold' : ''" > {{ charWithStyle.char }} </view> </view> </template> <script lang="ts" setup> import { defineProps, computed } from 'vue' interface Props { text: string matches: { startIndex: number; endIndex: number }[] } const props = defineProps<Props>() const styledText = computed(() => { const textArray = _.toArray(props.text) const returnArr = [] let index = 0 let arrIndex = 0 while (index < props.text.length) { let char = '' if (textArray[arrIndex].length > 1) { char = textArray[arrIndex] } else { char = props.text[index] } const isMatched = props.matches.some((match) => { const endIndex = match.endIndex const startIndex = match.startIndex return startIndex <= index && index < endIndex }) returnArr.push({ char, isMatched }) index += textArray[arrIndex].length arrIndex += 1 } return returnArr }) </script> 杩欓噷鎴戞病鏈変娇鐢� for of 鐩存帴閬嶅巻瀛楃涓诧紝杩欎篃鏄垜鐨勪竴涓俯鍧戠偣锛屽儚 emoji 琛ㄦ儏杩欑瀛楃瀹冪殑闀垮害鍏跺疄涓嶆槸 1锛屽鏋滀綘鐩存帴浣跨敤 for of 鍘婚亶鍘嗕細鎶婂畠鐨勭粨鏋勭粰鎷嗗紑锛屾渶缁堝睍绀哄嚭鏉ョ殑鏄贡鐮侊紝濡傛灉浣犳兂姝e父灞曠ず灏辫鐢� Array.from(props.text) 鐨勬柟寮忓皢瀛楃涓茶浆鎹㈡垚鏁扮粍锛屽啀杩涜閬嶅巻锛岃繖鏍锋瘡涓瓧绗﹀氨閮芥槸瀹屾暣鐨勩��/p> 鍋囪鎴戜滑鎵撳嵃锛�/p> console.log('馃槦'[0], '馃槦'.length) console.log(Array.from('馃槦')[0], Array.from('馃槦').length) 杩欓噷鎴戞病鏈変娇鐢� Array.from 鑰屾槸浣跨敤浜� lodash 涓殑 toArray锛屾槸鍥犱负鐪嬪埌杩欑瘒鏂囩珷 fehey.com/emoji-lengt鈥�/a> 涓彁鍒帮細 Array.from(props.text) 鍒涘缓鐨勬暟缁� textArray 涓殑姣忎釜鍏冪礌瀹為檯涓婃槸涓�涓� UTF-16 浠g爜鍗曞厓鐨勫瓧绗︿覆琛ㄧず锛岃�屼笉鏄畬鏁寸殑 Unicode 瀛楃 Emoji 琛ㄦ儏鏈夊彲鑳芥槸澶氫釜 Emoji + 涓�浜涢澶栫殑瀛楃 鏉ユ嫾鎺ュ嚭鏉ョ殑锛屽儚 '馃懇鈥嶐煈┾�嶐煈р�嶐煈�' 灏辨槸鐢� ['馃懇', '', '馃懇', '', '馃懅', '', '馃懅'] 鎷兼帴鑰屾垚鐨勶紝鍗曚釜 Emoji 闀垮害涓� 2锛屼腑闂寸殑杩炴帴瀛楃闀垮害涓� 1锛屾晠杩斿洖浜� 11銆�/p> 濡備綍鑾峰彇 '馃懇鈥嶐煈┾�嶐煈р�嶐煈�' 鐨勯暱搴︿负瑙嗚鐨� 1 鍛紝鍙互浣跨敤 lodash 鐨� toArray 鏂规硶锛宊.toArray('馃懇鈥嶐煈┾�嶐煈р�嶐煈�').length = 1,鍏�a href="http://222.178.203.72:19005/whst/63/=khmjzitdihmzbm>sZqfds=gssor$29$1E$1Efhsgtazbnl$1EkncZrg$1EkncZrg$1Eakna$1E1e68.42c6ab6b8b8450Z2.ccZ1.1a2cbc1a61a8.$1EzhmsdqmZk$1ErsqhmfSn9qqZxzir$12K01/" target="_blank" title="https://github.com/lodash/lodash/blob/2f79053d7bc7c9c9561a30dda202b3dcd2b72b90/.internal/stringToArray.js#L12" ref="nofollow noopener noreferrer">鍐呴儴瀹炵幇聽浜嗗 unicode 瀛楃杞崲鏁扮粍鐨勫吋瀹广��/p> 姝f槸鍥犱负鎴戜滑绗竴姝ヤ腑浣跨敤姝e垯鍘诲尮閰嶅瓧绗︿覆鐨勬椂鍊欙紝鏄牴鎹〃鎯呭寘瀛楃瀹為檯鐨勯暱搴﹁繑鍥炵殑绱㈠紩鍊硷紝鎵�浠ユ垜浠繖閲屾湁涓�涓�昏緫锛�/p> let index = 0 let arrIndex = 0 while (index < props.text.length) { let char = '' if (textArray[arrIndex].length > 1) { char = textArray[arrIndex] } else { char = props.text[index] } //锛岋紝锛�/span> index += textArray[arrIndex].length arrIndex += 1 } 濡傛灉瀛楃鐨勯暱搴﹀ぇ浜庝竴鎴戜滑灏变粠瀛楃涓叉暟缁勪腑鍙栧�硷紝杩欐牱琛ㄦ儏鍖呭氨鑳芥甯稿睍绀轰簡锛岀劧鍚庣淮鎶や袱涓储寮曪紝涓�涓储寮曠粰瀛楃闀垮害澶т簬1鐨勫瓧绗︾敤锛屼竴涓粰瀛楃闀垮害涓�勭敤锛屾牴鎹笉鍚岀殑鎯呭喌鍙栦笉鍚岀殑鍊硷紝杩欐牱灏辫兘澶勭悊濂借〃鎯呭寘鐨勮繖绉嶆儏鍐典簡銆備笅闈㈣繖绉嶅緢澶氫釜琛ㄦ儏鍖呯殑鏂囨湰锛屼篃鑳藉湪姝g‘鐨勪綅缃珮浜�/p> 婊氬姩鍒版寚瀹氫綅缃苟楂樹寒 杩欎竴姝ュ氨姣旇緝绠�鍗曚簡锛岀洿鎺ヤ笂浠g爜锛�/p> import { getCurrentInstance } from 'vue' const instance = getCurrentInstance() const { safeAreaInsets } = uni.getWindowInfo() // 婊氬姩鍒板崱鐩掍綅缃�/span> const scrollToCardBox = (position: 'top' | 'bottom' = 'top') => { const query = uni.createSelectorQuery().in(instance.proxy) query .select(`#card-box-${props.cardBoxIndex}`) .boundingClientRect((data) => { return data }) .selectViewport() .scrollOffset((data) => { return data }) .exec((data) => { uni.pageScrollTo({ scrollTop: data[1].scrollTop + data[0].top - safeAreaInsets.top + (position === 'top' ? 0 : data[0].height), duration: 200, }) }) } 鍏充簬瑙f瀽锛屽湪 馃ゲ韪╁潙鏃犳暟锛屽浣曠敤 uniapp 瀹炵幇涓�涓笣婊戠殑鑻辫瀛︿範鍗$洅灏忕▼搴�/a> 杩欑瘒鏂囩珷涓湁璇︾粏鎻愬埌锛岃繖閲屼笉璧樿堪浜嗐��/p> uni.pageScrollTo 鏈変竴涓洖璋冿紝鍙互鐢ㄤ簬婊氬姩鍒版寚瀹氫綅缃悗锛屾墽琛屾煇涓嚱鏁帮紝閭d箞鎴戜滑鍙互鍦ㄨ繖閲岃缃Е鍙戦珮浜殑鍔ㄧ敾锛屽姩鐢荤殑瀹炵幇濡備笅锛�/p> <view //... :class=" cardItemStore.scrollToCardItemId === props.cardItemData.id ? 'animation-after-search' : '' " .animation-after-search { animation: vague 1s; animation-iteration-count: 2; } @keyframes vague { 0%, 100% { box-shadow: inset 0 0 0 0 transparent; /* 鍒濆鍜岀粨鏉熸椂娌℃湁闃村奖 */ } 50% { box-shadow: inset 0 0 0 2px #6366f1; /* 涓棿鏃跺埢鏄剧ず闃村奖 */ } } 杩欓噷娌℃湁浣跨敤杈规锛岃�屾槸浣跨敤浜嗗唴宓岀殑闃村奖锛岄伩鍏嶈竟妗嗕細鎶婂鍣ㄦ拺澶х殑闂锛屾粴鍔ㄥ畬鎴愬悗鍔ㄦ�佺粰鎸囧畾鍏冪礌涓�涓墽琛屽姩鐢荤殑 class,鍔ㄧ敾瑙﹀彂瀹屾垚鍚庡啀绉婚櫎 class 灏� OK 浜嗐�傛晥鏋滃涓嬶細 鎬荤粨 濡傛灉涓嶆槸閬囧埌浜嗚〃鎯呭寘闀垮害闂锛岃繖涓悳绱㈠姛鑳界殑瀹炵幇杩樻槸姣旇緝绠�鍗曠殑锛岄噸鐐规槸浜や簰鍜岃璁℃槸鍚﹁兘澶熻鐢ㄦ埛蹇�熷畾浣嶅埌鎯虫壘鐨勫唴瀹广�傜洰鍓嶆槸绾墠绔疄鐜帮紝鑰屼笖娑夊強浜嗗緢澶氶亶鍘嗭紝鎬ц兘杩樻湁寰呮彁鍗囷紝涓嶈繃鍏堝疄鐜板啀浼樺寲浜嗐�傚涔犲崱鐩掑凡缁忎笂绾夸簡锛屽ぇ瀹跺彲浠ョ洿鎺ユ悳绱㈠埌锛岃繖涓悳绱㈠姛鑳藉緢蹇篃鍙戠増浜嗭紝娆㈣繋浣撻獙銆�/p>