import { addStyle, DOMUtils, httpx, log, utils } from "@/env"; import { Panel } from "@components/setting/panel"; import { GestureBack } from "@components/utils/GestureBack"; import searchToolBarCSS from "./search-toolbar.css?raw"; export const BaiduSearchToolBar = { $el: { /** 搜索框总容器 */ $container: null as any as HTMLElement, shadowRoot: null as any as ShadowRoot, $toolbarContainer: null as any as HTMLDivElement, /** 搜索框容器 */ $toolbar: null as any as HTMLDivElement, /** 提交表单 */ $form: null as any as HTMLFormElement, /** 输入框 */ $input: null as any as HTMLInputElement, /** 搜索建议 */ $suggestion: null as any as HTMLDivElement, /** 返回按钮 */ $back: null as any as HTMLDivElement, /** 清空图标 */ $empty: null as any as HTMLDivElement, /** 搜索按钮 */ $submit: null as any as HTMLButtonElement, }, $data: { gestureBack: new GestureBack({ hash: "global-search", beforeHistoryBackCallBack(isUrlChange) { BaiduSearchToolBar.hideToolBar(); }, }), }, init() { DOMUtils.onReady(() => { this.addFloatButton(); this.addToolBar(); }); }, /** * 添加悬浮搜索按钮 */ addFloatButton() { let $btn = DOMUtils.createElement("div", { className: "gm-search-toolbar-float-btn", innerHTML: /*html*/ ` `, }); DOMUtils.on($btn, "click", (event) => { DOMUtils.preventEvent(event); this.showToolBar(); this.initDefaultSearchText(); setTimeout(() => { this.$el.$input.focus(); this.$el.$input.select(); }, 150); Panel.execMenu("baidu-search-global-searchToolBar-gesture-back", () => { // 手势返回 this.$data.gestureBack.enterGestureBackMode(); }); }); addStyle(/*css*/ ` .gm-search-toolbar-float-btn { --gm-search-toolbar-icon-size: 45px; position: fixed; bottom: 20px; right: 15px; width: var(--gm-search-toolbar-icon-size); height: var(--gm-search-toolbar-icon-size); z-index: 9000; } `); document.body.appendChild($btn); return $btn; }, /** * 添加搜索工具栏 */ addToolBar() { let $toolbarInner = DOMUtils.createElement("div"); $toolbarInner.className = "gm-search-toolbar"; // 使用shadow $toolbarInner.attachShadow({ mode: "open" }); let shadowRoot = $toolbarInner.shadowRoot!; this.$el.$container = $toolbarInner; this.$el.shadowRoot = shadowRoot; // 添加css let $css = DOMUtils.createElement("style", { innerHTML: searchToolBarCSS, }); shadowRoot.appendChild($css); // container let $container = DOMUtils.createElement("div", { className: "search-toolbar-container", innerHTML: /*html*/ `
`, }); this.$el.$toolbarContainer = $container; this.$el.$toolbar = $container.querySelector(".search-toolbar")!; this.$el.$input = $container.querySelector(".search-toolbar-input")!; this.$el.$form = $container.querySelector(".search-form")!; this.$el.$suggestion = $container.querySelector(".search-suggestion")!; this.$el.$back = $container.querySelector(".search-toolbar-back")!; this.$el.$empty = $container.querySelector(".search-toolbar-empty")!; this.$el.$submit = $container.querySelector(".search-form-submit")!; shadowRoot.appendChild($container); // 添加到页面 this.hideToolBar(); document.body.appendChild($toolbarInner); this.setInputEvent(); this.setEmptyEvent(); this.setBackEvent(); this.setFormEvent(); }, /** * 显示搜索工具栏 */ showToolBar() { this.$el.$toolbarContainer.style.opacity = ""; this.$el.$toolbarContainer.style.visibility = ""; }, /** * 隐藏搜索工具栏 */ hideToolBar() { this.$el.$toolbarContainer.style.opacity = "0"; this.$el.$toolbarContainer.style.visibility = "hidden"; }, /** * 获取当前页面搜索的关键字 */ getPageSearchText() { let searchParams = new URLSearchParams(window.location.search); let searchText = searchParams.get("word") || searchParams.get("wd"); return searchText!; }, /** * 获取搜索建议内容 * @param text 搜索内容 */ async getSuggestionText(text: string) { let searchParamData = { json: 1, prod: "wise", callback: "baidusug", wd: text, }; let allowApiHostName = ["m.baidu.com", "www.baidu.com"]; let apiHostName = "m.baidu.com"; let useFetch = true; if (allowApiHostName.includes(window.location.hostname)) { apiHostName = window.location.hostname; } else { useFetch = false; } let response = await httpx.get(`https://${apiHostName}/sugrec?${utils.toSearchParamsStr(searchParamData)}`, { fetch: useFetch, allowInterceptConfig: false, }); if (!response.status) { log.error("获取百度搜索建议失败", response); return; } let suggestion = response.data.responseText.replace(/^baidusug\(/, "").replace(/\)$/, ""); let suggestionJSON = utils.toJSON(suggestion) as { g: { q: string; sa: string; type: string; }[]; p: boolean; q: string; queryid: string; slid: string; }; log.info(`百度搜索联想词:`, suggestionJSON); return suggestionJSON.g || []; }, /** * 初始化当前页面默认的搜索关键字 */ initDefaultSearchText() { let searchText = this.getPageSearchText(); this.setInputText(searchText); }, /** * 监听输入框内容改变 */ setInputEvent() { DOMUtils.on(this.$el.$input, ["input", "propertychange"], () => { // 判断是否为空,动态修改图标显示和颜色 if (this.$el.$input.value === "") { // 空的 this.clearSuggestion(); this.$el.$empty.style.display = "none"; this.$el.$submit.setAttribute("disabled", "true"); } else { // 非空 this.$el.$empty.style.display = ""; this.$el.$submit.removeAttribute("disabled"); } }); DOMUtils.on( this.$el.$input, ["input", "propertychange"], utils.debounce(async () => { let searchText = this.$el.$input.value; if (searchText === "") { return; } let suggestionList = await this.getSuggestionText(searchText); if (Array.isArray(suggestionList) && suggestionList.length) { // 清空搜索结果 this.clearSuggestion(); // if (searchText.trim() !== "") { // this.addSuggestionItem( // this.createSuggestionItem({ // searchText: searchText, // suggestionText: searchText, // isHistory: true, // }) // ); // } suggestionList.forEach((item) => { if (item.type === "sug") { this.addSuggestionItem( this.createSuggestionItem({ searchText: searchText, suggestionText: item.q, isHistory: false, }) ); } }); } }, 50) ); }, /** * 设置搜索文本内容 * @param text 搜索关键字 * @param emitEvent 是否触发事件 * @default true */ setInputText(text: string, emitEvent: boolean = true) { this.$el.$input.value = text; if (emitEvent) { DOMUtils.emit(this.$el.$input, "input"); } }, /** * 设置返回按钮点击事件 */ setBackEvent() { DOMUtils.on(this.$el.$back, "click", (event) => { DOMUtils.preventEvent(event); log.success("点击返回"); this.hideToolBar(); Panel.execMenu("baidu-search-global-searchToolBar-gesture-back", () => { // 退出手势模式 this.$data.gestureBack.quitGestureBackMode(); }); }); }, /** * 设置清空图标点击事件 */ setEmptyEvent() { DOMUtils.on(this.$el.$empty, "click", (event) => { DOMUtils.preventEvent(event); this.setInputText(""); }); }, /** * 设置表单事件 */ setFormEvent() { DOMUtils.on(this.$el.$form, "submit", (event) => { DOMUtils.preventEvent(event); const searchText = this.$el.$input.value; log.success("提交表单 搜索 ==> " + searchText); window.location.href = `${window.location.origin}/s?word=${searchText}`; }); }, /** * 创建搜索建议元素项 */ createSuggestionItem(config: { /** 搜索的关键字 */ searchText: string; /** 搜索建议文本 */ suggestionText: string; /** 是否是历史输入 */ isHistory: boolean; }) { let $suggestionItem = DOMUtils.createElement("div", { className: "search-suggestion-item", innerHTML: /*html*/ `
`, }); let $leftIcon = $suggestionItem.querySelector(".search-suggestion-item-left-icon")!; let $leftIconI = $leftIcon.querySelector(".search-icon")!; let $text = $suggestionItem.querySelector(".search-suggestion-item-text")!; let $rightIcon = $suggestionItem.querySelector(".search-suggestion-item-right-icon")!; if (config.isHistory) { // 切换图标为历史 $leftIconI.innerHTML = /*html*/ ` `; } // 处理搜索关键字灰色 let searchText = config.suggestionText.replaceAll(config.searchText, `${config.searchText}`); $text.innerHTML = searchText; DOMUtils.on($leftIcon, "click", (event) => { DOMUtils.preventEvent(event); }); // 搜索建议点击事件 DOMUtils.on($text, "click", (event) => { DOMUtils.preventEvent(event); this.setInputText(config.suggestionText, false); this.$el.$submit.click(); }); DOMUtils.on($rightIcon, "click", (event) => { DOMUtils.preventEvent(event); this.setInputText(config.suggestionText); }); return $suggestionItem; }, /** * 清除搜索建议 */ clearSuggestion() { this.$el.$suggestion.innerHTML = ""; }, /** * 添加搜索建议 */ addSuggestionItem($ele: HTMLElement) { this.$el.$suggestion.appendChild($ele); }, };