From 83ea700eac06dc6454e4d0b8a7e56849c3cb7c46 Mon Sep 17 00:00:00 2001 From: Frost-ZX <30585462+Frost-ZX@users.noreply.github.com> Date: Sun, 20 Mar 2022 21:49:43 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=85=A8=E5=B1=80=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E8=AF=BB=E5=86=99=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=20Vuex?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 85 +++++----- src/assets/js/config.js | 154 ----------------- src/assets/js/search-utils.js | 292 +++++++++++++++++++++++++++------ src/assets/js/utils.js | 4 +- src/components/FloatingBtn.vue | 26 +-- src/main.js | 11 -- src/router/index.js | 8 +- src/store/index.js | 108 +++++++++++- src/views/AboutView.vue | 4 +- src/views/HomeView.vue | 164 +++++++++--------- src/views/SettingsView.vue | 96 ++++++++--- src/views/ToolsDetail.vue | 6 +- 12 files changed, 556 insertions(+), 402 deletions(-) diff --git a/src/App.vue b/src/App.vue index 6fe69a6..fe47238 100644 --- a/src/App.vue +++ b/src/App.vue @@ -2,7 +2,7 @@
-
+
@@ -20,7 +20,7 @@ diff --git a/src/assets/js/config.js b/src/assets/js/config.js index 3c1f7aa..4fab6af 100644 --- a/src/assets/js/config.js +++ b/src/assets/js/config.js @@ -2,160 +2,6 @@ let config = { loading: { subPage: false }, - searchEngines: { - search: { - title: '搜索', - list: [ - { - name: '百度', - desc: 'www.baidu.com', - url: 'https://www.baidu.com/s?wd=%keyword%', - icon: 'website/baidu.svg', - show: true - }, - { - name: '必应', - desc: 'cn.bing.com', - url: 'https://cn.bing.com/search?q=%keyword%', - icon: 'website/bing.svg', - show: true - }, - { - name: '秘迹', - desc: 'mijisou.com', - url: 'https://mijisou.com/?q=%keyword%', - icon: 'website/mijisou.svg', - show: true - }, - { - name: '搜狗', - desc: 'www.sogou.com', - url: 'https://www.sogou.com/web?query=%keyword%', - icon: 'website/sogou.svg', - show: true - }, - { - name: '360', - desc: 'www.so.com', - url: 'https://www.so.com/s?q=%keyword%', - icon: 'website/360.svg', - show: true - }, - { - name: 'Google', - desc: 'www.google.com', - url: 'https://www.google.com/search?q=%keyword%', - icon: 'website/google.svg', - show: true - }, - { - name: 'Yandex', - desc: 'yandex.com', - url: 'https://yandex.com/search/?text=%keyword%', - icon: 'website/yandex.svg', - show: true - } - ] - }, - media: { - title: '多媒体', - list: [ - { - name: '网易云音乐', - desc: 'music.163.com', - url: 'https://music.163.com/#/search/m/?s=%keyword%', - icon: 'website/netease_music.svg', - show: true - }, - { - name: 'AcFun', - desc: 'www.acfun.cn', - url: 'https://www.acfun.cn/search/?keyword=%keyword%', - icon: 'website/acfun.svg', - show: true - }, - { - name: 'bilibili', - desc: 'search.bilibili.com', - url: 'https://search.bilibili.com/all?keyword=%keyword%', - icon: 'website/bilibili.svg', - show: true - }, - { - name: 'QQ音乐', - desc: 'y.qq.com', - url: 'https://y.qq.com/n/ryqq/search?w=%keyword%', - icon: 'website/qq_music.svg', - show: true - } - ] - }, - technology: { - title: '技术', - list: [ - { - name: 'CSDN', - desc: 'so.csdn.net', - url: 'https://so.csdn.net/so/search/all?q=%keyword%', - icon: 'website/csdn.svg', - show: true - }, - { - name: 'GitHub', - desc: 'github.com', - url: 'https://github.com/search?q=%keyword%', - icon: 'website/github.svg', - show: true - }, - { - name: 'MDN', - desc: 'developer.mozilla.org', - url: 'https://developer.mozilla.org/zh-CN/search?q=%keyword%', - icon: 'website/mdn.svg', - show: true - } - ] - }, - design: { - title: '设计', - list: [ - { - name: '站酷', - desc: 'www.zcool.com.cn', - url: 'https://www.zcool.com.cn/search/content?word=%keyword%', - icon: 'website/zcool.svg', - show: true - }, - { - name: 'Iconfont', - desc: 'www.iconfont.cn', - url: 'https://www.iconfont.cn/search/index?searchType=icon&q=%keyword%', - icon: 'website/iconfont.svg', - show: true - } - ] - }, - community: { - title: '社区', - list: [ - { - name: '天涯', - desc: 'search.tianya.cn', - url: 'https://search.tianya.cn/bbs?q=%keyword%', - icon: 'website/tianya.svg', - show: true - }, - { - name: '知乎', - desc: 'www.zhihu.com', - url: 'https://www.zhihu.com/search?type=content&q=%keyword%', - icon: 'website/zhihu.svg', - show: true - } - ] - } - }, - siteName: 'Frost 网址导航', storage: { fontSize: 16, showSiteTitle: true, diff --git a/src/assets/js/search-utils.js b/src/assets/js/search-utils.js index 243062d..d1e2201 100644 --- a/src/assets/js/search-utils.js +++ b/src/assets/js/search-utils.js @@ -1,52 +1,3 @@ -/** - * @description 解析推荐的关键词 - * @param {string} type 来源类型 - * @param {*} datas 关键词数据 - * @param {number} [max] 最大返回数量 - * @returns {string[]} 关键词列表 - */ -function parseSearchWords(type = '', datas = null, max = 10) { - if (!datas) { - return []; - } - - /** @type {string[]} */ - let words = []; - - try { - switch (type) { - case '360': - words = parseSearch360(datas); - case 'baidu': - words = parseSearchBaidu(datas); - case 'bing': - words = parseSearchBing(datas); - default: - break; - } - } catch (error) { - console.error('解析失败'); - return []; - } - - const arrLength = words.length; - const cutLength = Math.max(arrLength - max, 0); - const cutStart = arrLength - cutLength; - - words.splice(cutStart, cutLength); - - let value = ''; - - for (value of words) { - if (typeof value !== 'string') { - console.error('关键词的数据类型错误'); - return []; - } - } - - return words; -} - /** * @desc 解析 360 推荐关键词(2021-12-29) * @param {{ result: { word: string }[] }} datas @@ -91,10 +42,41 @@ function parseSearchBing(datas) { return words; } +/** + * @typedef MDNSearchIndexDatas + * @type {{ title: string, url: string }[]} + */ + +/** + * @description 解析 MDN 搜索关键词 + * @param {MDNSearchIndexDatas} datas 关键词数据 + * @param {string} keyword 输入的关键词 + * @param {number} [max] 最多返回的结果数量,默认为 10 + * @returns {MDNSearchIndexDatas} 匹配到的关键词 + */ +function parseSearchMDN(datas = [], keyword = '', max = 10) { + /** @type {MDNSearchIndexDatas} */ + const result = []; + const word = String(keyword).toLowerCase(); + + let count = 0; + + for (const item of datas) { + if (item.title.toLowerCase().indexOf(word) > -1) { + result.push(item); + if ((count += 1) >= max) { + break; + } + } + } + + return result; +} + /** * @description 获取搜索 URL - * @param {string} type 搜索引擎类型 - * @param {string} word 搜索关键词 + * @param {string} type 搜索引擎类型 + * @param {string} word 搜索关键词 * @param {string} [cbName] 回调函数名称,用于获取推荐关键词 * @returns {(string|null)} 根据参数返回不同的结果 * - 无 `cbName` 时返回搜索结果页面 URL @@ -128,6 +110,207 @@ function getSearchURL(type, word, cbName) { } } +/** + * @description 解析推荐的关键词 + * @param {string} type 来源类型 + * @param {*} datas 关键词数据 + * @param {number} [max] 最大返回数量 + * @returns {string[]} 关键词列表 + */ +function parseSearchWords(type = '', datas = null, max = 10) { + if (!datas) { + return []; + } + + /** @type {string[]} */ + let words = []; + + try { + switch (type) { + case '360': + words = parseSearch360(datas); + break; + case 'baidu': + words = parseSearchBaidu(datas); + break; + case 'bing': + words = parseSearchBing(datas); + break; + default: + console.error('来源类型错误'); + return []; + } + } catch (error) { + console.error('解析失败'); + return []; + } + + const arrLength = words.length; + const cutLength = Math.max(arrLength - max, 0); + const cutStart = arrLength - cutLength; + + words.splice(cutStart, cutLength); + + let value = ''; + + for (value of words) { + if (typeof value !== 'string') { + console.error('关键词的数据类型错误'); + return []; + } + } + + return words; +} + +/** 搜索引擎列表 */ +const searchEngines = { + search: { + title: '搜索', + list: [ + { + name: '百度', + desc: 'www.baidu.com', + url: 'https://www.baidu.com/s?wd=%keyword%', + icon: 'website/baidu.svg', + show: true + }, + { + name: '必应', + desc: 'cn.bing.com', + url: 'https://cn.bing.com/search?q=%keyword%', + icon: 'website/bing.svg', + show: true + }, + { + name: '搜狗', + desc: 'www.sogou.com', + url: 'https://www.sogou.com/web?query=%keyword%', + icon: 'website/sogou.svg', + show: true + }, + { + name: '360', + desc: 'www.so.com', + url: 'https://www.so.com/s?q=%keyword%', + icon: 'website/360.svg', + show: true + }, + { + name: 'Google', + desc: 'www.google.com', + url: 'https://www.google.com/search?q=%keyword%', + icon: 'website/google.svg', + show: true + }, + { + name: 'Yandex', + desc: 'yandex.com', + url: 'https://yandex.com/search/?text=%keyword%', + icon: 'website/yandex.svg', + show: true + } + ] + }, + media: { + title: '多媒体', + list: [ + { + name: '网易云音乐', + desc: 'music.163.com', + url: 'https://music.163.com/#/search/m/?s=%keyword%', + icon: 'website/netease_music.svg', + show: true + }, + { + name: 'AcFun', + desc: 'www.acfun.cn', + url: 'https://www.acfun.cn/search/?keyword=%keyword%', + icon: 'website/acfun.svg', + show: true + }, + { + name: 'bilibili', + desc: 'search.bilibili.com', + url: 'https://search.bilibili.com/all?keyword=%keyword%', + icon: 'website/bilibili.svg', + show: true + }, + { + name: 'QQ音乐', + desc: 'y.qq.com', + url: 'https://y.qq.com/n/ryqq/search?w=%keyword%', + icon: 'website/qq_music.svg', + show: true + } + ] + }, + technology: { + title: '技术', + list: [ + { + name: 'CSDN', + desc: 'so.csdn.net', + url: 'https://so.csdn.net/so/search/all?q=%keyword%', + icon: 'website/csdn.svg', + show: true + }, + { + name: 'GitHub', + desc: 'github.com', + url: 'https://github.com/search?q=%keyword%', + icon: 'website/github.svg', + show: true + }, + { + name: 'MDN', + desc: 'developer.mozilla.org', + url: 'https://developer.mozilla.org/zh-CN/search?q=%keyword%', + icon: 'website/mdn.svg', + show: true + } + ] + }, + design: { + title: '设计', + list: [ + { + name: '站酷', + desc: 'www.zcool.com.cn', + url: 'https://www.zcool.com.cn/search/content?word=%keyword%', + icon: 'website/zcool.svg', + show: true + }, + { + name: 'Iconfont', + desc: 'www.iconfont.cn', + url: 'https://www.iconfont.cn/search/index?searchType=icon&q=%keyword%', + icon: 'website/iconfont.svg', + show: true + } + ] + }, + community: { + title: '社区', + list: [ + { + name: '天涯', + desc: 'search.tianya.cn', + url: 'https://search.tianya.cn/bbs?q=%keyword%', + icon: 'website/tianya.svg', + show: true + }, + { + name: '知乎', + desc: 'www.zhihu.com', + url: 'https://www.zhihu.com/search?type=content&q=%keyword%', + icon: 'website/zhihu.svg', + show: true + } + ] + } +}; + /** * @typedef {object} SearchItem * @property {string} name 名称 @@ -154,3 +337,10 @@ const searchItems = [ // wordURL: 'https://sg1.api.bing.com/qsonhs.aspx?type=cb&cb={cb}&q={w}', }, ]; + +export default { + getSearchURL, + parseSearchMDN, + parseSearchWords, + searchEngines, +}; diff --git a/src/assets/js/utils.js b/src/assets/js/utils.js index b842c25..8aa22a7 100644 --- a/src/assets/js/utils.js +++ b/src/assets/js/utils.js @@ -1,5 +1,3 @@ -import config from './config.js'; - class Utils { constructor() { } @@ -9,7 +7,7 @@ class Utils { * @param {string} [value] 新的标题 */ changeTitle(value) { - document.title = (value ? (value + ' - ') : '') + config.siteName; + document.title = ((value ? `${value} - ` : '') + 'Frost 网址导航'); } /** diff --git a/src/components/FloatingBtn.vue b/src/components/FloatingBtn.vue index ba3cf57..7d6de89 100644 --- a/src/components/FloatingBtn.vue +++ b/src/components/FloatingBtn.vue @@ -24,8 +24,7 @@ export default { name: 'FloatingBtn', data() { return { - config: this.$root.config.storage, - showInner: false + showInner: false, } }, mounted () { @@ -33,9 +32,7 @@ export default { }, methods: { - /** - * 设置动画 - */ + /** 设置动画 */ initAnimation() { var vm = this; var el = vm.$refs['floatingBtn']; @@ -53,16 +50,12 @@ export default { }); }, - /** - * 切换按钮显示 - */ + /** 切换按钮显示 */ toggleInnerBtns() { this.showInner = !this.showInner; }, - /** - * 返回主页 - */ + /** 返回主页 */ backToHome() { const routeName = 'Home'; @@ -77,19 +70,14 @@ export default { } }, - /** - * 刷新 - */ + /** 刷新 */ refreshPage() { window.location.reload(); }, - /** - * 切换侧边菜单折叠状态 - */ + /** 切换侧边菜单折叠状态 */ toggleSideCollapse() { - var cfg = this.config; - cfg.sideMenuCollapse = !cfg.sideMenuCollapse; + this.$store.dispatch('toggleSideCollapse'); }, }, diff --git a/src/main.js b/src/main.js index 21f189b..0c5208a 100644 --- a/src/main.js +++ b/src/main.js @@ -4,10 +4,6 @@ import App from './App.vue'; import router from './router'; import store from './store'; -import config from './assets/js/config'; -import navLinks from './assets/js/navLinks'; -import utils from './assets/js/utils'; - import 'ress/ress.css'; import 'font-awesome/css/font-awesome.min.css'; import './assets/css/element.scss'; @@ -20,12 +16,5 @@ Vue.config.productionTip = false; new Vue({ router, store, - data: function () { - return { - config, - navLinks, - utils - } - }, render: h => h(App) }).$mount('#app'); diff --git a/src/router/index.js b/src/router/index.js index 292077c..fd16d1d 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -2,8 +2,8 @@ import Vue from 'vue'; import VueRouter from 'vue-router'; import routes from './routes'; -import config from '@/assets/js/config'; import utils from '@/assets/js/utils'; +import store from '@/store/index'; Vue.use(VueRouter); @@ -11,18 +11,16 @@ const router = new VueRouter({ routes }); -// to, from, next router.beforeEach((to, from, next) => { if (to.meta.loadingBar) { - config.loading.subPage = true; + store.commit('toggleLoading', true); } next(); }); -// to, from router.afterEach((to) => { if (to.meta.loadingBar) { - config.loading.subPage = false; + store.commit('toggleLoading', false); } utils.changeTitle(to.meta.title); }); diff --git a/src/store/index.js b/src/store/index.js index 0533d49..1ebeac5 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -4,9 +4,111 @@ import Vuex from 'vuex'; Vue.use(Vuex); export default new Vuex.Store({ - state: {}, + state: { + + /** 设置 */ + config: { + fontSize: 16, + showSiteTitle: true, + sideMenuCollapse: true, + searchEngine: '百度', + searchSuggestion: false, + }, + + /** 显示加载动画 */ + showLoading: false, + + }, getters: {}, - mutations: {}, - actions: {}, + mutations: { + + /** 从本地储存中读取设置 */ + readConfig(state) { + + let keyName = 'fn_config'; + let storage = localStorage.getItem(keyName); + let parsed = null; + let config = state.config; + + try { + parsed = JSON.parse(storage); + } catch (error) { + console.error('解析保存的设置失败。'); + } + + if (parsed && parsed.constructor === Object) { + // [本地储存中有数据,读取] + for (let key in config) { + let value = parsed[key]; + + if (typeof value !== 'undefined') { + config[key] = value; + } + } + } else { + // [本地储存中无数据,写入] + localStorage.setItem(keyName, JSON.stringify(config)); + } + + }, + + /** 重置保存的设置 */ + resetConfig() { + localStorage.removeItem('fn_config'); + }, + + /** + * @description 更新设置 + * @param {object} payload + * @param {string} payload.key + * @param {any} payload.value + */ + setConfig(state, payload) { + + const { + key: cKey = null, + value: cValue = null, + } = payload; + + const { config } = state; + + if (cKey === null) { + console.error('更新设置失败,key 为空。'); + return; + } + + if (typeof config[cKey] === 'undefined') { + console.error('更新设置失败,key 不存在。'); + return; + } + + // 更新设置 + config[cKey] = cValue; + // 保存设置 + localStorage.setItem('fn_config', JSON.stringify(config)); + + }, + + /** 切换加载动画显示隐藏 */ + toggleLoading(state, payload = false) { + state.showLoading = payload; + }, + + }, + actions: { + + /** 切换导航链接侧边菜单显示隐藏 */ + toggleSideCollapse(store) { + + const { sideMenuCollapse } = store.state.config; + + store.commit('setConfig', { + key: 'sideMenuCollapse', + value: !sideMenuCollapse, + }); + + }, + + }, modules: {}, }); diff --git a/src/views/AboutView.vue b/src/views/AboutView.vue index ad1a5c2..fa73c2c 100644 --- a/src/views/AboutView.vue +++ b/src/views/AboutView.vue @@ -41,11 +41,13 @@