Просмотр исходного кода

:sparkles: 鼠标移入单词区自动查字典

visuddhinanda 3 лет назад
Родитель
Сommit
bfecd5fe2b

+ 34 - 34
dashboard/src/components/api/Dict.ts

@@ -1,41 +1,41 @@
-export interface IDictlDataRequest {
-	id: number;
-	word: string;
-	type: string;
-	grammar: string;
-	mean: string;
-	parent: string;
-	note: string;
-	factors: string;
-	factormean: string;
-	language: string;
-	confidence: number;
+export interface IDictDataRequest {
+  id: number;
+  word: string;
+  type: string;
+  grammar: string;
+  mean: string;
+  parent: string;
+  note: string;
+  factors: string;
+  factormean: string;
+  language: string;
+  confidence: number;
 }
 export interface IApiResponseDictlData {
-	id: number;
-	word: string;
-	type: string;
-	grammar: string;
-	mean: string;
-	parent: string;
-	note: string;
-	factors: string;
-	factormean: string;
-	language: string;
-	confidence: number;
-	creator_id: number;
-	updated_at: string;
+  id: number;
+  word: string;
+  type: string;
+  grammar: string;
+  mean: string;
+  parent: string;
+  note: string;
+  factors: string;
+  factormean: string;
+  language: string;
+  confidence: number;
+  creator_id: number;
+  updated_at: string;
 }
 export interface IApiResponseDict {
-	ok: boolean;
-	message: string;
-	data: IApiResponseDictlData;
+  ok: boolean;
+  message: string;
+  data: IApiResponseDictlData;
 }
 export interface IApiResponseDictList {
-	ok: boolean;
-	message: string;
-	data: {
-		rows: IApiResponseDictlData[];
-		count: number;
-	};
+  ok: boolean;
+  message: string;
+  data: {
+    rows: IApiResponseDictlData[];
+    count: number;
+  };
 }

+ 50 - 2
dashboard/src/components/template/Wbw/WbwWord.tsx

@@ -1,4 +1,4 @@
-import { useState, useEffect } from "react";
+import { useState, useEffect, useRef } from "react";
 import WbwCase from "./WbwCase";
 import { bookMarkColor } from "./WbwDetailBookMark";
 import WbwFactorMeaning from "./WbwFactorMeaning";
@@ -8,6 +8,11 @@ import WbwPali from "./WbwPali";
 import "./wbw.css";
 import WbwPara from "./WbwPara";
 import WbwPage from "./WbwPage";
+import { useAppSelector } from "../../../hooks";
+import { add, wordList } from "../../../reducers/inline-dict";
+import { get } from "../../../request";
+import { IApiResponseDictList } from "../../api/Dict";
+import store from "../../../store";
 
 export type TFieldName =
   | "word"
@@ -89,10 +94,12 @@ const Widget = ({
 }: IWidget) => {
   const [wordData, setWordData] = useState(data);
   const [fieldDisplay, setFieldDisplay] = useState(fields);
+  const intervalRef = useRef<number | null>(null); //防抖计时器句柄
+  const inlineWords = useAppSelector(wordList);
+
   useEffect(() => {
     setWordData(data);
     setFieldDisplay(fields);
-    console.log("display change", fields);
   }, [data, fields]);
 
   const color = wordData.bookMarkColor
@@ -105,6 +112,35 @@ const Widget = ({
     display: display === "block" ? "block" : "flex",
   };
 
+  /**
+   * 停止查字典计时
+   * 在两种情况下停止计时
+   * 1. 开始查字典
+   * 2. 防抖时间内鼠标移出单词区
+   */
+  const stopLookup = () => {
+    if (intervalRef.current) {
+      window.clearInterval(intervalRef.current);
+      intervalRef.current = null;
+    }
+  };
+  /**
+   * 查字典
+   * @param word 要查的单词
+   */
+  const lookup = (word: string) => {
+    stopLookup();
+    //查询这个词在内存字典里是否有
+    if (inlineWords.has(word)) {
+      //已经有了,退出
+      return;
+    }
+    get<IApiResponseDictList>(`/v2/wbwlookup?word=${word}`).then((json) => {
+      console.log("lookup ok", json.data.count);
+      store.dispatch(add([word, json.data.rows]));
+    });
+    console.log("lookup", word);
+  };
   if (wordData.type?.value === ".ctl.") {
     if (wordData.word.value.includes("para")) {
       return <WbwPara data={wordData} />;
@@ -116,6 +152,18 @@ const Widget = ({
       <div
         className={`wbw_word ${display} ${wbwCtl} ${wbwAnchor} `}
         style={styleWbw}
+        onMouseEnter={() => {
+          if (intervalRef.current === null) {
+            intervalRef.current = window.setInterval(
+              lookup,
+              200,
+              wordData.word.value
+            );
+          }
+        }}
+        onMouseLeave={() => {
+          stopLookup();
+        }}
       >
         <WbwPali
           data={wordData}

+ 38 - 0
dashboard/src/reducers/inline-dict.ts

@@ -0,0 +1,38 @@
+import { createSlice, PayloadAction } from "@reduxjs/toolkit";
+
+import type { RootState } from "../store";
+import { IDictDataRequest } from "../components/api/Dict";
+
+/**
+ * 在查询字典后,将查询结果放入map
+ * key: 单词词头
+ * value: 查询到的单词列表
+ */
+interface IState {
+  wordMap: Map<string, IDictDataRequest[]>;
+  word?: string;
+  value?: IDictDataRequest[];
+}
+
+const initialState: IState = {
+  wordMap: new Map<string, IDictDataRequest[]>([["word", []]]),
+};
+
+export const slice = createSlice({
+  name: "inline-dict",
+  initialState,
+  reducers: {
+    add: (state, action: PayloadAction<[string, IDictDataRequest[]]>) => {
+      state.wordMap.set(action.payload[0], action.payload[1]);
+    },
+  },
+});
+
+export const { add } = slice.actions;
+
+export const inlineDict = (state: RootState): IState => state.inlineDict;
+
+export const wordList = (state: RootState): Map<string, IDictDataRequest[]> =>
+  state.inlineDict.wordMap;
+
+export default slice.reducer;

+ 2 - 0
dashboard/src/store.ts

@@ -7,6 +7,7 @@ import settingReducer from "./reducers/setting";
 import commandReducer from "./reducers/command";
 import suggestionReducer from "./reducers/suggestion";
 import articleModeReducer from "./reducers/article-mode";
+import inlineDictReducer from "./reducers/inline-dict";
 
 const store = configureStore({
   reducer: {
@@ -17,6 +18,7 @@ const store = configureStore({
     command: commandReducer,
     suggestion: suggestionReducer,
     articleMode: articleModeReducer,
+    inlineDict: inlineDictReducer,
   },
 });