├── showImg ├── gif1.gif ├── gif2.gif ├── current1.jpg └── origin.png ├── public ├── favicon.ico └── index.html ├── src ├── assets │ ├── img │ │ ├── logo.png │ │ └── myWx.png │ └── css │ │ ├── animate.css │ │ ├── source │ │ │ ├── _vars.css │ │ │ ├── fading_entrances │ │ │ │ ├── fadeIn.css │ │ │ │ ├── fadeInUp.css │ │ │ │ ├── fadeInDown.css │ │ │ │ ├── fadeInLeft.css │ │ │ │ ├── fadeInRight.css │ │ │ │ ├── fadeInUpBig.css │ │ │ │ ├── fadeInDownBig.css │ │ │ │ ├── fadeInLeftBig.css │ │ │ │ ├── fadeInTopLeft.css │ │ │ │ ├── fadeInTopRight.css │ │ │ │ ├── fadeInRightBig.css │ │ │ │ ├── fadeInBottomLeft.css │ │ │ │ └── fadeInBottomRight.css │ │ │ ├── fading_exits │ │ │ │ ├── fadeOut.css │ │ │ │ ├── fadeOutUp.css │ │ │ │ ├── fadeOutDown.css │ │ │ │ ├── fadeOutLeft.css │ │ │ │ ├── fadeOutRight.css │ │ │ │ ├── fadeOutUpBig.css │ │ │ │ ├── fadeOutDownBig.css │ │ │ │ ├── fadeOutLeftBig.css │ │ │ │ ├── fadeOutRightBig.css │ │ │ │ ├── fadeOutTopLeft.css │ │ │ │ ├── fadeOutTopRight.css │ │ │ │ ├── fadeOutBottomLeft.css │ │ │ │ └── fadeOutBottomRight.css │ │ │ ├── attention_seekers │ │ │ │ ├── flash.css │ │ │ │ ├── shake.css │ │ │ │ ├── shakeX.css │ │ │ │ ├── shakeY.css │ │ │ │ ├── pulse.css │ │ │ │ ├── swing.css │ │ │ │ ├── heartBeat.css │ │ │ │ ├── tada.css │ │ │ │ ├── rubberBand.css │ │ │ │ ├── headShake.css │ │ │ │ ├── wobble.css │ │ │ │ ├── jello.css │ │ │ │ └── bounce.css │ │ │ ├── zooming_entrances │ │ │ │ ├── zoomIn.css │ │ │ │ ├── zoomInUp.css │ │ │ │ ├── zoomInDown.css │ │ │ │ ├── zoomInLeft.css │ │ │ │ └── zoomInRight.css │ │ │ ├── sliding_entrances │ │ │ │ ├── slideInUp.css │ │ │ │ ├── slideInDown.css │ │ │ │ ├── slideInLeft.css │ │ │ │ └── slideInRight.css │ │ │ ├── sliding_exits │ │ │ │ ├── slideOutUp.css │ │ │ │ ├── slideOutDown.css │ │ │ │ ├── slideOutLeft.css │ │ │ │ └── slideOutRight.css │ │ │ ├── rotating_exits │ │ │ │ ├── rotateOut.css │ │ │ │ ├── rotateOutUpLeft.css │ │ │ │ ├── rotateOutUpRight.css │ │ │ │ ├── rotateOutDownLeft.css │ │ │ │ └── rotateOutDownRight.css │ │ │ ├── zooming_exits │ │ │ │ ├── zoomOut.css │ │ │ │ ├── zoomOutLeft.css │ │ │ │ ├── zoomOutRight.css │ │ │ │ ├── zoomOutUp.css │ │ │ │ └── zoomOutDown.css │ │ │ ├── rotating_entrances │ │ │ │ ├── rotateIn.css │ │ │ │ ├── rotateInUpLeft.css │ │ │ │ ├── rotateInUpRight.css │ │ │ │ ├── rotateInDownLeft.css │ │ │ │ └── rotateInDownRight.css │ │ │ ├── bouncing_exits │ │ │ │ ├── bounceOutLeft.css │ │ │ │ ├── bounceOutRight.css │ │ │ │ ├── bounceOutUp.css │ │ │ │ ├── bounceOutDown.css │ │ │ │ └── bounceOut.css │ │ │ ├── lightspeed │ │ │ │ ├── lightSpeedOutLeft.css │ │ │ │ ├── lightSpeedOutRight.css │ │ │ │ ├── lightSpeedInLeft.css │ │ │ │ └── lightSpeedInRight.css │ │ │ ├── specials │ │ │ │ ├── rollOut.css │ │ │ │ ├── rollIn.css │ │ │ │ ├── jackInTheBox.css │ │ │ │ └── hinge.css │ │ │ ├── back_entrances │ │ │ │ ├── backInUp.css │ │ │ │ ├── backInDown.css │ │ │ │ ├── backInLeft.css │ │ │ │ └── backInRight.css │ │ │ ├── back_exits │ │ │ │ ├── backOutUp.css │ │ │ │ ├── backOutDown.css │ │ │ │ ├── backOutLeft.css │ │ │ │ └── backOutRight.css │ │ │ ├── flippers │ │ │ │ ├── flipOutX.css │ │ │ │ ├── flipOutY.css │ │ │ │ ├── flipInX.css │ │ │ │ ├── flipInY.css │ │ │ │ └── flip.css │ │ │ ├── bouncing_entrances │ │ │ │ ├── bounceInUp.css │ │ │ │ ├── bounceInDown.css │ │ │ │ ├── bounceInLeft.css │ │ │ │ ├── bounceInRight.css │ │ │ │ └── bounceIn.css │ │ │ ├── _base.css │ │ │ └── animate.css │ │ ├── LICENSE │ │ ├── README.md │ │ └── package.json │ │ ├── fontawesome │ │ └── webfonts │ │ │ ├── fa-solid-900.eot │ │ │ ├── fa-solid-900.ttf │ │ │ ├── fa-brands-400.eot │ │ │ ├── fa-brands-400.ttf │ │ │ ├── fa-brands-400.woff │ │ │ ├── fa-brands-400.woff2 │ │ │ ├── fa-regular-400.eot │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-regular-400.woff │ │ │ ├── fa-solid-900.woff │ │ │ ├── fa-solid-900.woff2 │ │ │ └── fa-regular-400.woff2 │ │ └── reset │ │ └── reset.css ├── network │ └── request.js ├── main.js ├── store │ ├── module │ │ ├── search.js │ │ ├── tab.js │ │ └── url.js │ └── index.js ├── use │ ├── progressive.js │ ├── toID.js │ ├── saveConfig.js │ ├── search.js │ ├── init.js │ ├── trackImg.js │ ├── importConfig.js │ ├── edit.js │ ├── tabAlert.js │ └── urlAlert.js ├── components │ ├── public │ │ ├── lp-dialog │ │ │ ├── lp-dialog.js │ │ │ └── lp-dialog.vue │ │ ├── lp-popover │ │ │ ├── lp-popover.js │ │ │ └── lp-popover.vue │ │ ├── lp-message │ │ │ ├── lp-message.js │ │ │ └── lp-message.vue │ │ ├── tabAlert │ │ │ ├── selectIcon.vue │ │ │ └── index.vue │ │ ├── lp-input │ │ │ └── lp-input.vue │ │ ├── urlAlert │ │ │ ├── index.vue │ │ │ └── selectIcon.vue │ │ ├── iconList │ │ │ ├── iconList.vue │ │ │ └── icons.js │ │ └── lp-button │ │ │ └── lp-button.vue │ ├── main │ │ ├── carousel.vue │ │ ├── search.vue │ │ └── index.vue │ └── tabs │ │ ├── saveConfig.vue │ │ ├── importConfig.vue │ │ └── index.vue ├── App.vue └── utils │ └── utils.js ├── babel.config.js ├── .gitignore ├── interfaceTest.js ├── vue.config.js ├── package.json ├── LICENSE ├── README.md └── app.js /showImg/gif1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/showImg/gif1.gif -------------------------------------------------------------------------------- /showImg/gif2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/showImg/gif2.gif -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /showImg/current1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/showImg/current1.jpg -------------------------------------------------------------------------------- /showImg/origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/showImg/origin.png -------------------------------------------------------------------------------- /src/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/src/assets/img/logo.png -------------------------------------------------------------------------------- /src/assets/img/myWx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/src/assets/img/myWx.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/_vars.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --animate-duration: 1s; 3 | --animate-delay: 1s; 4 | --animate-repeat: 1; 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/css/fontawesome/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/src/assets/css/fontawesome/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /src/assets/css/fontawesome/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/src/assets/css/fontawesome/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /src/assets/css/fontawesome/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/src/assets/css/fontawesome/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /src/assets/css/fontawesome/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/src/assets/css/fontawesome/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /src/assets/css/fontawesome/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/src/assets/css/fontawesome/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /src/assets/css/fontawesome/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/src/assets/css/fontawesome/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /src/assets/css/fontawesome/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/src/assets/css/fontawesome/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /src/assets/css/fontawesome/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/src/assets/css/fontawesome/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /src/assets/css/fontawesome/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/src/assets/css/fontawesome/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /src/assets/css/fontawesome/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/src/assets/css/fontawesome/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /src/assets/css/fontawesome/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/src/assets/css/fontawesome/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /src/assets/css/fontawesome/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero2one3/nav-url/HEAD/src/assets/css/fontawesome/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_entrances/fadeIn.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeIn { 2 | from { 3 | opacity: 0; 4 | } 5 | 6 | to { 7 | opacity: 1; 8 | } 9 | } 10 | 11 | .fadeIn { 12 | animation-name: fadeIn; 13 | } 14 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_exits/fadeOut.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeOut { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | opacity: 0; 8 | } 9 | } 10 | 11 | .fadeOut { 12 | animation-name: fadeOut; 13 | } 14 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/attention_seekers/flash.css: -------------------------------------------------------------------------------- 1 | @keyframes flash { 2 | from, 3 | 50%, 4 | to { 5 | opacity: 1; 6 | } 7 | 8 | 25%, 9 | 75% { 10 | opacity: 0; 11 | } 12 | } 13 | 14 | .flash { 15 | animation-name: flash; 16 | } 17 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/zooming_entrances/zoomIn.css: -------------------------------------------------------------------------------- 1 | @keyframes zoomIn { 2 | from { 3 | opacity: 0; 4 | transform: scale3d(0.3, 0.3, 0.3); 5 | } 6 | 7 | 50% { 8 | opacity: 1; 9 | } 10 | } 11 | 12 | .zoomIn { 13 | animation-name: zoomIn; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_exits/fadeOutUp.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeOutUp { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | opacity: 0; 8 | transform: translate3d(0, -100%, 0); 9 | } 10 | } 11 | 12 | .fadeOutUp { 13 | animation-name: fadeOutUp; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_exits/fadeOutDown.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeOutDown { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | opacity: 0; 8 | transform: translate3d(0, 100%, 0); 9 | } 10 | } 11 | 12 | .fadeOutDown { 13 | animation-name: fadeOutDown; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_exits/fadeOutLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeOutLeft { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | opacity: 0; 8 | transform: translate3d(-100%, 0, 0); 9 | } 10 | } 11 | 12 | .fadeOutLeft { 13 | animation-name: fadeOutLeft; 14 | } 15 | -------------------------------------------------------------------------------- /src/network/request.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | function request(config) { 4 | const instance = axios.create({ 5 | baseURL: 'http://47.117.1.239:4000/api', 6 | timeout: 10000 7 | }) 8 | 9 | return instance(config) 10 | } 11 | 12 | export default request 13 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_exits/fadeOutRight.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeOutRight { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | opacity: 0; 8 | transform: translate3d(100%, 0, 0); 9 | } 10 | } 11 | 12 | .fadeOutRight { 13 | animation-name: fadeOutRight; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_exits/fadeOutUpBig.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeOutUpBig { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | opacity: 0; 8 | transform: translate3d(0, -2000px, 0); 9 | } 10 | } 11 | 12 | .fadeOutUpBig { 13 | animation-name: fadeOutUpBig; 14 | } 15 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue' 3 | import vuex from './store/index' 4 | import vPopover from '@/components/public/lp-popover/lp-popover' 5 | 6 | const app = createApp(App) 7 | 8 | // 注册自定义指令 v-popver 9 | vPopover(app) 10 | 11 | app.use(vuex).mount('#app') 12 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_exits/fadeOutDownBig.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeOutDownBig { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | opacity: 0; 8 | transform: translate3d(0, 2000px, 0); 9 | } 10 | } 11 | 12 | .fadeOutDownBig { 13 | animation-name: fadeOutDownBig; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_exits/fadeOutLeftBig.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeOutLeftBig { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | opacity: 0; 8 | transform: translate3d(-2000px, 0, 0); 9 | } 10 | } 11 | 12 | .fadeOutLeftBig { 13 | animation-name: fadeOutLeftBig; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_exits/fadeOutRightBig.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeOutRightBig { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | opacity: 0; 8 | transform: translate3d(2000px, 0, 0); 9 | } 10 | } 11 | 12 | .fadeOutRightBig { 13 | animation-name: fadeOutRightBig; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/sliding_entrances/slideInUp.css: -------------------------------------------------------------------------------- 1 | @keyframes slideInUp { 2 | from { 3 | transform: translate3d(0, 100%, 0); 4 | visibility: visible; 5 | } 6 | 7 | to { 8 | transform: translate3d(0, 0, 0); 9 | } 10 | } 11 | 12 | .slideInUp { 13 | animation-name: slideInUp; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/sliding_exits/slideOutUp.css: -------------------------------------------------------------------------------- 1 | @keyframes slideOutUp { 2 | from { 3 | transform: translate3d(0, 0, 0); 4 | } 5 | 6 | to { 7 | visibility: hidden; 8 | transform: translate3d(0, -100%, 0); 9 | } 10 | } 11 | 12 | .slideOutUp { 13 | animation-name: slideOutUp; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/rotating_exits/rotateOut.css: -------------------------------------------------------------------------------- 1 | @keyframes rotateOut { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | transform: rotate3d(0, 0, 1, 200deg); 8 | opacity: 0; 9 | } 10 | } 11 | 12 | .rotateOut { 13 | animation-name: rotateOut; 14 | transform-origin: center; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_entrances/fadeInUp.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeInUp { 2 | from { 3 | opacity: 0; 4 | transform: translate3d(0, 100%, 0); 5 | } 6 | 7 | to { 8 | opacity: 1; 9 | transform: translate3d(0, 0, 0); 10 | } 11 | } 12 | 13 | .fadeInUp { 14 | animation-name: fadeInUp; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/sliding_entrances/slideInDown.css: -------------------------------------------------------------------------------- 1 | @keyframes slideInDown { 2 | from { 3 | transform: translate3d(0, -100%, 0); 4 | visibility: visible; 5 | } 6 | 7 | to { 8 | transform: translate3d(0, 0, 0); 9 | } 10 | } 11 | 12 | .slideInDown { 13 | animation-name: slideInDown; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/sliding_entrances/slideInLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes slideInLeft { 2 | from { 3 | transform: translate3d(-100%, 0, 0); 4 | visibility: visible; 5 | } 6 | 7 | to { 8 | transform: translate3d(0, 0, 0); 9 | } 10 | } 11 | 12 | .slideInLeft { 13 | animation-name: slideInLeft; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/sliding_exits/slideOutDown.css: -------------------------------------------------------------------------------- 1 | @keyframes slideOutDown { 2 | from { 3 | transform: translate3d(0, 0, 0); 4 | } 5 | 6 | to { 7 | visibility: hidden; 8 | transform: translate3d(0, 100%, 0); 9 | } 10 | } 11 | 12 | .slideOutDown { 13 | animation-name: slideOutDown; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/sliding_exits/slideOutLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes slideOutLeft { 2 | from { 3 | transform: translate3d(0, 0, 0); 4 | } 5 | 6 | to { 7 | visibility: hidden; 8 | transform: translate3d(-100%, 0, 0); 9 | } 10 | } 11 | 12 | .slideOutLeft { 13 | animation-name: slideOutLeft; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/zooming_exits/zoomOut.css: -------------------------------------------------------------------------------- 1 | @keyframes zoomOut { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | 50% { 7 | opacity: 0; 8 | transform: scale3d(0.3, 0.3, 0.3); 9 | } 10 | 11 | to { 12 | opacity: 0; 13 | } 14 | } 15 | 16 | .zoomOut { 17 | animation-name: zoomOut; 18 | } 19 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/sliding_entrances/slideInRight.css: -------------------------------------------------------------------------------- 1 | @keyframes slideInRight { 2 | from { 3 | transform: translate3d(100%, 0, 0); 4 | visibility: visible; 5 | } 6 | 7 | to { 8 | transform: translate3d(0, 0, 0); 9 | } 10 | } 11 | 12 | .slideInRight { 13 | animation-name: slideInRight; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/sliding_exits/slideOutRight.css: -------------------------------------------------------------------------------- 1 | @keyframes slideOutRight { 2 | from { 3 | transform: translate3d(0, 0, 0); 4 | } 5 | 6 | to { 7 | visibility: hidden; 8 | transform: translate3d(100%, 0, 0); 9 | } 10 | } 11 | 12 | .slideOutRight { 13 | animation-name: slideOutRight; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_entrances/fadeInDown.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeInDown { 2 | from { 3 | opacity: 0; 4 | transform: translate3d(0, -100%, 0); 5 | } 6 | 7 | to { 8 | opacity: 1; 9 | transform: translate3d(0, 0, 0); 10 | } 11 | } 12 | 13 | .fadeInDown { 14 | animation-name: fadeInDown; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_entrances/fadeInLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeInLeft { 2 | from { 3 | opacity: 0; 4 | transform: translate3d(-100%, 0, 0); 5 | } 6 | 7 | to { 8 | opacity: 1; 9 | transform: translate3d(0, 0, 0); 10 | } 11 | } 12 | 13 | .fadeInLeft { 14 | animation-name: fadeInLeft; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_entrances/fadeInRight.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeInRight { 2 | from { 3 | opacity: 0; 4 | transform: translate3d(100%, 0, 0); 5 | } 6 | 7 | to { 8 | opacity: 1; 9 | transform: translate3d(0, 0, 0); 10 | } 11 | } 12 | 13 | .fadeInRight { 14 | animation-name: fadeInRight; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_entrances/fadeInUpBig.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeInUpBig { 2 | from { 3 | opacity: 0; 4 | transform: translate3d(0, 2000px, 0); 5 | } 6 | 7 | to { 8 | opacity: 1; 9 | transform: translate3d(0, 0, 0); 10 | } 11 | } 12 | 13 | .fadeInUpBig { 14 | animation-name: fadeInUpBig; 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | up2 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_entrances/fadeInDownBig.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeInDownBig { 2 | from { 3 | opacity: 0; 4 | transform: translate3d(0, -2000px, 0); 5 | } 6 | 7 | to { 8 | opacity: 1; 9 | transform: translate3d(0, 0, 0); 10 | } 11 | } 12 | 13 | .fadeInDownBig { 14 | animation-name: fadeInDownBig; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_entrances/fadeInLeftBig.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeInLeftBig { 2 | from { 3 | opacity: 0; 4 | transform: translate3d(-2000px, 0, 0); 5 | } 6 | 7 | to { 8 | opacity: 1; 9 | transform: translate3d(0, 0, 0); 10 | } 11 | } 12 | 13 | .fadeInLeftBig { 14 | animation-name: fadeInLeftBig; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_entrances/fadeInTopLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeInTopLeft { 2 | from { 3 | opacity: 0; 4 | transform: translate3d(-100%, -100%, 0); 5 | } 6 | to { 7 | opacity: 1; 8 | transform: translate3d(0, 0, 0); 9 | } 10 | } 11 | 12 | .fadeInTopLeft { 13 | animation-name: fadeInTopLeft; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_entrances/fadeInTopRight.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeInTopRight { 2 | from { 3 | opacity: 0; 4 | transform: translate3d(100%, -100%, 0); 5 | } 6 | to { 7 | opacity: 1; 8 | transform: translate3d(0, 0, 0); 9 | } 10 | } 11 | 12 | .fadeInTopRight { 13 | animation-name: fadeInTopRight; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_exits/fadeOutTopLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeOutTopLeft { 2 | from { 3 | opacity: 1; 4 | transform: translate3d(0, 0, 0); 5 | } 6 | to { 7 | opacity: 0; 8 | transform: translate3d(-100%, -100%, 0); 9 | } 10 | } 11 | 12 | .fadeOutTopLeft { 13 | animation-name: fadeOutTopLeft; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_exits/fadeOutTopRight.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeOutTopRight { 2 | from { 3 | opacity: 1; 4 | transform: translate3d(0, 0, 0); 5 | } 6 | to { 7 | opacity: 0; 8 | transform: translate3d(100%, -100%, 0); 9 | } 10 | } 11 | 12 | .fadeOutTopRight { 13 | animation-name: fadeOutTopRight; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_entrances/fadeInRightBig.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeInRightBig { 2 | from { 3 | opacity: 0; 4 | transform: translate3d(2000px, 0, 0); 5 | } 6 | 7 | to { 8 | opacity: 1; 9 | transform: translate3d(0, 0, 0); 10 | } 11 | } 12 | 13 | .fadeInRightBig { 14 | animation-name: fadeInRightBig; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/rotating_exits/rotateOutUpLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes rotateOutUpLeft { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | transform: rotate3d(0, 0, 1, -45deg); 8 | opacity: 0; 9 | } 10 | } 11 | 12 | .rotateOutUpLeft { 13 | animation-name: rotateOutUpLeft; 14 | transform-origin: left bottom; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/rotating_exits/rotateOutUpRight.css: -------------------------------------------------------------------------------- 1 | @keyframes rotateOutUpRight { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | transform: rotate3d(0, 0, 1, 90deg); 8 | opacity: 0; 9 | } 10 | } 11 | 12 | .rotateOutUpRight { 13 | animation-name: rotateOutUpRight; 14 | transform-origin: right bottom; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_entrances/fadeInBottomLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeInBottomLeft { 2 | from { 3 | opacity: 0; 4 | transform: translate3d(-100%, 100%, 0); 5 | } 6 | to { 7 | opacity: 1; 8 | transform: translate3d(0, 0, 0); 9 | } 10 | } 11 | 12 | .fadeInBottomLeft { 13 | animation-name: fadeInBottomLeft; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_entrances/fadeInBottomRight.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeInBottomRight { 2 | from { 3 | opacity: 0; 4 | transform: translate3d(100%, 100%, 0); 5 | } 6 | to { 7 | opacity: 1; 8 | transform: translate3d(0, 0, 0); 9 | } 10 | } 11 | 12 | .fadeInBottomRight { 13 | animation-name: fadeInBottomRight; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_exits/fadeOutBottomLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeOutBottomLeft { 2 | from { 3 | opacity: 1; 4 | transform: translate3d(0, 0, 0); 5 | } 6 | to { 7 | opacity: 0; 8 | transform: translate3d(-100%, 100%, 0); 9 | } 10 | } 11 | 12 | .fadeOutBottomLeft { 13 | animation-name: fadeOutBottomLeft; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/fading_exits/fadeOutBottomRight.css: -------------------------------------------------------------------------------- 1 | @keyframes fadeOutBottomRight { 2 | from { 3 | opacity: 1; 4 | transform: translate3d(0, 0, 0); 5 | } 6 | to { 7 | opacity: 0; 8 | transform: translate3d(100%, 100%, 0); 9 | } 10 | } 11 | 12 | .fadeOutBottomRight { 13 | animation-name: fadeOutBottomRight; 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/rotating_exits/rotateOutDownLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes rotateOutDownLeft { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | transform: rotate3d(0, 0, 1, 45deg); 8 | opacity: 0; 9 | } 10 | } 11 | 12 | .rotateOutDownLeft { 13 | animation-name: rotateOutDownLeft; 14 | transform-origin: left bottom; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/rotating_entrances/rotateIn.css: -------------------------------------------------------------------------------- 1 | @keyframes rotateIn { 2 | from { 3 | transform: rotate3d(0, 0, 1, -200deg); 4 | opacity: 0; 5 | } 6 | 7 | to { 8 | transform: translate3d(0, 0, 0); 9 | opacity: 1; 10 | } 11 | } 12 | 13 | .rotateIn { 14 | animation-name: rotateIn; 15 | transform-origin: center; 16 | } 17 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/rotating_exits/rotateOutDownRight.css: -------------------------------------------------------------------------------- 1 | @keyframes rotateOutDownRight { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | transform: rotate3d(0, 0, 1, -45deg); 8 | opacity: 0; 9 | } 10 | } 11 | 12 | .rotateOutDownRight { 13 | animation-name: rotateOutDownRight; 14 | transform-origin: right bottom; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/bouncing_exits/bounceOutLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes bounceOutLeft { 2 | 20% { 3 | opacity: 1; 4 | transform: translate3d(20px, 0, 0) scaleX(0.9); 5 | } 6 | 7 | to { 8 | opacity: 0; 9 | transform: translate3d(-2000px, 0, 0) scaleX(2); 10 | } 11 | } 12 | 13 | .bounceOutLeft { 14 | animation-name: bounceOutLeft; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/lightspeed/lightSpeedOutLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes lightSpeedOutLeft { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | transform: translate3d(-100%, 0, 0) skewX(-30deg); 8 | opacity: 0; 9 | } 10 | } 11 | 12 | .lightSpeedOutLeft { 13 | animation-name: lightSpeedOutLeft; 14 | animation-timing-function: ease-in; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/lightspeed/lightSpeedOutRight.css: -------------------------------------------------------------------------------- 1 | @keyframes lightSpeedOutRight { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | transform: translate3d(100%, 0, 0) skewX(30deg); 8 | opacity: 0; 9 | } 10 | } 11 | 12 | .lightSpeedOutRight { 13 | animation-name: lightSpeedOutRight; 14 | animation-timing-function: ease-in; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/bouncing_exits/bounceOutRight.css: -------------------------------------------------------------------------------- 1 | @keyframes bounceOutRight { 2 | 20% { 3 | opacity: 1; 4 | transform: translate3d(-20px, 0, 0) scaleX(0.9); 5 | } 6 | 7 | to { 8 | opacity: 0; 9 | transform: translate3d(2000px, 0, 0) scaleX(2); 10 | } 11 | } 12 | 13 | .bounceOutRight { 14 | animation-name: bounceOutRight; 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/specials/rollOut.css: -------------------------------------------------------------------------------- 1 | /* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ 2 | 3 | @keyframes rollOut { 4 | from { 5 | opacity: 1; 6 | } 7 | 8 | to { 9 | opacity: 0; 10 | transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); 11 | } 12 | } 13 | 14 | .rollOut { 15 | animation-name: rollOut; 16 | } 17 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/rotating_entrances/rotateInUpLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes rotateInUpLeft { 2 | from { 3 | transform: rotate3d(0, 0, 1, 45deg); 4 | opacity: 0; 5 | } 6 | 7 | to { 8 | transform: translate3d(0, 0, 0); 9 | opacity: 1; 10 | } 11 | } 12 | 13 | .rotateInUpLeft { 14 | animation-name: rotateInUpLeft; 15 | transform-origin: left bottom; 16 | } 17 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/rotating_entrances/rotateInUpRight.css: -------------------------------------------------------------------------------- 1 | @keyframes rotateInUpRight { 2 | from { 3 | transform: rotate3d(0, 0, 1, -90deg); 4 | opacity: 0; 5 | } 6 | 7 | to { 8 | transform: translate3d(0, 0, 0); 9 | opacity: 1; 10 | } 11 | } 12 | 13 | .rotateInUpRight { 14 | animation-name: rotateInUpRight; 15 | transform-origin: right bottom; 16 | } 17 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/rotating_entrances/rotateInDownLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes rotateInDownLeft { 2 | from { 3 | transform: rotate3d(0, 0, 1, -45deg); 4 | opacity: 0; 5 | } 6 | 7 | to { 8 | transform: translate3d(0, 0, 0); 9 | opacity: 1; 10 | } 11 | } 12 | 13 | .rotateInDownLeft { 14 | animation-name: rotateInDownLeft; 15 | transform-origin: left bottom; 16 | } 17 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/rotating_entrances/rotateInDownRight.css: -------------------------------------------------------------------------------- 1 | @keyframes rotateInDownRight { 2 | from { 3 | transform: rotate3d(0, 0, 1, 45deg); 4 | opacity: 0; 5 | } 6 | 7 | to { 8 | transform: translate3d(0, 0, 0); 9 | opacity: 1; 10 | } 11 | } 12 | 13 | .rotateInDownRight { 14 | animation-name: rotateInDownRight; 15 | transform-origin: right bottom; 16 | } 17 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/back_entrances/backInUp.css: -------------------------------------------------------------------------------- 1 | @keyframes backInUp { 2 | 0% { 3 | transform: translateY(1200px) scale(0.7); 4 | opacity: 0.7; 5 | } 6 | 7 | 80% { 8 | transform: translateY(0px) scale(0.7); 9 | opacity: 0.7; 10 | } 11 | 12 | 100% { 13 | transform: scale(1); 14 | opacity: 1; 15 | } 16 | } 17 | 18 | .backInUp { 19 | animation-name: backInUp; 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/back_exits/backOutUp.css: -------------------------------------------------------------------------------- 1 | @keyframes backOutUp { 2 | 0% { 3 | transform: scale(1); 4 | opacity: 1; 5 | } 6 | 7 | 20% { 8 | transform: translateY(0px) scale(0.7); 9 | opacity: 0.7; 10 | } 11 | 12 | 100% { 13 | transform: translateY(-700px) scale(0.7); 14 | opacity: 0.7; 15 | } 16 | } 17 | 18 | .backOutUp { 19 | animation-name: backOutUp; 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/zooming_exits/zoomOutLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes zoomOutLeft { 2 | 40% { 3 | opacity: 1; 4 | transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); 5 | } 6 | 7 | to { 8 | opacity: 0; 9 | transform: scale(0.1) translate3d(-2000px, 0, 0); 10 | } 11 | } 12 | 13 | .zoomOutLeft { 14 | animation-name: zoomOutLeft; 15 | transform-origin: left center; 16 | } 17 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/zooming_exits/zoomOutRight.css: -------------------------------------------------------------------------------- 1 | @keyframes zoomOutRight { 2 | 40% { 3 | opacity: 1; 4 | transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); 5 | } 6 | 7 | to { 8 | opacity: 0; 9 | transform: scale(0.1) translate3d(2000px, 0, 0); 10 | } 11 | } 12 | 13 | .zoomOutRight { 14 | animation-name: zoomOutRight; 15 | transform-origin: right center; 16 | } 17 | -------------------------------------------------------------------------------- /src/store/module/search.js: -------------------------------------------------------------------------------- 1 | const moduleSearch = { 2 | state: { 3 | isSearch: false, 4 | searchWord: '' 5 | }, 6 | mutations: { 7 | changeSearchWord(state, payload) { 8 | state.searchWord = payload 9 | }, 10 | changeIsSearch(state, payload) { 11 | state.isSearch = payload 12 | } 13 | } 14 | } 15 | 16 | export default moduleSearch 17 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/back_entrances/backInDown.css: -------------------------------------------------------------------------------- 1 | @keyframes backInDown { 2 | 0% { 3 | transform: translateY(-1200px) scale(0.7); 4 | opacity: 0.7; 5 | } 6 | 7 | 80% { 8 | transform: translateY(0px) scale(0.7); 9 | opacity: 0.7; 10 | } 11 | 12 | 100% { 13 | transform: scale(1); 14 | opacity: 1; 15 | } 16 | } 17 | 18 | .backInDown { 19 | animation-name: backInDown; 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/back_entrances/backInLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes backInLeft { 2 | 0% { 3 | transform: translateX(-2000px) scale(0.7); 4 | opacity: 0.7; 5 | } 6 | 7 | 80% { 8 | transform: translateX(0px) scale(0.7); 9 | opacity: 0.7; 10 | } 11 | 12 | 100% { 13 | transform: scale(1); 14 | opacity: 1; 15 | } 16 | } 17 | 18 | .backInLeft { 19 | animation-name: backInLeft; 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/back_exits/backOutDown.css: -------------------------------------------------------------------------------- 1 | @keyframes backOutDown { 2 | 0% { 3 | transform: scale(1); 4 | opacity: 1; 5 | } 6 | 7 | 20% { 8 | transform: translateY(0px) scale(0.7); 9 | opacity: 0.7; 10 | } 11 | 12 | 100% { 13 | transform: translateY(700px) scale(0.7); 14 | opacity: 0.7; 15 | } 16 | } 17 | 18 | .backOutDown { 19 | animation-name: backOutDown; 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/back_exits/backOutLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes backOutLeft { 2 | 0% { 3 | transform: scale(1); 4 | opacity: 1; 5 | } 6 | 7 | 20% { 8 | transform: translateX(0px) scale(0.7); 9 | opacity: 0.7; 10 | } 11 | 12 | 100% { 13 | transform: translateX(-2000px) scale(0.7); 14 | opacity: 0.7; 15 | } 16 | } 17 | 18 | .backOutLeft { 19 | animation-name: backOutLeft; 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/specials/rollIn.css: -------------------------------------------------------------------------------- 1 | /* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ 2 | 3 | @keyframes rollIn { 4 | from { 5 | opacity: 0; 6 | transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); 7 | } 8 | 9 | to { 10 | opacity: 1; 11 | transform: translate3d(0, 0, 0); 12 | } 13 | } 14 | 15 | .rollIn { 16 | animation-name: rollIn; 17 | } 18 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/back_entrances/backInRight.css: -------------------------------------------------------------------------------- 1 | @keyframes backInRight { 2 | 0% { 3 | transform: translateX(2000px) scale(0.7); 4 | opacity: 0.7; 5 | } 6 | 7 | 80% { 8 | transform: translateX(0px) scale(0.7); 9 | opacity: 0.7; 10 | } 11 | 12 | 100% { 13 | transform: scale(1); 14 | opacity: 1; 15 | } 16 | } 17 | 18 | .backInRight { 19 | animation-name: backInRight; 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/back_exits/backOutRight.css: -------------------------------------------------------------------------------- 1 | @keyframes backOutRight { 2 | 0% { 3 | transform: scale(1); 4 | opacity: 1; 5 | } 6 | 7 | 20% { 8 | transform: translateX(0px) scale(0.7); 9 | opacity: 0.7; 10 | } 11 | 12 | 100% { 13 | transform: translateX(2000px) scale(0.7); 14 | opacity: 0.7; 15 | } 16 | } 17 | 18 | .backOutRight { 19 | animation-name: backOutRight; 20 | } 21 | -------------------------------------------------------------------------------- /interfaceTest.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios') 2 | 3 | axios({ 4 | url: 'http://localhost:4000/api', 5 | params: { 6 | target: 'icon', 7 | targetUrl: 'https://segmentfault.com/' 8 | } 9 | }) 10 | .then(res => { 11 | console.log(res.data); 12 | }) 13 | 14 | // https://apidingtest.hexiaoxiang.com/./favicon-32x32.png 15 | // https://apidingtest.hexiaoxiang.com/dingcardtask/swagger/index.html/favicon-32x32.png -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/attention_seekers/shake.css: -------------------------------------------------------------------------------- 1 | @keyframes shake { 2 | from, 3 | to { 4 | transform: translate3d(0, 0, 0); 5 | } 6 | 7 | 10%, 8 | 30%, 9 | 50%, 10 | 70%, 11 | 90% { 12 | transform: translate3d(-10px, 0, 0); 13 | } 14 | 15 | 20%, 16 | 40%, 17 | 60%, 18 | 80% { 19 | transform: translate3d(10px, 0, 0); 20 | } 21 | } 22 | 23 | .shake { 24 | animation-name: shake; 25 | } 26 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/attention_seekers/shakeX.css: -------------------------------------------------------------------------------- 1 | @keyframes shakeX { 2 | from, 3 | to { 4 | transform: translate3d(0, 0, 0); 5 | } 6 | 7 | 10%, 8 | 30%, 9 | 50%, 10 | 70%, 11 | 90% { 12 | transform: translate3d(-10px, 0, 0); 13 | } 14 | 15 | 20%, 16 | 40%, 17 | 60%, 18 | 80% { 19 | transform: translate3d(10px, 0, 0); 20 | } 21 | } 22 | 23 | .shakeX { 24 | animation-name: shakeX; 25 | } 26 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/attention_seekers/shakeY.css: -------------------------------------------------------------------------------- 1 | @keyframes shakeY { 2 | from, 3 | to { 4 | transform: translate3d(0, 0, 0); 5 | } 6 | 7 | 10%, 8 | 30%, 9 | 50%, 10 | 70%, 11 | 90% { 12 | transform: translate3d(0, -10px, 0); 13 | } 14 | 15 | 20%, 16 | 40%, 17 | 60%, 18 | 80% { 19 | transform: translate3d(0, 10px, 0); 20 | } 21 | } 22 | 23 | .shakeY { 24 | animation-name: shakeY; 25 | } 26 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/bouncing_exits/bounceOutUp.css: -------------------------------------------------------------------------------- 1 | @keyframes bounceOutUp { 2 | 20% { 3 | transform: translate3d(0, -10px, 0) scaleY(0.985); 4 | } 5 | 6 | 40%, 7 | 45% { 8 | opacity: 1; 9 | transform: translate3d(0, 20px, 0) scaleY(0.9); 10 | } 11 | 12 | to { 13 | opacity: 0; 14 | transform: translate3d(0, -2000px, 0) scaleY(3); 15 | } 16 | } 17 | 18 | .bounceOutUp { 19 | animation-name: bounceOutUp; 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/attention_seekers/pulse.css: -------------------------------------------------------------------------------- 1 | /* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ 2 | 3 | @keyframes pulse { 4 | from { 5 | transform: scale3d(1, 1, 1); 6 | } 7 | 8 | 50% { 9 | transform: scale3d(1.05, 1.05, 1.05); 10 | } 11 | 12 | to { 13 | transform: scale3d(1, 1, 1); 14 | } 15 | } 16 | 17 | .pulse { 18 | animation-name: pulse; 19 | animation-timing-function: ease-in-out; 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/bouncing_exits/bounceOutDown.css: -------------------------------------------------------------------------------- 1 | @keyframes bounceOutDown { 2 | 20% { 3 | transform: translate3d(0, 10px, 0) scaleY(0.985); 4 | } 5 | 6 | 40%, 7 | 45% { 8 | opacity: 1; 9 | transform: translate3d(0, -20px, 0) scaleY(0.9); 10 | } 11 | 12 | to { 13 | opacity: 0; 14 | transform: translate3d(0, 2000px, 0) scaleY(3); 15 | } 16 | } 17 | 18 | .bounceOutDown { 19 | animation-name: bounceOutDown; 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/bouncing_exits/bounceOut.css: -------------------------------------------------------------------------------- 1 | @keyframes bounceOut { 2 | 20% { 3 | transform: scale3d(0.9, 0.9, 0.9); 4 | } 5 | 6 | 50%, 7 | 55% { 8 | opacity: 1; 9 | transform: scale3d(1.1, 1.1, 1.1); 10 | } 11 | 12 | to { 13 | opacity: 0; 14 | transform: scale3d(0.3, 0.3, 0.3); 15 | } 16 | } 17 | 18 | .bounceOut { 19 | animation-duration: calc(var(--animate-duration) * 0.75); 20 | animation-name: bounceOut; 21 | } 22 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/specials/jackInTheBox.css: -------------------------------------------------------------------------------- 1 | @keyframes jackInTheBox { 2 | from { 3 | opacity: 0; 4 | transform: scale(0.1) rotate(30deg); 5 | transform-origin: center bottom; 6 | } 7 | 8 | 50% { 9 | transform: rotate(-10deg); 10 | } 11 | 12 | 70% { 13 | transform: rotate(3deg); 14 | } 15 | 16 | to { 17 | opacity: 1; 18 | transform: scale(1); 19 | } 20 | } 21 | 22 | .jackInTheBox { 23 | animation-name: jackInTheBox; 24 | } 25 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/lightspeed/lightSpeedInLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes lightSpeedInLeft { 2 | from { 3 | transform: translate3d(-100%, 0, 0) skewX(30deg); 4 | opacity: 0; 5 | } 6 | 7 | 60% { 8 | transform: skewX(-20deg); 9 | opacity: 1; 10 | } 11 | 12 | 80% { 13 | transform: skewX(5deg); 14 | } 15 | 16 | to { 17 | transform: translate3d(0, 0, 0); 18 | } 19 | } 20 | 21 | .lightSpeedInLeft { 22 | animation-name: lightSpeedInLeft; 23 | animation-timing-function: ease-out; 24 | } 25 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/attention_seekers/swing.css: -------------------------------------------------------------------------------- 1 | @keyframes swing { 2 | 20% { 3 | transform: rotate3d(0, 0, 1, 15deg); 4 | } 5 | 6 | 40% { 7 | transform: rotate3d(0, 0, 1, -10deg); 8 | } 9 | 10 | 60% { 11 | transform: rotate3d(0, 0, 1, 5deg); 12 | } 13 | 14 | 80% { 15 | transform: rotate3d(0, 0, 1, -5deg); 16 | } 17 | 18 | to { 19 | transform: rotate3d(0, 0, 1, 0deg); 20 | } 21 | } 22 | 23 | .swing { 24 | transform-origin: top center; 25 | animation-name: swing; 26 | } 27 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/lightspeed/lightSpeedInRight.css: -------------------------------------------------------------------------------- 1 | @keyframes lightSpeedInRight { 2 | from { 3 | transform: translate3d(100%, 0, 0) skewX(-30deg); 4 | opacity: 0; 5 | } 6 | 7 | 60% { 8 | transform: skewX(20deg); 9 | opacity: 1; 10 | } 11 | 12 | 80% { 13 | transform: skewX(-5deg); 14 | } 15 | 16 | to { 17 | transform: translate3d(0, 0, 0); 18 | } 19 | } 20 | 21 | .lightSpeedInRight { 22 | animation-name: lightSpeedInRight; 23 | animation-timing-function: ease-out; 24 | } 25 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/zooming_entrances/zoomInUp.css: -------------------------------------------------------------------------------- 1 | @keyframes zoomInUp { 2 | from { 3 | opacity: 0; 4 | transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); 5 | animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); 6 | } 7 | 8 | 60% { 9 | opacity: 1; 10 | transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); 11 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); 12 | } 13 | } 14 | 15 | .zoomInUp { 16 | animation-name: zoomInUp; 17 | } 18 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/flippers/flipOutX.css: -------------------------------------------------------------------------------- 1 | @keyframes flipOutX { 2 | from { 3 | transform: perspective(400px); 4 | } 5 | 6 | 30% { 7 | transform: perspective(400px) rotate3d(1, 0, 0, -20deg); 8 | opacity: 1; 9 | } 10 | 11 | to { 12 | transform: perspective(400px) rotate3d(1, 0, 0, 90deg); 13 | opacity: 0; 14 | } 15 | } 16 | 17 | .flipOutX { 18 | animation-duration: calc(var(--animate-duration) * 0.75); 19 | animation-name: flipOutX; 20 | backface-visibility: visible !important; 21 | } 22 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/flippers/flipOutY.css: -------------------------------------------------------------------------------- 1 | @keyframes flipOutY { 2 | from { 3 | transform: perspective(400px); 4 | } 5 | 6 | 30% { 7 | transform: perspective(400px) rotate3d(0, 1, 0, -15deg); 8 | opacity: 1; 9 | } 10 | 11 | to { 12 | transform: perspective(400px) rotate3d(0, 1, 0, 90deg); 13 | opacity: 0; 14 | } 15 | } 16 | 17 | .flipOutY { 18 | animation-duration: calc(var(--animate-duration) * 0.75); 19 | backface-visibility: visible !important; 20 | animation-name: flipOutY; 21 | } 22 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/zooming_entrances/zoomInDown.css: -------------------------------------------------------------------------------- 1 | @keyframes zoomInDown { 2 | from { 3 | opacity: 0; 4 | transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); 5 | animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); 6 | } 7 | 8 | 60% { 9 | opacity: 1; 10 | transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); 11 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); 12 | } 13 | } 14 | 15 | .zoomInDown { 16 | animation-name: zoomInDown; 17 | } 18 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/zooming_entrances/zoomInLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes zoomInLeft { 2 | from { 3 | opacity: 0; 4 | transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); 5 | animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); 6 | } 7 | 8 | 60% { 9 | opacity: 1; 10 | transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); 11 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); 12 | } 13 | } 14 | 15 | .zoomInLeft { 16 | animation-name: zoomInLeft; 17 | } 18 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/zooming_entrances/zoomInRight.css: -------------------------------------------------------------------------------- 1 | @keyframes zoomInRight { 2 | from { 3 | opacity: 0; 4 | transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); 5 | animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); 6 | } 7 | 8 | 60% { 9 | opacity: 1; 10 | transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); 11 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); 12 | } 13 | } 14 | 15 | .zoomInRight { 16 | animation-name: zoomInRight; 17 | } 18 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/attention_seekers/heartBeat.css: -------------------------------------------------------------------------------- 1 | @keyframes heartBeat { 2 | 0% { 3 | transform: scale(1); 4 | } 5 | 6 | 14% { 7 | transform: scale(1.3); 8 | } 9 | 10 | 28% { 11 | transform: scale(1); 12 | } 13 | 14 | 42% { 15 | transform: scale(1.3); 16 | } 17 | 18 | 70% { 19 | transform: scale(1); 20 | } 21 | } 22 | 23 | .heartBeat { 24 | animation-name: heartBeat; 25 | animation-duration: calc(var(--animate-duration) * 1.3); 26 | animation-timing-function: ease-in-out; 27 | } 28 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/zooming_exits/zoomOutUp.css: -------------------------------------------------------------------------------- 1 | @keyframes zoomOutUp { 2 | 40% { 3 | opacity: 1; 4 | transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); 5 | animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); 6 | } 7 | 8 | to { 9 | opacity: 0; 10 | transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); 11 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); 12 | } 13 | } 14 | 15 | .zoomOutUp { 16 | animation-name: zoomOutUp; 17 | transform-origin: center bottom; 18 | } 19 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/zooming_exits/zoomOutDown.css: -------------------------------------------------------------------------------- 1 | @keyframes zoomOutDown { 2 | 40% { 3 | opacity: 1; 4 | transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); 5 | animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); 6 | } 7 | 8 | to { 9 | opacity: 0; 10 | transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); 11 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); 12 | } 13 | } 14 | 15 | .zoomOutDown { 16 | animation-name: zoomOutDown; 17 | transform-origin: center bottom; 18 | } 19 | -------------------------------------------------------------------------------- /src/use/progressive.js: -------------------------------------------------------------------------------- 1 | // 渐进式渲染 2 | 3 | let progress = 1 4 | 5 | export default function progressive(total = 10) { 6 | let render = () => { 7 | if(progress <= total) { 8 | progress ++ 9 | window.requestAnimationFrame(render) 10 | } 11 | } 12 | 13 | render() 14 | 15 | // 判断是否轮到当前元素渲染 16 | let defer = (n) => { 17 | // 针对渲染总数不确定的情况,自行增加total的值,并进行渲染 18 | if(n >= total) { 19 | total ++ 20 | render() 21 | } 22 | return n <= progress 23 | } 24 | 25 | return defer 26 | } 27 | -------------------------------------------------------------------------------- /src/use/toID.js: -------------------------------------------------------------------------------- 1 | // 点击左侧标签,自动滚动到对应标签内容 2 | 3 | export default function toID(id) { 4 | const content = document.getElementById('content') 5 | const el = document.getElementById(`${id}`) 6 | let start = content.scrollTop 7 | let end = el.offsetTop - 80 8 | let each = start > end ? -1 * Math.abs(start - end) / 20 : Math.abs(start - end) / 20 9 | let count = 0 10 | let scroll = () => { 11 | if(count < 20) { 12 | content.scrollTop += each 13 | count ++ 14 | window.requestAnimationFrame(scroll); 15 | } 16 | } 17 | scroll() 18 | } 19 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/attention_seekers/tada.css: -------------------------------------------------------------------------------- 1 | @keyframes tada { 2 | from { 3 | transform: scale3d(1, 1, 1); 4 | } 5 | 6 | 10%, 7 | 20% { 8 | transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); 9 | } 10 | 11 | 30%, 12 | 50%, 13 | 70%, 14 | 90% { 15 | transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); 16 | } 17 | 18 | 40%, 19 | 60%, 20 | 80% { 21 | transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); 22 | } 23 | 24 | to { 25 | transform: scale3d(1, 1, 1); 26 | } 27 | } 28 | 29 | .tada { 30 | animation-name: tada; 31 | } 32 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/attention_seekers/rubberBand.css: -------------------------------------------------------------------------------- 1 | @keyframes rubberBand { 2 | from { 3 | transform: scale3d(1, 1, 1); 4 | } 5 | 6 | 30% { 7 | transform: scale3d(1.25, 0.75, 1); 8 | } 9 | 10 | 40% { 11 | transform: scale3d(0.75, 1.25, 1); 12 | } 13 | 14 | 50% { 15 | transform: scale3d(1.15, 0.85, 1); 16 | } 17 | 18 | 65% { 19 | transform: scale3d(0.95, 1.05, 1); 20 | } 21 | 22 | 75% { 23 | transform: scale3d(1.05, 0.95, 1); 24 | } 25 | 26 | to { 27 | transform: scale3d(1, 1, 1); 28 | } 29 | } 30 | 31 | .rubberBand { 32 | animation-name: rubberBand; 33 | } 34 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/attention_seekers/headShake.css: -------------------------------------------------------------------------------- 1 | @keyframes headShake { 2 | 0% { 3 | transform: translateX(0); 4 | } 5 | 6 | 6.5% { 7 | transform: translateX(-6px) rotateY(-9deg); 8 | } 9 | 10 | 18.5% { 11 | transform: translateX(5px) rotateY(7deg); 12 | } 13 | 14 | 31.5% { 15 | transform: translateX(-3px) rotateY(-5deg); 16 | } 17 | 18 | 43.5% { 19 | transform: translateX(2px) rotateY(3deg); 20 | } 21 | 22 | 50% { 23 | transform: translateX(0); 24 | } 25 | } 26 | 27 | .headShake { 28 | animation-timing-function: ease-in-out; 29 | animation-name: headShake; 30 | } 31 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const resolve = dir => path.join(__dirname, dir) 3 | 4 | module.exports = { 5 | // devServer: { 6 | // proxy: { 7 | // '/api': { 8 | // target: 'http://localhost:5000/api', 9 | // ws: true, 10 | // changeOrigin: true, 11 | // pathRewrite: { 12 | // '^/api': '' 13 | // }, 14 | // }, 15 | // } 16 | // }, 17 | publicPath:"./", 18 | chainWebpack: config => { 19 | config.resolve.alias 20 | .set('@', resolve('src')) 21 | } 22 | } -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/specials/hinge.css: -------------------------------------------------------------------------------- 1 | @keyframes hinge { 2 | 0% { 3 | animation-timing-function: ease-in-out; 4 | } 5 | 6 | 20%, 7 | 60% { 8 | transform: rotate3d(0, 0, 1, 80deg); 9 | animation-timing-function: ease-in-out; 10 | } 11 | 12 | 40%, 13 | 80% { 14 | transform: rotate3d(0, 0, 1, 60deg); 15 | animation-timing-function: ease-in-out; 16 | opacity: 1; 17 | } 18 | 19 | to { 20 | transform: translate3d(0, 700px, 0); 21 | opacity: 0; 22 | } 23 | } 24 | 25 | .hinge { 26 | animation-duration: calc(var(--animate-duration) * 2); 27 | animation-name: hinge; 28 | transform-origin: top left; 29 | } 30 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue3", 3 | "version": "0.1.3", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build" 8 | }, 9 | "dependencies": { 10 | "animate.css": "^4.1.1", 11 | "axios": "^0.21.0", 12 | "core-js": "^3.6.5", 13 | "vue": "^3.0.0-beta.1", 14 | "vue-router": "^4.0.0-beta.7", 15 | "vuex": "^4.0.0-rc.1" 16 | }, 17 | "devDependencies": { 18 | "@vue/cli-plugin-babel": "~4.5.0", 19 | "@vue/cli-service": "~4.5.0", 20 | "@vue/compiler-sfc": "^3.0.0-beta.1", 21 | "vue-cli-plugin-vue-next": "~0.1.4" 22 | }, 23 | "browserslist": [ 24 | "> 1%", 25 | "last 2 versions", 26 | "not dead" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/flippers/flipInX.css: -------------------------------------------------------------------------------- 1 | @keyframes flipInX { 2 | from { 3 | transform: perspective(400px) rotate3d(1, 0, 0, 90deg); 4 | animation-timing-function: ease-in; 5 | opacity: 0; 6 | } 7 | 8 | 40% { 9 | transform: perspective(400px) rotate3d(1, 0, 0, -20deg); 10 | animation-timing-function: ease-in; 11 | } 12 | 13 | 60% { 14 | transform: perspective(400px) rotate3d(1, 0, 0, 10deg); 15 | opacity: 1; 16 | } 17 | 18 | 80% { 19 | transform: perspective(400px) rotate3d(1, 0, 0, -5deg); 20 | } 21 | 22 | to { 23 | transform: perspective(400px); 24 | } 25 | } 26 | 27 | .flipInX { 28 | backface-visibility: visible !important; 29 | animation-name: flipInX; 30 | } 31 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/flippers/flipInY.css: -------------------------------------------------------------------------------- 1 | @keyframes flipInY { 2 | from { 3 | transform: perspective(400px) rotate3d(0, 1, 0, 90deg); 4 | animation-timing-function: ease-in; 5 | opacity: 0; 6 | } 7 | 8 | 40% { 9 | transform: perspective(400px) rotate3d(0, 1, 0, -20deg); 10 | animation-timing-function: ease-in; 11 | } 12 | 13 | 60% { 14 | transform: perspective(400px) rotate3d(0, 1, 0, 10deg); 15 | opacity: 1; 16 | } 17 | 18 | 80% { 19 | transform: perspective(400px) rotate3d(0, 1, 0, -5deg); 20 | } 21 | 22 | to { 23 | transform: perspective(400px); 24 | } 25 | } 26 | 27 | .flipInY { 28 | backface-visibility: visible !important; 29 | animation-name: flipInY; 30 | } 31 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/bouncing_entrances/bounceInUp.css: -------------------------------------------------------------------------------- 1 | @keyframes bounceInUp { 2 | from, 3 | 60%, 4 | 75%, 5 | 90%, 6 | to { 7 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); 8 | } 9 | 10 | from { 11 | opacity: 0; 12 | transform: translate3d(0, 3000px, 0) scaleY(5); 13 | } 14 | 15 | 60% { 16 | opacity: 1; 17 | transform: translate3d(0, -20px, 0) scaleY(0.9); 18 | } 19 | 20 | 75% { 21 | transform: translate3d(0, 10px, 0) scaleY(0.95); 22 | } 23 | 24 | 90% { 25 | transform: translate3d(0, -5px, 0) scaleY(0.985); 26 | } 27 | 28 | to { 29 | transform: translate3d(0, 0, 0); 30 | } 31 | } 32 | 33 | .bounceInUp { 34 | animation-name: bounceInUp; 35 | } 36 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/bouncing_entrances/bounceInDown.css: -------------------------------------------------------------------------------- 1 | @keyframes bounceInDown { 2 | from, 3 | 60%, 4 | 75%, 5 | 90%, 6 | to { 7 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); 8 | } 9 | 10 | 0% { 11 | opacity: 0; 12 | transform: translate3d(0, -3000px, 0) scaleY(3); 13 | } 14 | 15 | 60% { 16 | opacity: 1; 17 | transform: translate3d(0, 25px, 0) scaleY(0.9); 18 | } 19 | 20 | 75% { 21 | transform: translate3d(0, -10px, 0) scaleY(0.95); 22 | } 23 | 24 | 90% { 25 | transform: translate3d(0, 5px, 0) scaleY(0.985); 26 | } 27 | 28 | to { 29 | transform: translate3d(0, 0, 0); 30 | } 31 | } 32 | 33 | .bounceInDown { 34 | animation-name: bounceInDown; 35 | } 36 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/bouncing_entrances/bounceInLeft.css: -------------------------------------------------------------------------------- 1 | @keyframes bounceInLeft { 2 | from, 3 | 60%, 4 | 75%, 5 | 90%, 6 | to { 7 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); 8 | } 9 | 10 | 0% { 11 | opacity: 0; 12 | transform: translate3d(-3000px, 0, 0) scaleX(3); 13 | } 14 | 15 | 60% { 16 | opacity: 1; 17 | transform: translate3d(25px, 0, 0) scaleX(1); 18 | } 19 | 20 | 75% { 21 | transform: translate3d(-10px, 0, 0) scaleX(0.98); 22 | } 23 | 24 | 90% { 25 | transform: translate3d(5px, 0, 0) scaleX(0.995); 26 | } 27 | 28 | to { 29 | transform: translate3d(0, 0, 0); 30 | } 31 | } 32 | 33 | .bounceInLeft { 34 | animation-name: bounceInLeft; 35 | } 36 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/bouncing_entrances/bounceInRight.css: -------------------------------------------------------------------------------- 1 | @keyframes bounceInRight { 2 | from, 3 | 60%, 4 | 75%, 5 | 90%, 6 | to { 7 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); 8 | } 9 | 10 | from { 11 | opacity: 0; 12 | transform: translate3d(3000px, 0, 0) scaleX(3); 13 | } 14 | 15 | 60% { 16 | opacity: 1; 17 | transform: translate3d(-25px, 0, 0) scaleX(1); 18 | } 19 | 20 | 75% { 21 | transform: translate3d(10px, 0, 0) scaleX(0.98); 22 | } 23 | 24 | 90% { 25 | transform: translate3d(-5px, 0, 0) scaleX(0.995); 26 | } 27 | 28 | to { 29 | transform: translate3d(0, 0, 0); 30 | } 31 | } 32 | 33 | .bounceInRight { 34 | animation-name: bounceInRight; 35 | } 36 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/attention_seekers/wobble.css: -------------------------------------------------------------------------------- 1 | /* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ 2 | 3 | @keyframes wobble { 4 | from { 5 | transform: translate3d(0, 0, 0); 6 | } 7 | 8 | 15% { 9 | transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); 10 | } 11 | 12 | 30% { 13 | transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); 14 | } 15 | 16 | 45% { 17 | transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); 18 | } 19 | 20 | 60% { 21 | transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); 22 | } 23 | 24 | 75% { 25 | transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); 26 | } 27 | 28 | to { 29 | transform: translate3d(0, 0, 0); 30 | } 31 | } 32 | 33 | .wobble { 34 | animation-name: wobble; 35 | } 36 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/attention_seekers/jello.css: -------------------------------------------------------------------------------- 1 | @keyframes jello { 2 | from, 3 | 11.1%, 4 | to { 5 | transform: translate3d(0, 0, 0); 6 | } 7 | 8 | 22.2% { 9 | transform: skewX(-12.5deg) skewY(-12.5deg); 10 | } 11 | 12 | 33.3% { 13 | transform: skewX(6.25deg) skewY(6.25deg); 14 | } 15 | 16 | 44.4% { 17 | transform: skewX(-3.125deg) skewY(-3.125deg); 18 | } 19 | 20 | 55.5% { 21 | transform: skewX(1.5625deg) skewY(1.5625deg); 22 | } 23 | 24 | 66.6% { 25 | transform: skewX(-0.78125deg) skewY(-0.78125deg); 26 | } 27 | 28 | 77.7% { 29 | transform: skewX(0.390625deg) skewY(0.390625deg); 30 | } 31 | 32 | 88.8% { 33 | transform: skewX(-0.1953125deg) skewY(-0.1953125deg); 34 | } 35 | } 36 | 37 | .jello { 38 | animation-name: jello; 39 | transform-origin: center; 40 | } 41 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/bouncing_entrances/bounceIn.css: -------------------------------------------------------------------------------- 1 | @keyframes bounceIn { 2 | from, 3 | 20%, 4 | 40%, 5 | 60%, 6 | 80%, 7 | to { 8 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); 9 | } 10 | 11 | 0% { 12 | opacity: 0; 13 | transform: scale3d(0.3, 0.3, 0.3); 14 | } 15 | 16 | 20% { 17 | transform: scale3d(1.1, 1.1, 1.1); 18 | } 19 | 20 | 40% { 21 | transform: scale3d(0.9, 0.9, 0.9); 22 | } 23 | 24 | 60% { 25 | opacity: 1; 26 | transform: scale3d(1.03, 1.03, 1.03); 27 | } 28 | 29 | 80% { 30 | transform: scale3d(0.97, 0.97, 0.97); 31 | } 32 | 33 | to { 34 | opacity: 1; 35 | transform: scale3d(1, 1, 1); 36 | } 37 | } 38 | 39 | .bounceIn { 40 | animation-duration: calc(var(--animate-duration) * 0.75); 41 | animation-name: bounceIn; 42 | } 43 | -------------------------------------------------------------------------------- /src/components/public/lp-dialog/lp-dialog.js: -------------------------------------------------------------------------------- 1 | import lp_dialog from './lp-dialog.vue' 2 | import {createVNode, render, toRef, watch} from 'vue' 3 | 4 | export const createDialog = (options) => { 5 | if(Object.prototype.toString.call(options) !== '[object Object]') { 6 | console.error('Please enter an object as a parameter'); 7 | } 8 | 9 | options = options ? options : {} 10 | 11 | const instance = createVNode( 12 | lp_dialog, 13 | options 14 | ) 15 | 16 | const container = document.createElement('div') 17 | render(instance, container) 18 | 19 | const status = toRef(instance.component.setupState, 'status') 20 | 21 | return new Promise((resolve, reject) => { 22 | watch(status, (now) => { 23 | if(now == 0) reject(); 24 | else if(now == 1) resolve() 25 | }) 26 | }) 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/attention_seekers/bounce.css: -------------------------------------------------------------------------------- 1 | @keyframes bounce { 2 | from, 3 | 20%, 4 | 53%, 5 | to { 6 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); 7 | transform: translate3d(0, 0, 0); 8 | } 9 | 10 | 40%, 11 | 43% { 12 | animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); 13 | transform: translate3d(0, -30px, 0) scaleY(1.1); 14 | } 15 | 16 | 70% { 17 | animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); 18 | transform: translate3d(0, -15px, 0) scaleY(1.05); 19 | } 20 | 21 | 80% { 22 | transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); 23 | transform: translate3d(0, 0, 0) scaleY(0.95); 24 | } 25 | 26 | 90% { 27 | transform: translate3d(0, -4px, 0) scaleY(1.02); 28 | } 29 | } 30 | 31 | .bounce { 32 | animation-name: bounce; 33 | transform-origin: center bottom; 34 | } 35 | -------------------------------------------------------------------------------- /src/use/saveConfig.js: -------------------------------------------------------------------------------- 1 | /* 保存配置 */ 2 | import { ref } from 'vue' 3 | 4 | // 变量 5 | const isShowSaveAlert = ref(false) // 保存配置弹框是否展示 6 | 7 | export default function saveConfigFunction() { 8 | 9 | // 控制保存配置弹框的展示 10 | function handleSaveConfigAlert(value) { 11 | isShowSaveAlert.value = value 12 | } 13 | 14 | // 封装的下载数据函数 15 | function downLoadFile(fileName, content) { 16 | var aTag = document.createElement('a'); 17 | var blob = new Blob([content]); 18 | aTag.download = fileName; 19 | aTag.href = URL.createObjectURL(blob); 20 | aTag.click(); 21 | URL.revokeObjectURL(blob); 22 | } 23 | 24 | // 调用下载接口 25 | function saveConfig() { 26 | downLoadFile('nav.config.json', window.localStorage.navInfos) 27 | } 28 | 29 | return { 30 | isShowSaveAlert, 31 | handleSaveConfigAlert, 32 | saveConfig, 33 | } 34 | } -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/flippers/flip.css: -------------------------------------------------------------------------------- 1 | @keyframes flip { 2 | from { 3 | transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg); 4 | animation-timing-function: ease-out; 5 | } 6 | 7 | 40% { 8 | transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) 9 | rotate3d(0, 1, 0, -190deg); 10 | animation-timing-function: ease-out; 11 | } 12 | 13 | 50% { 14 | transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) 15 | rotate3d(0, 1, 0, -170deg); 16 | animation-timing-function: ease-in; 17 | } 18 | 19 | 80% { 20 | transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0) 21 | rotate3d(0, 1, 0, 0deg); 22 | animation-timing-function: ease-in; 23 | } 24 | 25 | to { 26 | transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg); 27 | animation-timing-function: ease-in; 28 | } 29 | } 30 | 31 | .animated.flip { 32 | backface-visibility: visible; 33 | animation-name: flip; 34 | } 35 | -------------------------------------------------------------------------------- /src/use/search.js: -------------------------------------------------------------------------------- 1 | // 搜索功能 2 | import { } from 'vue' 3 | import store from '@/store/index' 4 | 5 | // 变量 6 | const moduleSearch = store.state.moduleSearch // 搜索相关的全局状态 7 | 8 | export default function searchFunction() { 9 | 10 | // 搜索框的输入改变 11 | function inputSearchContent(value) { 12 | store.commit('changeSearchWord', value) 13 | } 14 | 15 | // 控制搜索框的展示 16 | function handleSearchBox() { 17 | if(moduleSearch.isSearch) { 18 | store.commit('changeIsSearch', false) 19 | store.commit('changeSearchWord', '') 20 | } else { 21 | store.commit('changeIsSearch', true) 22 | } 23 | } 24 | 25 | // 判断标签是否显示 26 | function judgeTabIsShow(i) { 27 | return store.getters.judgeTabIsShow(i) 28 | } 29 | 30 | // 判断url是否显示 31 | function judgeUrlIsShow(i, j) { 32 | return store.getters.judgeUrlIsShow(i, j) 33 | } 34 | 35 | return { 36 | moduleSearch, 37 | inputSearchContent, 38 | handleSearchBox, 39 | judgeTabIsShow, 40 | judgeUrlIsShow, 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 39 | 40 | 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Lpyexplore 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/store/module/tab.js: -------------------------------------------------------------------------------- 1 | // 存储用户的添加标签情况 2 | const moduleTab = { 3 | state: { 4 | tagName: '', // 标签名称 5 | trueIcon : 'plus', // 真正选好了的icon 6 | currentIcon: '', // 当前用户选择了的icon,但未确认 7 | isSelected: false, // 用户是否选择了 8 | isShowIconList: false, // icon列表是否展示 9 | isShowAddTabAlert: false, // 添加标签弹框是否显示 10 | id: '', 11 | alertType: '新增标签' 12 | }, 13 | mutations: { 14 | // 修改增加标签弹框内的信息 15 | changeTabInfo(state, payload) { 16 | let key, value, current 17 | if(Array.isArray(payload)) { 18 | let length = payload.length 19 | for(let i = 0; i < length; i++) { 20 | current = payload[i] 21 | key = current.key 22 | value = current.value 23 | state[key] = value 24 | } 25 | } else { 26 | key = payload.key 27 | value = payload.value 28 | state[key] = value 29 | } 30 | 31 | 32 | } 33 | } 34 | } 35 | 36 | export default moduleTab 37 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Daniel Eden 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/components/main/carousel.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 27 | 28 | -------------------------------------------------------------------------------- /src/use/init.js: -------------------------------------------------------------------------------- 1 | // 在页面初次加载时,做一些初始化的操作 2 | import { writeToVuex } from '@/utils/utils' 3 | import store from '@/store/index' 4 | 5 | export default function init() { 6 | // 判断用户是否时第一次进入该网页 7 | if(window.localStorage.isSet === 'true') { 8 | writeToVuex(store, JSON.parse(window.localStorage.navInfos)) 9 | } 10 | // 自动设置默认信息 11 | else { 12 | let obj = { 13 | navName: "Nav Url", 14 | catalogue : [ 15 | {id:'1' , name: "常用网站", icon: "align-justify", URLS: [ 16 | {id:'1.1' , url: 'http://www.baidu.com', icon: 'http://www.baidu.com/favicon.ico', name: '百度'}, 17 | {id:'1.3', url: 'https://juejin.im/', icon: 'https://b-gold-cdn.xitu.io/favicons/v2/favicon.ico', name: '掘金'}, 18 | {id:'1.4', url: 'https://gitee.com/', icon: 'https://gitee.com/assets/favicon.ico', name: '码云'}, 19 | ]}, 20 | {id:'2' , name: "实用工具", icon: "bookmark", URLS: []}, 21 | {id:'3' , name: "娱乐影视", icon: "blog", URLS: []} 22 | ] 23 | } 24 | window.localStorage.navInfos = JSON.stringify(obj) 25 | window.localStorage.isSet = 'true' 26 | writeToVuex(store, obj) 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/store/module/url.js: -------------------------------------------------------------------------------- 1 | // 存储用户的添加URL情况 2 | const moduleUrl = { 3 | state: { 4 | url: '', // URL地址 5 | icon: '', // URL图标 6 | otherIcon: '', // 网址的默认icon地址 7 | isShow: false, // 是否显示 8 | isLoadingIcon: false, // 是否正在获取Icon 9 | isLoadingName: false, // 是否正在获取Name 10 | name: '', // 网址名称 11 | imgErr: false, // 图片是否显示异常 12 | whichTag: -1, // 添加到哪个标签中去 13 | id: -1, // 记录id 14 | alertType: '新增网址' 15 | }, 16 | mutations: { 17 | // 修改增加URL弹框内的信息 18 | changeUrlInfo(state, payload) { 19 | let key, value, current 20 | if(Array.isArray(payload)) { 21 | let length = payload.length 22 | for(let i = 0; i < length; i++) { 23 | current = payload[i] 24 | key = current.key 25 | value = current.value 26 | state[key] = value 27 | } 28 | } else { 29 | key = payload.key 30 | value = payload.value 31 | state[key] = value 32 | } 33 | } 34 | } 35 | } 36 | 37 | export default moduleUrl 38 | -------------------------------------------------------------------------------- /src/components/public/lp-popover/lp-popover.js: -------------------------------------------------------------------------------- 1 | import lpPopover from './lp-popover.vue' 2 | import {defineComponent, createVNode, render, toRaw} from 'vue' 3 | 4 | const popoverConstructor = defineComponent(lpPopover) 5 | 6 | export default function createPopover(app) { 7 | app.directive('popover', { 8 | mounted (el, binding) { 9 | let { value } = binding 10 | 11 | let options = toRaw(value) 12 | 13 | if(!Object.prototype.toString.call(options) === '[object Object]') { 14 | console.error('Please enter an object as a parameter'); 15 | } 16 | 17 | options = options ? options : {} 18 | 19 | const popoverInstance = createVNode( 20 | popoverConstructor, 21 | options 22 | ) 23 | const container = document.createElement('div') 24 | render(popoverInstance, container) 25 | el.appendChild(popoverInstance.el) 26 | const props = popoverInstance.component.props 27 | Object.keys(options).forEach(v => { 28 | props[v] = options[v] 29 | }) 30 | 31 | el.style.position = 'relative' 32 | 33 | } 34 | }) 35 | } -------------------------------------------------------------------------------- /src/use/trackImg.js: -------------------------------------------------------------------------------- 1 | // 一些处理图片的方法 2 | import { ref } from 'vue' 3 | 4 | // 缓存图片懒加载的节点 5 | const map = new WeakMap() 6 | const scrollContent = ref(null) 7 | 8 | export default function trackImgFunction() { 9 | 10 | // 处理无icon或icon加载失败的图片,令其使用默认svg图标 11 | function imgLoadErr(e) { 12 | let el = e.target 13 | el.style.display = 'none' 14 | el.nextSibling.style.display = 'inline-block' 15 | } 16 | 17 | // 图片加载成功后的处理 18 | function imgLoadSuccess(e) { 19 | let el = e.target 20 | el.style.display = 'inline-block' 21 | el.nextSibling.style.display = 'none' 22 | } 23 | 24 | function lazyLoad() { 25 | const el = scrollContent.value 26 | const imgs = el.querySelectorAll('.url-icon') 27 | let len = imgs.length 28 | console.log(len); 29 | let { clientHeight } = el 30 | for(let i = 0; i < len; i ++) { 31 | let img = imgs[i] 32 | if(map.has(img)) continue; 33 | if(img.getBoundingClientRect().top <= clientHeight) { 34 | img.src = img.getAttribute('data-src'); 35 | map.set(img, 1) 36 | } 37 | } 38 | } 39 | 40 | return { 41 | imgLoadErr, 42 | imgLoadSuccess, 43 | lazyLoad, 44 | scrollContent 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/components/public/lp-message/lp-message.js: -------------------------------------------------------------------------------- 1 | import lp_message from "./lp-message.vue" 2 | import { createVNode, render } from 'vue' 3 | 4 | let instance; 5 | const instances = [] 6 | 7 | export const createMessage = (options) => { 8 | 9 | if(!Object.prototype.toString.call(options) === '[object Object]') { 10 | console.error('Please enter an object as a parameter') 11 | } 12 | 13 | options = options ? options : {} 14 | 15 | instance = createVNode( 16 | lp_message, 17 | options 18 | ) 19 | 20 | //挂载 21 | const container = document.createElement('div') 22 | render(instance, container) 23 | 24 | // document.querySelector('#app').appendChild(instance.el) 25 | 26 | const cpn = instance.component 27 | const props = cpn.props 28 | props.seed = instances.length 29 | 30 | // 加入到instances中管理 31 | instances.push(instance) 32 | 33 | // 消息框出现 34 | setTimeout(() => { 35 | props.isShow = true 36 | props.isEnter = true 37 | }, 200) 38 | 39 | // 消息框离开 40 | setTimeout(() => { 41 | props.isEnter = false 42 | props.isShow = false 43 | props.isLeave = true 44 | }, props.lastTime) 45 | 46 | // 移除消息框 47 | setTimeout(() => { 48 | close(props) 49 | }, props.lastTime + 200) 50 | 51 | } 52 | 53 | // 关闭某个弹框 54 | const close = (props) => { 55 | instances.shift() 56 | instances.forEach((v) => { 57 | v.component.props.seed -= 1 58 | }) 59 | props.isDestory = true 60 | } 61 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/_base.css: -------------------------------------------------------------------------------- 1 | .animated { 2 | animation-duration: var(--animate-duration); 3 | animation-fill-mode: both; 4 | } 5 | 6 | .animated.infinite { 7 | animation-iteration-count: infinite; 8 | } 9 | 10 | .animated.repeat-1 { 11 | animation-iteration-count: var(--animate-repeat); 12 | } 13 | 14 | .animated.repeat-2 { 15 | animation-iteration-count: calc(var(--animate-repeat) * 2); 16 | } 17 | 18 | .animated.repeat-3 { 19 | animation-iteration-count: calc(var(--animate-repeat) * 3); 20 | } 21 | 22 | .animated.delay-1s { 23 | animation-delay: var(--animate-delay); 24 | } 25 | 26 | .animated.delay-2s { 27 | animation-delay: calc(var(--animate-delay) * 2); 28 | } 29 | 30 | .animated.delay-3s { 31 | animation-delay: calc(var(--animate-delay) * 3); 32 | } 33 | 34 | .animated.delay-4s { 35 | animation-delay: calc(var(--animate-delay) * 4); 36 | } 37 | 38 | .animated.delay-5s { 39 | animation-delay: calc(var(--animate-delay) * 5); 40 | } 41 | 42 | .animated.faster { 43 | animation-duration: calc(var(--animate-duration) / 2); 44 | } 45 | 46 | .animated.fast { 47 | animation-duration: calc(var(--animate-duration) * 0.8); 48 | } 49 | 50 | .animated.slow { 51 | animation-duration: calc(var(--animate-duration) * 2); 52 | } 53 | 54 | .animated.slower { 55 | animation-duration: calc(var(--animate-duration) * 3); 56 | } 57 | 58 | @media print, (prefers-reduced-motion: reduce) { 59 | .animated { 60 | animation-duration: 1ms !important; 61 | transition-duration: 1ms !important; 62 | animation-iteration-count: 1 !important; 63 | } 64 | 65 | .animated[class*='Out'] { 66 | opacity: 0; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/components/main/search.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 35 | 36 | -------------------------------------------------------------------------------- /src/components/tabs/saveConfig.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 30 | 31 | -------------------------------------------------------------------------------- /src/utils/utils.js: -------------------------------------------------------------------------------- 1 | // 防抖 2 | function debounce(fn, delay = 1000) { 3 | let timer = null 4 | 5 | return function(...args) { 6 | if(timer) clearTimeout(timer); 7 | 8 | timer = setTimeout(() => { 9 | fn.apply(this, args) 10 | clearTimeout(timer) 11 | }, delay) 12 | } 13 | } 14 | 15 | // 节流函数 16 | function throttle(fn, delay = 1000) { 17 | let timer = null 18 | let status = false 19 | 20 | return function(...args) { 21 | if(status) return; 22 | status = true 23 | timer = setTimeout(() => { 24 | fn.apply(this, args) 25 | status = false 26 | clearTimeout(timer) 27 | }, delay) 28 | } 29 | } 30 | 31 | // 将导航所有信息全部重新导入到vuex中 32 | function writeToVuex(store, obj) { 33 | store.commit('init', obj) 34 | } 35 | 36 | // 将Vuex中的信息更新到localStorage中(未经过防抖处理) 37 | function updateLocalStorage(store) { 38 | window.localStorage.navInfos = JSON.stringify({ 39 | navName: store.state.navName, 40 | catalogue: store.state.catalogue 41 | }) 42 | } 43 | 44 | // 将Vuex中的信息更新到localStorage中(经过防抖处理) 45 | let updateLocal = debounce(updateLocalStorage) 46 | 47 | // 判断字符串长度是否符合大小规定 48 | function judgeString(s) { 49 | let count = 12 50 | let characters = s.match(/\w/g) 51 | let words = s.match(/\W/g) 52 | count -= characters ? characters.length : 0 53 | count -= words ? words.length * 2 : 0 54 | return count >= 0 ? true : false 55 | } 56 | 57 | // 交换两个元素的位置 58 | function exchangeElements(el1, el2) { 59 | let sibling1 = el1.nextElementSibling, 60 | sibling2 = el2.nextElementSibling, 61 | parentNode = el1.parentNode 62 | 63 | // el1 在 el2前面,且相邻 64 | if(sibling1 === el2) parentNode.insertBefore(el2, el1); 65 | // el2 在 el1前面,且相邻 66 | else if(sibling2 === el1) parentNode.insertBefore(el1, el2) 67 | // el1 和 el2 不相邻 68 | else { 69 | parentNode.insertBefore(el2, sibling1) 70 | parentNode.insertBefore(el1, sibling2) 71 | } 72 | } 73 | 74 | export { 75 | writeToVuex, 76 | updateLocal, 77 | debounce, 78 | throttle, 79 | judgeString, 80 | exchangeElements, 81 | } -------------------------------------------------------------------------------- /src/components/public/tabAlert/selectIcon.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 58 | 59 | -------------------------------------------------------------------------------- /src/use/importConfig.js: -------------------------------------------------------------------------------- 1 | // 导入配置功能 2 | import { ref } from 'vue' 3 | 4 | const isShowImportAlert = ref(false), // 导入配置弹框是否展示 5 | result = ref('none'), // 导入的结果 6 | isUpload = ref(false), // 判断是否上传配置文件 7 | isImport = ref(false), // 判断配置是否导入成功 8 | isLoading = ref(false), // 判断按钮是否处于加载状态 9 | inputFile = ref(null), // 获取文件元素 10 | hasFile = ref(0) // 判断文件的传入情况。0:未传入 1: 格式错误 2:格式正确 11 | 12 | export default function importConfigFunction($message) { 13 | 14 | // 控制弹框的展示 15 | function handleImportConfigAlert(value) { 16 | isShowImportAlert.value = value 17 | if(!value) hasFile.value = 0 18 | } 19 | 20 | // 上传的文件内容发生改变 21 | function fileChange(e) { 22 | let files = e.target.files 23 | if(files.length === 0) { 24 | $message({ 25 | type: 'warning', 26 | content: '请先上传配置文件' 27 | }) 28 | } 29 | else { 30 | let targetFile = files[0] 31 | if(!/\.json$/.test(targetFile.name)) { 32 | hasFile.value = 1 33 | $message({ 34 | type: 'warning', 35 | content: '请确认文件格式是否正确' 36 | }) 37 | } else { 38 | hasFile.value = 2 39 | $message({ 40 | type: 'success', 41 | content: '文件格式正确' 42 | }) 43 | } 44 | } 45 | } 46 | 47 | // 导入配置 48 | function importConfig() { 49 | let reader = new FileReader() 50 | let files = inputFile.value.files 51 | if(hasFile.value == 0) { 52 | $message({ 53 | type: 'warning', 54 | content: '请先上传配置文件' 55 | }) 56 | } 57 | else if(hasFile.value == 1) { 58 | $message({ 59 | type: 'warning', 60 | content: '请上传正确格式的文件,例如xx.json' 61 | }) 62 | } 63 | else if(hasFile.value == 2) { 64 | reader.readAsText(files[0]) 65 | reader.onload = function() { 66 | let data = this.result 67 | window.localStorage.navInfos = data 68 | location.reload() 69 | } 70 | } 71 | } 72 | 73 | return { 74 | isShowImportAlert, 75 | result, 76 | isUpload, 77 | isImport, 78 | isLoading, 79 | inputFile, 80 | hasFile, 81 | handleImportConfigAlert, 82 | fileChange, 83 | importConfig, 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/README.md: -------------------------------------------------------------------------------- 1 | # Animate.css 2 | 3 | [![GitHub Version](https://img.shields.io/github/release/daneden/animate.css.svg?style=for-the-badge)](https://github.com/daneden/animate.css) [![Github Star](https://img.shields.io/github/stars/daneden/animate.css.svg?style=for-the-badge)](https://github.com/daneden/animate.css) [![Github Fork](https://img.shields.io/github/forks/daneden/animate.css.svg?style=for-the-badge)](https://github.com/daneden/animate.css) [![License](https://img.shields.io/github/license/daneden/animate.css.svg?style=for-the-badge)](https://github.com/daneden/animate.css) 4 | 5 | > If you need the old docs - v3.x.x and under - you can find it [here](https://github.com/animate-css/animate.css/tree/a8d92e585b1b302f7749809c3308d5e381f9cb17). 6 | 7 | ## _Just-add-water CSS animation_ 8 | 9 | ## Installation 10 | 11 | Install with npm: 12 | 13 | ```shell 14 | npm install animate.css --save 15 | ``` 16 | 17 | Install with yarn: 18 | 19 | ```shell 20 | yarn add animate.css 21 | ``` 22 | 23 | ## Getting started 24 | 25 | You can find the Animate.css documentation on the [website](https://animate.style/). 26 | 27 | ## Accessibility 28 | 29 | Animate.css supports the [`prefers-reduced-motion` media query](https://webkit.org/blog/7551/responsive-design-for-motion/) so that users with motion sensitivity can opt out of animations. On supported platforms (currently all the majors browsers and OS), users can select "reduce motion" on their operating system preferences and it will turn off CSS transitions for them without any further work required. 30 | 31 | ## Core team 32 | 33 | | ![](https://avatars2.githubusercontent.com/u/439365?s=460&u=512b4cc5324938ae40bbb8f3b7769d335953cd3a&v=4) | ![](https://avatars2.githubusercontent.com/u/5007208?s=460&u=418401ee605824272e5dcb955fd64ea24546a857&v=4) | ![](https://avatars1.githubusercontent.com/u/15052701?s=460&u=9e58364978379536d3f26c4ce5cae1a2a449a0e4&v=4) | 34 | | --- | --- | --- | 35 | | [Daniel Eden](https://github.com/daneden) | [Elton Mesquita](https://github.com/eltonmesquita) | [Waren Gonzaga](https://github.com/WarenGonzaga) | 36 | | Animate.css creator | Maintainer | Core contributor | 37 | 38 | ## License 39 | 40 | Animate.css is licensed under the MIT license. 41 | 42 | ## Code of Conduct 43 | 44 | This project and everyone participating in it is governed by the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [callmeelton@gmail.com](mailto:callmeelton@gmail.com). 45 | 46 | ## Contributing 47 | 48 | Pull requests are the way to go here. We only have two rules for submitting a pull request: match the naming convention (camelCase, categorised [fades, bounces, etc]) and let us see a demo of submitted animations in a [pen](https://codepen.io). That **last one is important**. 49 | -------------------------------------------------------------------------------- /src/components/public/lp-input/lp-input.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 84 | 85 | -------------------------------------------------------------------------------- /src/components/public/urlAlert/index.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 55 | 56 | -------------------------------------------------------------------------------- /src/components/public/tabAlert/index.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 56 | 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nav-url(网址导航栏) 2 | A nav web for urls, which based Vue3 3 | 通过Vue3框架实现的一个网址导航栏网站 4 | 5 | # Original intention of design(设计初衷) 6 | 7 | There are many social networking sites and tool websites on the Internet now. If I think the website is not bad, I will collect it. However, the favorite of the browser is too messy and very small, so it is very inconvenient to use. At the same time, because I love to organize things, I always want to have a website navigation bar similar to Figure 1. To sum up the above reasons, and because Vue3 has just been released in recent months, we have made such a project with `Vue3` 8 | 9 | 现在的互联网上有很多社交网站、工具网站,如果觉得网站还不错,我会把它收藏起来,但是浏览器的收藏夹实在太杂乱了,而且特别小,所以用起来特别得不方便,同时因为我爱整理东西,所以一直想有个类似 **图1** 的网站导航栏。综合上述原因,再加上Vue3近几个月刚发布,就用 `Vue3` 做了这样一个项目 10 | 11 | 图1:设想图 12 | ![](showImg/origin.png) 13 | 14 | 15 | 该图是我该项目当前的预览图 16 | 17 | ![](showImg/current1.jpg) 18 | 19 | 以下两张图是该项目一些基本操作 20 | 21 | ![](showImg/gif1.gif) 22 | 23 | ![](showImg/gif2.gif) 24 | 25 | # Characteristics(特色) 26 | 27 | ### 中文 28 | 29 | 1. 通过最新的 `Vue3` 框架实现,同时也用到了 `Vuex4` 进行数据的状态管理 30 | 2. 无需远程服务器储存,依靠 `localstorage` 作为本地数据库 31 | 3. 支持**一键保存导出数据** 、**一键导入数据** 32 | 4. 页面简单大方 33 | 5. 内部嵌入了独立接口用于自动获取目标网站的 `icon` 图标 34 | 6. 项目中用 `Vue3 API` 封装了 `button` 、`input` 、`dialog` 、 `popover` 、 `message` 组件 35 | 7. 支持URL搜索功能 36 | 8. 页面滚动动画 37 | 9. 在编辑状态下,可以进行拖拽排列 38 | 10. 按照项目功能进行代码抽离,便于项目的维护、迭代、管理 39 | 40 | ### English 41 | 1. Implemented by the latest `Vue3` and `Vuex4` 42 | 2. Rely on `localstorage` as a local database, without remote server storage 43 | 3. Support **saving export data with one key** and **importing data with one key** 44 | 4. The page is simple and generous 45 | 5. An independent interface is embedded inside to automatically acquire the `icon` icon of the target website 46 | 6. In the project, `button`, `input`, `dialog`, `popover` and `message` components are encapsulated with `vue3 API` 47 | 7. Support URL search function 48 | 8. Page scrolling animation 49 | 9. In editing state, you can drag and drop to arrange 50 | 10. Code extraction according to project functions is convenient for project maintenance, iteration and management 51 | 52 | # Schedule(进度) 53 | 54 | ### 中文 55 | 56 | 还有一些未完善的功能,会陆续完成: 57 | 1. 页面账号信息存储 58 | 2. 更多的常用网站图标供用户选择 59 | 3. 支持更丰富的搜索规则,便于用户搜索 60 | 4. ……更多 61 | 62 | ### English 63 | There are still some imperfect functions that will be completed one after another: 64 | 65 | 1. Page account information storage 66 | 2. More common website icons for users to choose 67 | 3. Support more abundant search rules for users to search 68 | 4. ……more 69 | 70 | # Use(使用) 71 | 72 | ### 中文 73 | 74 | 1. 可以访问这个地址:[http://lpyexplore.gitee.io/nav-infos/](http://lpyexplore.gitee.io/nav-infos/) 75 | 2. 将该网址设置成浏览器每次打开默认的地址 76 | 77 | ### English 78 | 79 | 1. You can access this address: [http://lpyexplore.gitee.io/nav-infos/](http://lpyexplore.gitee.io/nav-infos/) 80 | 2. Set the URL as the default address for every browser opening 81 | 82 | # Version(版本) 83 | 84 | - **0.1.0 :** 85 | 86 | 1. 项目第一次发布(涵盖特色:1 ~ 8) 87 | 88 | - **0.1.1 :** 89 | 90 | 1. 增加 `特色9`,在编辑状态下支持手动拖拽排列 91 | 92 | - **0.1.2 :** 93 | 94 | 1. 修复了搜索框无法弹出的bug 95 | 96 | - **0.1.3 :** 97 | 98 | 1. 修复了拖拽排列后id顺序打乱而导致新添加的url框的id不唯一 99 | 100 | 101 | # The end(最后) 102 | 103 | Welcome everyone to give me more advice 104 | 欢迎大家给我多提提意见,可加我微信:`Lpyexplore333`,或在 `github` 上提 **Issues** -------------------------------------------------------------------------------- /src/components/public/lp-dialog/lp-dialog.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 60 | 61 | -------------------------------------------------------------------------------- /src/use/edit.js: -------------------------------------------------------------------------------- 1 | // url框的拖拽排列 2 | import { ref } from 'vue' 3 | import { exchangeElements, debounce } from '@/utils/utils' 4 | import store from '@/store/index' 5 | 6 | //变量 7 | let elementNodeDragged = null, // 被移动的地址框元素 8 | elementNodeLocated = null, // 移入的地址框元素 9 | editWhich = ref(-1) // 记录正在编辑的tab索引 10 | 11 | export default function editFunction($message, $confirm) { 12 | 13 | // 控制编辑状态 14 | function handleEdit(id) { 15 | if(id != editWhich.value) { 16 | editWhich.value = id 17 | } else { 18 | editWhich.value = -1 19 | } 20 | } 21 | 22 | // 删除标签以及标签下的所有网址 23 | function deleteTab(id) { 24 | $confirm({ 25 | content: '确定删除该标签以及该标签下所有网址吗?' 26 | }) 27 | .then(() => { 28 | store.commit('remove', id) 29 | $message({ 30 | type: 'success', 31 | content: '标签页及子网址删除成功' 32 | }) 33 | }) 34 | .catch(() => {}) 35 | } 36 | 37 | // 删除某个网址 38 | function deleteUrl(id) { 39 | $confirm({ 40 | content: '确定删除该网址吗?' 41 | }) 42 | .then(() => { 43 | store.commit('remove', id) 44 | $message({ 45 | type: 'success', 46 | content: '网址删除成功' 47 | }) 48 | }) 49 | .catch(() => {}) 50 | } 51 | 52 | // 地址框开始拖拽 53 | function urlBoxDragStart(e) { 54 | const el = e.target 55 | if(el.nodeName !== 'LI') return; 56 | // 记录当前被拖拽地址框元素 57 | elementNodeDragged = el 58 | // 将被拖拽对象隐藏 59 | el.style.display = 'fixed' 60 | el.style.opacity = 0 61 | } 62 | 63 | // 拖拽后更新Vuex中的正确排序 64 | let dragEndToUpdate = debounce(function() { 65 | // 获取当前正在编辑标签中所有url的排序 66 | const result = [] 67 | const children = elementNodeLocated.parentNode.children 68 | let length = children.length 69 | for(let i = 0; i < length - 1; i++) { 70 | result.push(children[i].getAttribute('data-id')) 71 | } 72 | store.commit('dragEndToUpdate', {tabId: editWhich.value, result}) 73 | }, 500) 74 | 75 | // 地址框拖拽结束 76 | function urlBoxDragEnd(e) { 77 | let el = e.target 78 | el.style.display = 'inline-block' 79 | el.style.opacity = 1 80 | dragEndToUpdate() 81 | } 82 | 83 | // 被拖动的地址框触碰到其它的地址框 84 | function urlBoxEnter(e, tabId) { 85 | if(tabId != editWhich.value) return; 86 | let el = e.target 87 | while(el.nodeName !== 'LI') el = el.parentNode; // 若子元素触发dragenter事件,则查找到父元素li标签 88 | if(el === elementNodeDragged) return; // 避免自己拖拽进入自己的情况 89 | if(elementNodeLocated !== el) elementNodeLocated = el // 记录被移入的地址框元素 90 | exchangeElements(elementNodeDragged, el) // 地址框位置互换 91 | } 92 | 93 | return { 94 | editWhich, 95 | handleEdit, 96 | deleteTab, 97 | deleteUrl, 98 | urlBoxDragStart, 99 | urlBoxDragEnd, 100 | urlBoxEnter, 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/use/tabAlert.js: -------------------------------------------------------------------------------- 1 | // 新增以及修改tab的相关功能 2 | 3 | import { } from 'vue' 4 | 5 | import store from '@/store/index' 6 | import { judgeString } from '@/utils/utils' 7 | 8 | // 变量 9 | const state = store.state.moduleTab // tab相关全局状态 10 | 11 | export default function tabAlertFunction($message) { 12 | 13 | // 展示新增标签弹框 14 | function showNewAddTab() { 15 | store.commit('changeTabInfo', [ 16 | {key: 'isShowAddTabAlert', value: true}, 17 | {key: 'alertType', value: '新增标签'} 18 | ]) 19 | } 20 | 21 | // 展示修改标签弹框 22 | function showEditAddTab(tab) { 23 | store.commit('changeTabInfo', [ 24 | {key: 'isShowAddTabAlert', value: true}, 25 | {key: 'tagName', value: tab.name}, 26 | {key: 'trueIcon', value: tab.icon}, 27 | {key: 'isSelected', value: true}, 28 | {key: 'currentIcon', value: tab.icon}, 29 | {key: 'id', value: tab.id}, 30 | {key: 'alertType', value: '修改标签'} 31 | ]) 32 | } 33 | 34 | // 关闭弹框 35 | function closeTabAlert() { 36 | store.commit('changeTabInfo', [ 37 | {key: 'tagName', value: ''}, 38 | {key: 'trueIcon', value: 'plus'}, 39 | {key: 'currentIcon', value: ''}, 40 | {key: 'isSelected', value: false}, 41 | {key: 'isShowIconList', value: false}, 42 | {key: 'isShowAddTabAlert', value: false}, 43 | ]) 44 | } 45 | 46 | // 确认操作 47 | function confirm() { 48 | // 判断标签名是否为空 49 | if(state.tagName == '') { 50 | $message({ 51 | type: 'warning', 52 | content: '标签名称不能为空' 53 | }) 54 | return; 55 | } 56 | // 判断标签名长度是否符合要求 57 | if(!judgeString(state.tagName)) { 58 | $message({ 59 | type: 'warning', 60 | content: '标签名最多为6位中文或12位英文' 61 | }) 62 | return; 63 | } 64 | // 判断icon是否为空 65 | if(!state.isSelected) { 66 | $message({ 67 | type: 'warning', 68 | content: '请选择合适的图标' 69 | }) 70 | return; 71 | } 72 | if(state.alertType == '新增标签') { 73 | store.commit('add', { 74 | key: '1', 75 | value: { 76 | name: state.tagName, 77 | icon: state.trueIcon 78 | } 79 | }) 80 | $message({ 81 | type: 'success', 82 | content: '标签添加成功' 83 | }) 84 | } else if(state.alertType == '修改标签') { 85 | store.commit('update', { 86 | key: 'catalogue', 87 | value: { 88 | id: state.id, 89 | icon: state.trueIcon, 90 | name: state.tagName 91 | } 92 | }) 93 | $message({ 94 | type: 'success', 95 | content: '标签修改成功' 96 | }) 97 | } 98 | closeTabAlert() 99 | } 100 | 101 | // 输入框内容改变事件 102 | function inputTabName(value) { 103 | store.commit('changeTabInfo', { 104 | key: 'tagName', 105 | value 106 | }) 107 | } 108 | 109 | return { 110 | state, 111 | showNewAddTab, 112 | showEditAddTab, 113 | closeTabAlert, 114 | confirm, 115 | inputTabName, 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/assets/css/animate.css/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "_args": [ 3 | [ 4 | "animate.css@4.1.1", 5 | "D:\\hx\\nav-url" 6 | ] 7 | ], 8 | "_from": "animate.css@4.1.1", 9 | "_id": "animate.css@4.1.1", 10 | "_inBundle": false, 11 | "_integrity": "sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ==", 12 | "_location": "/animate.css", 13 | "_phantomChildren": {}, 14 | "_requested": { 15 | "type": "version", 16 | "registry": true, 17 | "raw": "animate.css@4.1.1", 18 | "name": "animate.css", 19 | "escapedName": "animate.css", 20 | "rawSpec": "4.1.1", 21 | "saveSpec": null, 22 | "fetchSpec": "4.1.1" 23 | }, 24 | "_requiredBy": [ 25 | "/" 26 | ], 27 | "_resolved": "https://registry.npmjs.org/animate.css/-/animate.css-4.1.1.tgz", 28 | "_spec": "4.1.1", 29 | "_where": "D:\\hx\\nav-url", 30 | "animateConfig": { 31 | "prefix": "animate__" 32 | }, 33 | "author": { 34 | "name": "Animate.css" 35 | }, 36 | "browserslist": [ 37 | "> 3%", 38 | "last 2 versions" 39 | ], 40 | "bugs": { 41 | "url": "https://github.com/animate-css/animate.css/issues" 42 | }, 43 | "description": "[![GitHub Version](https://img.shields.io/github/release/daneden/animate.css.svg?style=for-the-badge)](https://github.com/daneden/animate.css) [![Github Star](https://img.shields.io/github/stars/daneden/animate.css.svg?style=for-the-badge)](https://github.com/daneden/animate.css) [![Github Fork](https://img.shields.io/github/forks/daneden/animate.css.svg?style=for-the-badge)](https://github.com/daneden/animate.css) [![License](https://img.shields.io/github/license/daneden/animate.css.svg?style=for-the-badge)](https://github.com/daneden/animate.css)", 44 | "devDependencies": { 45 | "autoprefixer": "^9.7.6", 46 | "cssnano": "^4.1.10", 47 | "eslint": "^7.8.1", 48 | "husky": "^4.2.5", 49 | "lint-staged": "^10.3.0", 50 | "markdown-it": "^11.0.0", 51 | "npm-run-all": "^4.1.5", 52 | "postcss": "^7.0.27", 53 | "postcss-cli": "^7.1.2", 54 | "postcss-header": "^2.0.0", 55 | "postcss-import": "^12.0.1", 56 | "postcss-prefixer": "^2.1.2", 57 | "postcss-preset-env": "^6.7.0", 58 | "prettier": "^2.1.1" 59 | }, 60 | "files": [ 61 | "animate.compat.css", 62 | "animate.min.css", 63 | "animate.css", 64 | "source/**/*.css" 65 | ], 66 | "homepage": "https://animate.style/", 67 | "husky": { 68 | "hooks": { 69 | "pre-commit": "npm-run-all start precommit" 70 | } 71 | }, 72 | "jspm": { 73 | "main": "animate.css!", 74 | "format": "global", 75 | "directories": { 76 | "lib": "./" 77 | } 78 | }, 79 | "license": "MIT", 80 | "lint-staged": { 81 | "*.{js,json,md,css}": [ 82 | "prettier --write" 83 | ] 84 | }, 85 | "main": "animate.css", 86 | "name": "animate.css", 87 | "repository": { 88 | "type": "git", 89 | "url": "git+https://github.com/animate-css/animate.css.git" 90 | }, 91 | "scripts": { 92 | "compat": "npx postcss source/animate.css -o animate.compat.css --no-map --env compat", 93 | "dev": "npx postcss source/animate.css -o animate.css --no-map --env development -w", 94 | "docs": "npm-run-all docs:library docs:pages", 95 | "docs:library": "npx postcss source/animate.css -o ./docs/animate.min.css --no-map --env production", 96 | "docs:pages": "node ./docsSource/index.js", 97 | "format": "prettier --write \"**/*.{js,json,md,css}\"", 98 | "postversion": "git push && git push --tags", 99 | "precommit": "lint-staged", 100 | "prod": "npx postcss source/animate.css -o animate.min.css --no-map --env production", 101 | "raw": "npx postcss source/animate.css -o animate.css --no-map --env development", 102 | "start": "npm-run-all raw prod compat", 103 | "version": "npm-run-all start docs && git add -A docs animate.css animate.min.css animate.compat.css" 104 | }, 105 | "style": "./animate.css", 106 | "version": "4.1.1" 107 | } 108 | -------------------------------------------------------------------------------- /src/components/public/lp-message/lp-message.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 76 | 77 | 152 | -------------------------------------------------------------------------------- /src/components/tabs/importConfig.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 64 | 65 | -------------------------------------------------------------------------------- /src/components/public/urlAlert/selectIcon.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 68 | 69 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const url = require('url') 3 | const axios = require('axios') 4 | 5 | const app = express() 6 | 7 | 8 | // 允许跨域 9 | app.all('*', function(req, res, next) { 10 | res.header("Access-Control-Allow-Origin", '*'); 11 | res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With"); 12 | res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS"); 13 | res.header("Access-Control-Allow-Credentials","true"); 14 | res.header("X-Powered-By",' 3.2.1') 15 | if(req.method === "OPTIONS") res.send(200);/*让options请求快速返回*/ 16 | else next(); 17 | }); 18 | 19 | // 从文档中获取icon地址 20 | function getIcon(s, obj) { 21 | let {protocol, host, port, targetUrl} = obj 22 | port = port ? `:${port}` : '' 23 | let linkList = s.match(//g) // 所有link标签 24 | let length = linkList ? linkList.length : 0 25 | 26 | for(let i = 0; i < length; i++) { 27 | let link = linkList[i] 28 | // console.log(link); 29 | let rel, href 30 | const attrLists = link.split(' ') 31 | 32 | attrLists.forEach(v => { 33 | if(/=/.test(v)) { 34 | const attr = v.split('=') 35 | if(attr[0] == 'rel') rel = attr[1].toLowerCase(); 36 | if(attr[0] == 'href') href = attr[1]; 37 | } 38 | }) 39 | 40 | // 处理一些特殊情况 41 | if(href == '') continue; 42 | rel = rel.replace(/"/g, '') 43 | href = href.replace(/"/g, '') 44 | href = href.replace(/>/g, '') 45 | href = href.charAt(href.length - 1) == '/' ? href.slice(0, href.length - 1) : href 46 | 47 | /** 判断多种icon格式 48 | * 1. 'shortcut icon' 49 | * 2. 'SHORTCUT ICON' 50 | * 3. 'apple-touch-icon' 51 | * 4. 'icon' 52 | * 5. 没有icon 53 | * */ 54 | 55 | if(rel == 'shortcut' || rel == 'icon' || rel == 'apple-touch-icon' || /apple-touch-icon/.test(rel)) { 56 | // console.log(href); 57 | /** 判断多种href格式 58 | * 1. https://example.com:4000/icon.png 59 | * 2. //example.com:4000/icon.png 60 | * 3. /icon.png 61 | * 4. ./icon.png 62 | */ 63 | if(/http/.test(href)) return href; 64 | else if(/^\/\//.test(href)) return protocol + href; 65 | else if(/^\//.test(href)) return protocol + '//' + host + port + href; 66 | else if(/^\.\//.test(href)) return targetUrl + href.slice(1); 67 | else return protocol + '//' + host + port + '/' + href 68 | } 69 | } 70 | return null 71 | } 72 | // 从文档中获取标题 73 | function getTitle(s) { 74 | let result = s.match(/(.*)<\/title>/) 75 | return result ? result[1] : '' 76 | } 77 | 78 | app.get('/api', (req, res) => { 79 | let urlInfo = url.parse(req.query.targetUrl) // 解析网址 80 | let target = req.query.target // 判断请求名称还是图标 81 | let targetUrl = urlInfo.href // 目标网址 82 | let protocol = urlInfo.protocol // 协议 83 | let host = urlInfo.hostname // 主机名 84 | let port = urlInfo.port // 端口号 85 | axios({ 86 | url: targetUrl, 87 | timeout: 10000, 88 | headers: { 89 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36' 90 | } 91 | }) 92 | .then(data => { 93 | // console.log(data); 94 | let response = data.data 95 | let value; 96 | if(target === 'icon') value = getIcon(response, {protocol, host, port, targetUrl}); 97 | else if(target === 'name') value = getTitle(response); 98 | 99 | res.send({ 100 | status: 200, 101 | response: '成功获取', 102 | otherIcon: `${protocol}//${host}/favicon.ico`, 103 | data: value 104 | }) 105 | }) 106 | .catch(err => { 107 | // console.log(err); 108 | res.send({ 109 | status: 500, 110 | txt: '无法请求到资源' 111 | }) 112 | }) 113 | }) 114 | 115 | app.listen(4000, () => { 116 | console.log('localhost:4000'); 117 | }) -------------------------------------------------------------------------------- /src/components/tabs/index.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <aside id="tabs-container"> 3 | <div id="logo-container"> 4 | {{ navInfos.navName }} 5 | </div> 6 | <ul id="tabs"> 7 | <li class="tab tab-search" @click="handleSearchBox"> 8 | <i class="fas fa-search tab-icon"/> 9 | <span>快速搜索</span> 10 | </li> 11 | <li class="tab tab-save" @click="handleSaveConfigAlert(true)"> 12 | <i class="fas fa-share-square tab-icon"></i> 13 | <span>保存配置</span> 14 | </li> 15 | <li class="tab tab-import" @click="handleImportConfigAlert(true)"> 16 | <i class="fas fa-cog tab-icon"></i> 17 | <span>导入配置</span> 18 | </li> 19 | <br> 20 | <li v-for="(item, index) in navInfos.catalogue" 21 | :key="index" 22 | class="tab" 23 | @click="toID(item.id)"> 24 | <span class="li-container"> 25 | <i :class="['fas', `fa-${item.icon}`, 'tab-icon']" /> 26 | <span>{{ item.name }}</span> 27 | <i class="fas fa-angle-right tab-icon tab-angle-right"/> 28 | </span> 29 | </li> 30 | <li class="tab add-tab" @click="showNewAddTab"> 31 | <i class="fas fa-plus"/> 32 | </li> 33 | </ul> 34 | <!-- 添加标签弹框 --> 35 | <tabAlert/> 36 | <!-- 保存配置弹框 --> 37 | <save-config /> 38 | <!-- 导入配置弹框 --> 39 | <import-config /> 40 | </aside> 41 | </template> 42 | 43 | <script> 44 | /* API */ 45 | import { useStore } from 'vuex' 46 | import { inject } from 'vue' 47 | /* 组件 */ 48 | import tabAlert from '@/components/public/tabAlert/index' 49 | import saveConfig from './saveConfig' 50 | import importConfig from './importConfig' 51 | /* 功能模块 */ 52 | import saveConfigFunction from '@/use/saveConfig' 53 | import importConfigFunction from '@/use/importConfig' 54 | import searchFunction from '@/use/search' 55 | import toID from '@/use/toID' 56 | import tabAlertFunction from '@/use/tabAlert' 57 | export default { 58 | name: 'tabs', 59 | components: { 60 | tabAlert, 61 | saveConfig, 62 | importConfig 63 | }, 64 | setup() { 65 | let navInfos = useStore().state // Vuex的state对象 66 | const $message = inject('message') // 获取message组件方法 67 | 68 | // 展示新增标签弹框 69 | let { showNewAddTab } = tabAlertFunction() 70 | 71 | // 控制 "保存配置弹框" 的展示 72 | let { handleSaveConfigAlert } = saveConfigFunction() 73 | 74 | // 控制 "导入配置弹框" 的展示 75 | let { handleImportConfigAlert } = importConfigFunction($message) 76 | 77 | // 控制 "搜索框" 的展示 78 | let { handleSearchBox } = searchFunction() 79 | 80 | return { 81 | navInfos, 82 | showNewAddTab, 83 | handleSaveConfigAlert, 84 | handleImportConfigAlert, 85 | handleSearchBox, 86 | toID 87 | } 88 | } 89 | } 90 | </script> 91 | 92 | <style scoped> 93 | #tabs-container{ 94 | width: 250px; 95 | height: 100vh; 96 | float: left; 97 | background-color: rgb(44, 42, 42); 98 | } 99 | #logo-container{ 100 | height: 79px; 101 | color: white; 102 | text-align: center; 103 | line-height: 80px; 104 | border-bottom: 1px solid rgb(68, 67, 67); 105 | } 106 | #tabs{ 107 | height: calc(100% - 80px); 108 | overflow: auto; 109 | -ms-overflow-style: none; 110 | overflow: -moz-scrollbars-none; 111 | } 112 | #tabs::-webkit-scrollbar{ 113 | display: none; 114 | width: 0 !important; 115 | } 116 | 117 | .tab{ 118 | cursor: pointer; 119 | height: 50px; 120 | color: rgb(185, 164, 164); 121 | line-height: 50px; 122 | position: relative; 123 | } 124 | .to-id{ 125 | display: block; 126 | height: 100%; 127 | color: rgb(134, 125, 125); 128 | } 129 | .tab-search{ 130 | margin-top: 20px; 131 | text-align: center; 132 | } 133 | .tab-import, .tab-save{ 134 | text-align: center; 135 | } 136 | .tab:hover .to-id, .tab:hover{ 137 | color: white; 138 | } 139 | .li-container{ 140 | display: inline-block; 141 | width: 100%; 142 | padding-left: 90px; 143 | } 144 | .tab-icon{ 145 | margin: 0 15px 0 -30px; 146 | } 147 | .add-tab{ 148 | text-align: center; 149 | } 150 | .tab-angle-right{ 151 | position: absolute; 152 | top: 50%; 153 | transform: translate(0, -50%); 154 | right: 0; 155 | } 156 | </style> -------------------------------------------------------------------------------- /src/assets/css/animate.css/source/animate.css: -------------------------------------------------------------------------------- 1 | @import '_vars.css'; 2 | @import '_base.css'; 3 | 4 | /* Attention seekers */ 5 | @import 'attention_seekers/bounce.css'; 6 | @import 'attention_seekers/flash.css'; 7 | @import 'attention_seekers/pulse.css'; 8 | @import 'attention_seekers/rubberBand.css'; 9 | @import 'attention_seekers/shakeX.css'; 10 | @import 'attention_seekers/shakeY.css'; 11 | @import 'attention_seekers/headShake.css'; 12 | @import 'attention_seekers/swing.css'; 13 | @import 'attention_seekers/tada.css'; 14 | @import 'attention_seekers/wobble.css'; 15 | @import 'attention_seekers/jello.css'; 16 | @import 'attention_seekers/heartBeat.css'; 17 | 18 | /* Back entrances */ 19 | @import 'back_entrances/backInDown.css'; 20 | @import 'back_entrances/backInLeft.css'; 21 | @import 'back_entrances/backInRight.css'; 22 | @import 'back_entrances/backInUp.css'; 23 | 24 | /* Back exits */ 25 | @import 'back_exits/backOutDown.css'; 26 | @import 'back_exits/backOutLeft.css'; 27 | @import 'back_exits/backOutRight.css'; 28 | @import 'back_exits/backOutUp.css'; 29 | 30 | /* Bouncing entrances */ 31 | @import 'bouncing_entrances/bounceIn.css'; 32 | @import 'bouncing_entrances/bounceInDown.css'; 33 | @import 'bouncing_entrances/bounceInLeft.css'; 34 | @import 'bouncing_entrances/bounceInRight.css'; 35 | @import 'bouncing_entrances/bounceInUp.css'; 36 | 37 | /* Bouncing exits */ 38 | @import 'bouncing_exits/bounceOut.css'; 39 | @import 'bouncing_exits/bounceOutDown.css'; 40 | @import 'bouncing_exits/bounceOutLeft.css'; 41 | @import 'bouncing_exits/bounceOutRight.css'; 42 | @import 'bouncing_exits/bounceOutUp.css'; 43 | 44 | /* Fading entrances */ 45 | @import 'fading_entrances/fadeIn.css'; 46 | @import 'fading_entrances/fadeInDown.css'; 47 | @import 'fading_entrances/fadeInDownBig.css'; 48 | @import 'fading_entrances/fadeInLeft.css'; 49 | @import 'fading_entrances/fadeInLeftBig.css'; 50 | @import 'fading_entrances/fadeInRight.css'; 51 | @import 'fading_entrances/fadeInRightBig.css'; 52 | @import 'fading_entrances/fadeInUp.css'; 53 | @import 'fading_entrances/fadeInUpBig.css'; 54 | @import 'fading_entrances/fadeInTopLeft.css'; 55 | @import 'fading_entrances/fadeInTopRight.css'; 56 | @import 'fading_entrances/fadeInBottomLeft.css'; 57 | @import 'fading_entrances/fadeInBottomRight.css'; 58 | 59 | /* Fading exits */ 60 | @import 'fading_exits/fadeOut.css'; 61 | @import 'fading_exits/fadeOutDown.css'; 62 | @import 'fading_exits/fadeOutDownBig.css'; 63 | @import 'fading_exits/fadeOutLeft.css'; 64 | @import 'fading_exits/fadeOutLeftBig.css'; 65 | @import 'fading_exits/fadeOutRight.css'; 66 | @import 'fading_exits/fadeOutRightBig.css'; 67 | @import 'fading_exits/fadeOutUp.css'; 68 | @import 'fading_exits/fadeOutUpBig.css'; 69 | @import 'fading_exits/fadeOutTopLeft.css'; 70 | @import 'fading_exits/fadeOutTopRight.css'; 71 | @import 'fading_exits/fadeOutBottomRight.css'; 72 | @import 'fading_exits/fadeOutBottomLeft.css'; 73 | 74 | /* Flippers */ 75 | @import 'flippers/flip.css'; 76 | @import 'flippers/flipInX.css'; 77 | @import 'flippers/flipInY.css'; 78 | @import 'flippers/flipOutX.css'; 79 | @import 'flippers/flipOutY.css'; 80 | 81 | /* Lightspeed */ 82 | @import 'lightspeed/lightSpeedInRight.css'; 83 | @import 'lightspeed/lightSpeedInLeft.css'; 84 | @import 'lightspeed/lightSpeedOutRight.css'; 85 | @import 'lightspeed/lightSpeedOutLeft.css'; 86 | 87 | /* Rotating entrances */ 88 | @import 'rotating_entrances/rotateIn.css'; 89 | @import 'rotating_entrances/rotateInDownLeft.css'; 90 | @import 'rotating_entrances/rotateInDownRight.css'; 91 | @import 'rotating_entrances/rotateInUpLeft.css'; 92 | @import 'rotating_entrances/rotateInUpRight.css'; 93 | 94 | /* Rotating exits */ 95 | @import 'rotating_exits/rotateOut.css'; 96 | @import 'rotating_exits/rotateOutDownLeft.css'; 97 | @import 'rotating_exits/rotateOutDownRight.css'; 98 | @import 'rotating_exits/rotateOutUpLeft.css'; 99 | @import 'rotating_exits/rotateOutUpRight.css'; 100 | 101 | /* Specials */ 102 | @import 'specials/hinge.css'; 103 | @import 'specials/jackInTheBox.css'; 104 | @import 'specials/rollIn.css'; 105 | @import 'specials/rollOut.css'; 106 | 107 | /* Zooming entrances */ 108 | @import 'zooming_entrances/zoomIn.css'; 109 | @import 'zooming_entrances/zoomInDown.css'; 110 | @import 'zooming_entrances/zoomInLeft.css'; 111 | @import 'zooming_entrances/zoomInRight.css'; 112 | @import 'zooming_entrances/zoomInUp.css'; 113 | 114 | /* Zooming exits */ 115 | @import 'zooming_exits/zoomOut.css'; 116 | @import 'zooming_exits/zoomOutDown.css'; 117 | @import 'zooming_exits/zoomOutLeft.css'; 118 | @import 'zooming_exits/zoomOutRight.css'; 119 | @import 'zooming_exits/zoomOutUp.css'; 120 | 121 | /* Sliding entrances */ 122 | @import 'sliding_entrances/slideInDown.css'; 123 | @import 'sliding_entrances/slideInLeft.css'; 124 | @import 'sliding_entrances/slideInRight.css'; 125 | @import 'sliding_entrances/slideInUp.css'; 126 | 127 | /* Sliding exits */ 128 | @import 'sliding_exits/slideOutDown.css'; 129 | @import 'sliding_exits/slideOutLeft.css'; 130 | @import 'sliding_exits/slideOutRight.css'; 131 | @import 'sliding_exits/slideOutUp.css'; 132 | -------------------------------------------------------------------------------- /src/components/public/iconList/iconList.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="icon-list-box"> 3 | <div class="remind-choose"> 4 | 请选择一个你喜欢的图标 5 | </div> 6 | <div class="icon-list" ref="iconContainer" @click="chooseIcon" @scroll="scrollUpdate"> 7 | <span :class="['icon-container', {'active': state.currentIcon == item}]" 8 | :id="item" 9 | v-for="(item, index) in hasShowIconList" 10 | :key="index"> 11 | <i :class="['fas', `fa-${item}`]"/> 12 | <span class="select-box" v-show="state.currentIcon == item"> 13 | <i class="fas fa-check"/> 14 | </span> 15 | </span> 16 | </div> 17 | <div class="btn-group"> 18 | <lp-button @_click="cancel" type="warning" plain class="btn-cancel">取消</lp-button> 19 | <lp-button @_click="confirm" type="success" plain class="btn-confirm">确认</lp-button> 20 | </div> 21 | </div> 22 | </template> 23 | 24 | <script> 25 | import { useStore } from 'vuex' 26 | import lpButton from '../../public/lp-button/lp-button' 27 | import { iconList } from './icons' 28 | import { throttle } from '@/utils/utils.js' 29 | import { reactive, ref } from 'vue' 30 | export default { 31 | components: { 32 | lpButton 33 | }, 34 | setup() { 35 | 36 | const store = useStore() 37 | const state = store.state.moduleTab 38 | const hasShowIconList = reactive([]) 39 | const iconContainer = ref(null) 40 | function initIcon () { 41 | let trueCount = () => { 42 | return iconList.length < 30 ? iconList.length : 30 43 | } 44 | hasShowIconList.push(...iconList.slice(-trueCount())) 45 | iconList.length = iconList.length - trueCount() 46 | return function() { 47 | let { scrollHeight, scrollTop, clientHeight } = iconContainer.value 48 | if(scrollTop >= scrollHeight - clientHeight) { 49 | hasShowIconList.push(...iconList.slice(-trueCount())) 50 | iconList.length = iconList.length - trueCount() 51 | 52 | } 53 | } 54 | } 55 | let scrollFn = initIcon() 56 | const scrollUpdate = throttle(scrollFn, 500) 57 | 58 | // 选中某个的icon 59 | function chooseIcon(e) { 60 | let target = null 61 | let tagName = e.target.tagName 62 | if(tagName == 'I') { 63 | target = e.target.parentNode 64 | } else if(tagName == 'SPAN') { 65 | target = e.target 66 | } 67 | store.commit('changeTabInfo', { 68 | key: 'currentIcon', 69 | value: target.id 70 | }) 71 | } 72 | 73 | // 取消选择 74 | function cancel() { 75 | store.commit('changeTabInfo', [ 76 | {key: 'currentIcon', value: ''}, 77 | {key: 'isShowIconList', value: false} 78 | ]) 79 | } 80 | 81 | // 确认选择 82 | function confirm() { 83 | store.commit('changeTabInfo', [ 84 | {key: 'trueIcon', value: state.currentIcon}, 85 | {key: 'isShowIconList', value: false}, 86 | {key: 'isSelected', value: true} 87 | ]) 88 | } 89 | 90 | return { 91 | hasShowIconList, 92 | iconList, 93 | iconContainer, 94 | cancel, 95 | confirm, 96 | chooseIcon, 97 | state, 98 | scrollUpdate 99 | } 100 | } 101 | } 102 | </script> 103 | 104 | <style scoped> 105 | .icon-list-box{ 106 | z-index: 1000; 107 | position: fixed; 108 | top: 50%; 109 | left: 50%; 110 | transform: translate(-50%, -50%); 111 | width: 500px; 112 | height: 400px; 113 | border-radius: 10px; 114 | background-color: white; 115 | } 116 | .remind-choose{ 117 | height: 50px; 118 | line-height: 50px; 119 | font-size: 18px; 120 | font-weight: 600; 121 | color: black !important; 122 | } 123 | .icon-list{ 124 | height: 270px; 125 | overflow: auto; 126 | } 127 | .icon-container{ 128 | float: left; 129 | width: 80px; 130 | height: 80px; 131 | cursor: pointer; 132 | font-size: 30px; 133 | line-height: 80px; 134 | text-align: center; 135 | position: relative; 136 | color: black; 137 | } 138 | .icon-container:hover{ 139 | background-color: rgba(180, 160, 160, .2); 140 | } 141 | .active{ 142 | color: rgba(165, 149, 149, 0.6); 143 | background: rgba(194, 174, 174, .2); 144 | } 145 | .select-box{ 146 | position: absolute; 147 | top: 0; 148 | left: 0; 149 | width: 100%; 150 | height: 100%; 151 | color: green; 152 | } 153 | 154 | 155 | .btn-group{ 156 | height: 80px; 157 | line-height: 80px; 158 | float: right; 159 | } 160 | .btn-confirm{ 161 | margin-right: 15px; 162 | } 163 | .btn-cancel{ 164 | margin-right: 30px; 165 | } 166 | </style> -------------------------------------------------------------------------------- /src/components/public/lp-popover/lp-popover.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div ref="popover" 3 | :class="['lp-popover-container', position]" 4 | :style="{ 5 | 'top': `${top}px`, 6 | 'left': `${left}px`, 7 | 8 | }"> 9 | <div class="container-proxy"> 10 | <div class="lp-popover-title" v-html="title"></div> 11 | <div class="lp-popover-content" v-html="content"></div> 12 | </div> 13 | </div> 14 | </template> 15 | 16 | <script> 17 | import {ref, onMounted, reactive, toRefs} from 'vue' 18 | export default { 19 | props: { 20 | title: { 21 | type: String, 22 | default: '我是标题' 23 | }, 24 | content: { 25 | type: String, 26 | default: '我是一段内容' 27 | }, 28 | position: { // 出现的位置, top | bottom | left | right 29 | type: String, 30 | default: 'bottom' 31 | }, 32 | type: { // 触发方式, hover | click 33 | type: String, 34 | default: 'hover' 35 | } 36 | }, 37 | setup({ position, type }) { 38 | const popover = ref(null) 39 | const site = reactive({ 40 | top: 0, 41 | left: 0, 42 | }) 43 | 44 | onMounted(() => { 45 | const el = popover.value 46 | let { top, left, height: pHeight, widht: pWidth } = el.parentNode.getBoundingClientRect() // 获取目标元素的页面位置信息与尺寸大小 47 | let { height: cHeight, width: cWidth } = el.getBoundingClientRect() // 获取气泡框的宽高 48 | // 设置气泡框的位置 49 | switch(position) { 50 | case 'top': 51 | site['left'] = left 52 | site['top'] = top - cHeight - 25 53 | break; 54 | case 'bottom': 55 | site['left'] = left 56 | site['top'] = top + pHeight + 25 57 | break; 58 | case 'left': 59 | site['top'] = top 60 | site['left'] = left - cWidth - 25 61 | break; 62 | case 'right': 63 | site['top'] = top 64 | site['left'] = left + pWidth + 25 65 | break; 66 | } 67 | 68 | // 为气泡框设置触发方式 69 | switch(type) { 70 | case 'hover': 71 | el.parentNode.addEventListener('mouseover', function() { 72 | el.style.visibility = 'visible' 73 | el.style.opacity = '1' 74 | }) 75 | el.parentNode.addEventListener('mouseout', function() { 76 | el.style.visibility = 'hidden' 77 | el.style.opacity = '0' 78 | }) 79 | break; 80 | case 'click': 81 | el.parentNode.addEventListener('click', function() { 82 | if(el.style.visibility == 'hidden' || el.style.visibility == '') { 83 | el.style.visibility = 'visible' 84 | el.style.opacity = '1' 85 | } else { 86 | el.style.visibility = 'hidden' 87 | el.style.opacity = '2' 88 | } 89 | }) 90 | break; 91 | } 92 | 93 | 94 | }) 95 | 96 | return { 97 | ...toRefs(site), 98 | popover 99 | } 100 | } 101 | } 102 | </script> 103 | 104 | <style scoped> 105 | .lp-popover-container{ 106 | position: fixed; 107 | color: black; 108 | font-weight: normal; 109 | background: white; 110 | max-width: 220px; 111 | max-height: 200px; 112 | border-radius: 7px; 113 | box-shadow: 0 0 2px 3px rgba(206, 202, 202, 0.1); 114 | z-index: 990; 115 | opacity: 0; 116 | visibility: hidden; 117 | transition: all .2s ease; 118 | } 119 | .container-proxy{ 120 | height: 100%; 121 | position: relative; 122 | } 123 | .lp-popover-container::after{ 124 | content: ''; 125 | position: absolute; 126 | width: 0; 127 | height: 0; 128 | border-width: 10px; 129 | border-style: solid; 130 | border-color: transparent transparent white transparent; 131 | } 132 | .lp-popover-container.bottom::after{ 133 | top: -20px; 134 | left: 30px; 135 | } 136 | .lp-popover-container.top::after{ 137 | bottom: -20px; 138 | right: 30px; 139 | border-color: white transparent transparent transparent; 140 | } 141 | .lp-popover-container.left::after{ 142 | right: -20px; 143 | top: 20px; 144 | border-color: transparent transparent transparent white; 145 | } 146 | .lp-popover-container.right::after{ 147 | left: -20px; 148 | top: 20px; 149 | border-color: transparent white transparent transparent; 150 | } 151 | 152 | .lp-popover-title{ 153 | height: 50px; 154 | line-height: 50px; 155 | text-indent: 20px; 156 | font-weight: 400; 157 | font-size: 16px; 158 | text-align: left; 159 | } 160 | .lp-popover-content{ 161 | max-height: 150px; 162 | width: 100%; 163 | box-sizing: border-box; 164 | padding: 5px 10px 15px 15px; 165 | overflow: hidden; 166 | color: rgb(136, 124, 124); 167 | display: inline-block; 168 | font-size: 14px; 169 | line-height: 18px; 170 | letter-spacing: 1px; 171 | } 172 | </style> -------------------------------------------------------------------------------- /src/use/urlAlert.js: -------------------------------------------------------------------------------- 1 | // 新增以及修改url的相关功能 2 | 3 | import { nextTick } from 'vue' 4 | 5 | import store from '@/store/index' 6 | import request from '@/network/request' 7 | import trackImgFunction from '@/use/trackImg' 8 | 9 | // 变量 10 | const state = store.state.moduleUrl // url相关全局状态 11 | 12 | export default function urlAlertFunction($message) { 13 | 14 | // 展示新增url弹框 15 | function showNewUrlAlert(id) { 16 | store.commit('changeUrlInfo', [ 17 | {key: 'isShow', value: true}, 18 | {key: 'whichTag', value: id}, 19 | {key: 'alertType', value: '新增网址'} 20 | ]) 21 | } 22 | 23 | // 展示修改url弹框 24 | function showEditUrlAlert(url) { 25 | store.commit('changeUrlInfo', [ 26 | {key: 'url', value: url.url}, 27 | {key: 'icon', value: url.icon}, 28 | {key: 'id', value: url.id}, 29 | {key: 'name', value: url.name}, 30 | {key: 'isShow', value: true}, 31 | {key: 'alertType', value: '修改网址'} 32 | ]) 33 | } 34 | 35 | // 关闭弹框 36 | function closeUrlAlert() { 37 | store.commit('changeUrlInfo', [ 38 | {key: 'url', value: ''}, 39 | {key: 'icon', value: ''}, 40 | {key: 'isShow', value: false}, 41 | {key: 'name', value: ''}, 42 | {key: 'isLoadingIcon', value: false}, 43 | {key: 'isLoadingName', value: false}, 44 | {key: 'whichTag', value: -1}, 45 | {key: 'imgErr', value: false}, 46 | {key: 'otherIcon', value: ''}, 47 | {key: 'id', value: -1} 48 | ]) 49 | } 50 | 51 | // 点击确认按钮 52 | function confirm() { 53 | if(state.url == '') { 54 | $message({ 55 | type: 'warning', 56 | content: 'URL不能为空' 57 | }) 58 | return; 59 | } 60 | if(state.alertType == '新增网址') { 61 | store.commit('add', { 62 | key: '2', 63 | value: { 64 | name: state.name, 65 | icon: state.icon, 66 | url: state.url, 67 | whichTag: state.whichTag 68 | } 69 | }) 70 | nextTick(() => trackImgFunction().lazyLoad()) 71 | $message({ 72 | type: 'success', 73 | content: '网址添加成功' 74 | }) 75 | } else if(state.alertType == '修改网址') { 76 | store.commit('update', { 77 | key: 'catalogue', 78 | value: { 79 | id: state.id, 80 | name: state.name, 81 | icon: state.icon, 82 | url: state.url, 83 | } 84 | }) 85 | $message({ 86 | type: 'success', 87 | content: '网址修改成功' 88 | }) 89 | } 90 | 91 | closeUrlAlert() 92 | } 93 | 94 | // URL输入框内容改变事件 95 | function inputUrl(value) { 96 | store.commit('changeUrlInfo', { 97 | key: 'url', 98 | value 99 | }) 100 | } 101 | 102 | // Name输入框内容改变事件 103 | function inputName(value) { 104 | if(typeof value != 'object') { 105 | store.commit('changeUrlInfo', { 106 | key: 'name', 107 | value 108 | }) 109 | } 110 | } 111 | 112 | // 获取网页名称 113 | function getUrlName() { 114 | if(state.url == '') { 115 | $message({ 116 | type: 'warning', 117 | content: '请先输入URL' 118 | }) 119 | return; 120 | } 121 | store.commit('changeUrlInfo', { 122 | key: 'isLoadingName', 123 | value: true 124 | }) 125 | 126 | request({ 127 | params: { 128 | target: 'name', 129 | targetUrl: state.url 130 | } 131 | }) 132 | .then(res => { 133 | store.commit('changeUrlInfo', {key: 'name', value: res.data.data}) 134 | $message({ 135 | type: 'success', 136 | content: '网页名称获取成功' 137 | }) 138 | }) 139 | .catch((err) => { 140 | console.log(err); 141 | $message({ 142 | type: 'err', 143 | content: '网络超时或目标网站拒绝此次请求' 144 | }) 145 | }) 146 | .finally(() => { 147 | store.commit('changeUrlInfo', {key: 'isLoadingName', value: false}) 148 | }) 149 | } 150 | 151 | // 获取网页图标 152 | function getUrlIcon() { 153 | if(state.url == '') { 154 | $message({ 155 | type: 'warning', 156 | content: '请先输入URL' 157 | }) 158 | return; 159 | } 160 | 161 | store.commit('changeUrlInfo', { 162 | key: 'isLoadingIcon', 163 | value: true 164 | }) 165 | 166 | request({ 167 | params: { 168 | target: 'icon', 169 | targetUrl: state.url 170 | } 171 | }) 172 | .then(res => { 173 | let icon = res.data.data 174 | let otherIcon = res.data.otherIcon 175 | if(icon == null) icon = otherIcon; 176 | store.commit('changeUrlInfo', [ 177 | {key: 'icon', value: icon}, 178 | {key: 'otherIcon', value: otherIcon} 179 | ]) 180 | $message({ 181 | type: 'success', 182 | content: '图标获取成功' 183 | }) 184 | }) 185 | .catch(() => { 186 | $message({ 187 | type: 'err', 188 | content: '网络超时或目标网站拒绝此次请求' 189 | }) 190 | }) 191 | .finally(() => { 192 | store.commit('changeUrlInfo', [ 193 | {key: 'isLoadingIcon', value: false}, 194 | {key: 'imgErr', value: false} 195 | ]) 196 | }) 197 | 198 | } 199 | 200 | // 图片加载错误 201 | function imgloadErr() { 202 | if(state.otherIcon == '') { 203 | state.imgErr = true 204 | } else { 205 | store.commit('changeUrlInfo', [ 206 | {key: 'icon', value: state.otherIcon}, 207 | {key: 'otherIcon', value: ''} 208 | ]) 209 | } 210 | } 211 | 212 | return { 213 | state, 214 | showNewUrlAlert, 215 | showEditUrlAlert, 216 | closeUrlAlert, 217 | confirm, 218 | inputUrl, 219 | inputName, 220 | getUrlIcon, 221 | getUrlName, 222 | imgloadErr, 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vuex from '../../node_modules/vuex/dist/vuex.cjs' 2 | import { updateLocal } from '@/utils/utils' 3 | import moduleTab from './module/tab' 4 | import moduleUrl from './module/url' 5 | import moduleSearch from './module/search' 6 | 7 | const store = Vuex.createStore({ 8 | state: { 9 | navName: 'Quick Url', 10 | catalogue: [ 11 | {id:'1' , name: "常用网站", icon: "align-justify", URLS: [ 12 | {id:'1.1' , url: 'https://github.com/Lpyexplore/nav-url', icon: 'https://github.com/fluidicon.png', name: 'github'}, 13 | {id:'1.2' , url: 'https://juejin.cn/post/6897030228867022856', icon: 'https://b-gold-cdn.xitu.io/favicons/v2/favicon-32x32.png', name: 'Vue3 API教程'}, 14 | ]} 15 | ] 16 | }, 17 | getters: { 18 | // 判断标签是否显示 19 | judgeTabIsShow: (state) => (i) => { 20 | const searchWord = state.moduleSearch.searchWord 21 | const URLS = state.catalogue[i]['URLS'] 22 | let length = URLS.length 23 | for(let j = 0; j < length; j++) { 24 | if(searchWord == '') return false; 25 | else if(URLS[j].name.toLowerCase().indexOf(searchWord.toLowerCase()) !== -1) return true; 26 | } 27 | return false 28 | }, 29 | // 判断url是否显示 30 | judgeUrlIsShow: (state) => (i, j) => { 31 | const searchWord = state.moduleSearch.searchWord 32 | const url = state.catalogue[i]['URLS'][j] 33 | if(searchWord == '') return false; 34 | let matchResult = url.name.toLowerCase().indexOf(searchWord.toLowerCase()) 35 | if(matchResult !== -1) return true; 36 | return false; 37 | }, 38 | }, 39 | mutations: { 40 | // 初始化 41 | init(state, payload) { 42 | let { navName, catalogue } = payload 43 | state.navName = navName 44 | state.catalogue = catalogue 45 | }, 46 | // 更新 47 | update(state, payload) { 48 | let {key, value} = payload 49 | // 更新网页标题 50 | if(key === 'navName') state.navName = value; 51 | // 更新标签或URL 52 | else if(key === 'catalogue') { 53 | const catalogue = state.catalogue 54 | let length1 = catalogue.length 55 | for(let i = 0; i < length1; i++) { 56 | let current = catalogue[i] 57 | if(current.id == value.id.split('.')[0]) { 58 | // 修改的是标签信息 59 | if(current.id == value.id) { 60 | current.name = value.name 61 | current.icon = value.icon 62 | updateLocal(store) 63 | } else { 64 | let URLS = current.URLS 65 | let length2 = URLS.length 66 | for(let j = 0; j < length2; j++) { 67 | let URL = URLS[j] 68 | if(URL.id == value.id) { 69 | URL.url = value.url 70 | URL.icon = value.icon 71 | URL.name = value.name 72 | updateLocal(store) 73 | break; 74 | } 75 | } 76 | } 77 | break; 78 | } 79 | } 80 | } 81 | }, 82 | // 移除(根据id来移除) 83 | remove(state, payload) { 84 | // 需要判断是删除标签还是删除一个网址 85 | const catalogue = state.catalogue 86 | let length1 = catalogue.length 87 | let iid = payload.split('.') 88 | for(let i = 0; i < length1; i++) { 89 | let current = catalogue[i] 90 | if(current.id === iid[0]) { 91 | // 删除标签已经标签内的所有网址 92 | if(iid.length === 1) { 93 | catalogue.splice(i, 1) 94 | updateLocal(store) 95 | break; 96 | } 97 | // 删除标签内的某个网址 98 | else { 99 | let URLS = current.URLS 100 | let length2 = URLS.length 101 | for(let j = 0; j < length2; j++) { 102 | let URL = URLS[j] 103 | if(URL.id === payload) { 104 | URLS.splice(j, 1) 105 | updateLocal(store) 106 | break; 107 | } 108 | } 109 | } 110 | } 111 | } 112 | }, 113 | // 添加 114 | add(state, payload) { 115 | let {key, value} = payload 116 | const catalogue = state.catalogue 117 | let length1 = catalogue.length 118 | // 添加标签 119 | if(key == '1') { 120 | let _id = length1 == 0 ? '1' : (+catalogue[length1 - 1].id + 1).toString() 121 | catalogue.push({ 122 | id: _id, 123 | name: value.name, 124 | icon: value.icon, 125 | URLS: [] 126 | }) 127 | updateLocal(store) 128 | } 129 | // 添加网址 130 | else if(key == '2') { 131 | let id = value.whichTag 132 | for(let i = 0; i < length1; i++) { 133 | let current = catalogue[i] 134 | if(current.id == id) { 135 | let URLS = current.URLS 136 | let length2 = URLS.length 137 | let trueId; 138 | // 判断原来是否有其他URL 139 | if(length2 === 0) { 140 | trueId = `${id}.1` 141 | } 142 | else { 143 | let max = 0 144 | URLS.forEach(v => { 145 | let currentId = +v.id.split('.')[1] 146 | max = currentId > max ? currentId : max 147 | }) 148 | trueId = `${id}.${max + 1}` 149 | } 150 | URLS.push({ 151 | id: trueId, 152 | url: value.url, 153 | icon: value.icon, 154 | name: value.name 155 | }) 156 | updateLocal(store) 157 | break; 158 | } 159 | } 160 | } 161 | }, 162 | // 拖拽结束后,更新对应标签内地址框的位置变动 163 | dragEndToUpdate(state, payload) { 164 | let { tabId, result } = payload 165 | const catalogue = state.catalogue 166 | let length = catalogue.length 167 | for(let i = 0; i < length; i++) { 168 | if(catalogue[i].id != tabId) continue; 169 | const URLS = catalogue[i].URLS 170 | const newURLS = new Array(URLS.length) 171 | URLS.forEach(v => { 172 | newURLS[result.indexOf(v.id)] = v 173 | }) 174 | catalogue[i].URLS = newURLS 175 | break; 176 | } 177 | updateLocal(store) 178 | } 179 | }, 180 | modules: { 181 | moduleTab, 182 | moduleUrl, 183 | moduleSearch 184 | } 185 | }) 186 | 187 | export default store 188 | -------------------------------------------------------------------------------- /src/components/public/lp-button/lp-button.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | 3 | <button class="lp-button-container" 4 | :class="[ 5 | `lp-button-${type}`, 6 | {'is-round': round}, 7 | {'is-circle': circle}, 8 | {'is-disabled': disabled}, 9 | {'is-plain': plain}, 10 | {'is-loading': loading} 11 | ]" 12 | @click="btnClick" 13 | ref="el"> 14 | <span v-show="loading" class="is-loading"> 15 | <i class="fa fa-spinner fa-spin"/> 16 | <span style="margin-left: 5px" v-show="loading && !circle">加载中</span> 17 | </span> 18 | <span v-show="!loading"> 19 | <slot>{{ circle? '查': 'lp-button' }}</slot> 20 | </span> 21 | 22 | 23 | </button> 24 | 25 | </template> 26 | 27 | <script> 28 | import {ref} from 'vue' 29 | export default { 30 | name: "lp-button", 31 | props: { 32 | type: { 33 | type: String, 34 | default: '' 35 | }, 36 | plain: { 37 | type: Boolean, 38 | default: false 39 | }, 40 | round: { 41 | type: Boolean, 42 | default: false 43 | }, 44 | circle: { 45 | type: Boolean, 46 | default: false 47 | }, 48 | disabled: { 49 | type: Boolean, 50 | default: false 51 | }, 52 | loading: { 53 | type: Boolean, 54 | default: false 55 | } 56 | 57 | }, 58 | setup(props, context) { 59 | let el = ref(null) 60 | function btnClick() { 61 | if(props.disabled || props.loading) return; 62 | context.emit('_click', el) 63 | } 64 | return {btnClick, el} 65 | } 66 | 67 | 68 | } 69 | </script> 70 | 71 | <style scoped> 72 | .lp-button-container{ 73 | cursor: pointer; 74 | width: 80px; 75 | height: 45px; 76 | border-radius: 5px; 77 | border: 1px solid #d9d3d3; 78 | background: white; 79 | color: #606266; 80 | outline: none; 81 | display: inline-block; 82 | font-size: 14px; 83 | user-select: none; 84 | -webkit-user-select: none; 85 | -ms-user-select: none; 86 | -moz-user-select: none; 87 | text-align: center; 88 | position: relative; 89 | } 90 | 91 | .lp-button-container:not(.is-disabled):not(.is-loading):hover{ 92 | background: rgba(162, 222, 252, 0.5); 93 | color: #1292d9; 94 | } 95 | .lp-button-container:not(.is-disabled):not(.is-loading):active{ 96 | border: 1px solid #3e9fd4; 97 | } 98 | 99 | .lp-button-success{ 100 | background: #17af17; 101 | color: white; 102 | border: 1px solid #17af17; 103 | } 104 | .lp-button-success:not(.is-disabled):not(.is-loading):hover{ 105 | background: #19c119; 106 | color: white; 107 | border: 1px solid #19c119; 108 | } 109 | .lp-button-success:not(.is-disabled):not(.is-loading):active{ 110 | background: #22b422; 111 | } 112 | 113 | .lp-button-danger{ 114 | background: rgba(222, 7, 7, 0.8); 115 | color: white; 116 | border: 1px solid rgba(222, 7, 7, .8); 117 | } 118 | .lp-button-danger:not(.is-disabled):not(.is-loading):hover{ 119 | background: rgba(246, 76, 76, 1); 120 | color: white; 121 | border: 1px solid rgba(246, 76, 76, 1); 122 | } 123 | .lp-button-danger:not(.is-disabled):not(.is-loading):active{ 124 | background: rgba(238, 0, 0, .8); 125 | } 126 | 127 | .lp-button-primary{ 128 | background: #0c94de; 129 | color: white; 130 | border: 1px solid #0c94de; 131 | } 132 | .lp-button-primary:not(.is-disabled):not(.is-loading):hover{ 133 | background: #0e9fef; 134 | color: white; 135 | border: 1px solid #0e9fef; 136 | } 137 | .lp-button-primary:not(.is-disabled):not(.is-loading):active{ 138 | background: #0b8cd2; 139 | } 140 | 141 | .lp-button-warning{ 142 | background: #f39a34; 143 | color: white; 144 | border: 1px solid #f39a34; 145 | } 146 | .lp-button-warning:not(.is-disabled):not(.is-loading):hover{ 147 | background: #fca74b; 148 | color: white; 149 | border: 1px solid #fca74b; 150 | } 151 | .lp-button-warning:not(.is-disabled):not(.is-loading):active{ 152 | background: #f39a34; 153 | } 154 | 155 | /* -------------plain--------------- */ 156 | .lp-button-container.is-plain:not(.is-disabled):not(.is-loading):hover{ 157 | background: white; 158 | border: 1px solid #3e9fd4; 159 | } 160 | .lp-button-container.is-plain:not(.is-disabled):not(.is-loading):active{ 161 | border: 1px solid #3283ac; 162 | color: #3283ac; 163 | } 164 | 165 | .lp-button-success.is-plain{ 166 | background: rgba(26, 189, 26, 0.15); 167 | color: #61b836; 168 | border: 1px solid rgba(127, 201, 90, .5); 169 | } 170 | .lp-button-success.is-plain:not(.is-disabled):not(.is-loading):hover{ 171 | background: #19c119; 172 | color: white; 173 | border: 1px solid #19c119; 174 | } 175 | .lp-button-success.is-plain:not(.is-disabled):not(.is-loading):active{ 176 | background: #22b422; 177 | } 178 | 179 | .lp-button-danger.is-plain{ 180 | background: rgba(222, 7, 7, 0.09); 181 | color: rgba(224, 63, 63, .9); 182 | border: 1px solid rgba(222, 7, 7, .2); 183 | } 184 | .lp-button-danger.is-plain:not(.is-disabled):not(.is-loading):hover{ 185 | background: rgba(246, 76, 76, 1); 186 | color: white; 187 | border: 1px solid rgba(246, 76, 76, 1); 188 | } 189 | .lp-button-danger.is-plain:not(.is-disabled):not(.is-loading):active{ 190 | background: rgba(238, 0, 0, .8); 191 | } 192 | 193 | .lp-button-primary.is-plain{ 194 | background: rgba(12, 148, 222, .1); 195 | color: #0c94de; 196 | border: 1px solid rgba(12, 148, 222, .35); 197 | } 198 | .lp-button-primary.is-plain:not(.is-disabled):not(.is-loading):hover{ 199 | background: #0e9fef; 200 | color: white; 201 | border: 1px solid #0e9fef; 202 | } 203 | .lp-button-primary.is-plain:not(.is-disabled):not(.is-loading):active{ 204 | background: #0b8cd2; 205 | } 206 | 207 | .lp-button-warning.is-plain{ 208 | background: rgba(243, 154, 52, .1); 209 | color: #f39a34; 210 | border: 1px solid rgba(243, 154, 52, .4); 211 | } 212 | .lp-button-warning.is-plain:not(.is-disabled):not(.is-loading):hover{ 213 | background: #fca74b; 214 | color: white; 215 | border: 1px solid #fca74b; 216 | } 217 | .lp-button-warning.is-plain:not(.is-disabled):not(.is-loading):active{ 218 | background: #f39a34; 219 | } 220 | 221 | /* ------------- round --------------- */ 222 | .lp-button-container.is-round{ 223 | border-radius: 100px; 224 | } 225 | 226 | /* ------------- circle --------------- */ 227 | .lp-button-container.is-circle{ 228 | border-radius: 50%; 229 | width: 45px; 230 | } 231 | 232 | /* ------------- disabled / loading --------------- */ 233 | .lp-button-container.is-disabled, .lp-button-container.is-loading{ 234 | cursor: not-allowed; 235 | opacity: .6; 236 | filter:alpha(opacity=60) 237 | } 238 | 239 | /* ------------- loading --------------- */ 240 | 241 | span.is-loading{ 242 | width: 100%; 243 | height: 100%; 244 | display: flex; 245 | justify-content: center; 246 | align-items: center; 247 | } 248 | </style> -------------------------------------------------------------------------------- /src/assets/css/reset/reset.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in iOS. 9 | */ 10 | 11 | html { 12 | line-height: 1.15; /* 1 */ 13 | -webkit-text-size-adjust: 100%; /* 2 */ 14 | } 15 | 16 | /* Sections 17 | ========================================================================== */ 18 | 19 | /** 20 | * Remove the margin in all browsers. 21 | */ 22 | 23 | body { 24 | margin: 0; 25 | } 26 | 27 | /** 28 | * Render the `main` element consistently in IE. 29 | */ 30 | 31 | main { 32 | display: block; 33 | } 34 | 35 | /** 36 | * Correct the font size and margin on `h1` elements within `section` and 37 | * `article` contexts in Chrome, Firefox, and Safari. 38 | */ 39 | 40 | h1 { 41 | font-size: 2em; 42 | margin: 0.67em 0; 43 | } 44 | 45 | /* Grouping content 46 | ========================================================================== */ 47 | 48 | /** 49 | * 1. Add the correct box sizing in Firefox. 50 | * 2. Show the overflow in Edge and IE. 51 | */ 52 | 53 | hr { 54 | box-sizing: content-box; /* 1 */ 55 | height: 0; /* 1 */ 56 | overflow: visible; /* 2 */ 57 | } 58 | 59 | /** 60 | * 1. Correct the inheritance and scaling of font size in all browsers. 61 | * 2. Correct the odd `em` font sizing in all browsers. 62 | */ 63 | 64 | pre { 65 | font-family: monospace, monospace; /* 1 */ 66 | font-size: 1em; /* 2 */ 67 | } 68 | 69 | /* Text-level semantics 70 | ========================================================================== */ 71 | 72 | /** 73 | * Remove the gray background on active links in IE 10. 74 | */ 75 | 76 | a { 77 | background-color: transparent; 78 | } 79 | 80 | /** 81 | * 1. Remove the bottom border in Chrome 57- 82 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 83 | */ 84 | 85 | abbr[title] { 86 | border-bottom: none; /* 1 */ 87 | text-decoration: underline; /* 2 */ 88 | text-decoration: underline dotted; /* 2 */ 89 | } 90 | 91 | /** 92 | * Add the correct font weight in Chrome, Edge, and Safari. 93 | */ 94 | 95 | b, 96 | strong { 97 | font-weight: bolder; 98 | } 99 | 100 | /** 101 | * 1. Correct the inheritance and scaling of font size in all browsers. 102 | * 2. Correct the odd `em` font sizing in all browsers. 103 | */ 104 | 105 | code, 106 | kbd, 107 | samp { 108 | font-family: monospace, monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /** 113 | * Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /** 121 | * Prevent `sub` and `sup` elements from affecting the line height in 122 | * all browsers. 123 | */ 124 | 125 | sub, 126 | sup { 127 | font-size: 75%; 128 | line-height: 0; 129 | position: relative; 130 | vertical-align: baseline; 131 | } 132 | 133 | sub { 134 | bottom: -0.25em; 135 | } 136 | 137 | sup { 138 | top: -0.5em; 139 | } 140 | 141 | /* Embedded content 142 | ========================================================================== */ 143 | 144 | /** 145 | * Remove the border on images inside links in IE 10. 146 | */ 147 | 148 | img { 149 | border-style: none; 150 | } 151 | 152 | /* Forms 153 | ========================================================================== */ 154 | 155 | /** 156 | * 1. Change the font styles in all browsers. 157 | * 2. Remove the margin in Firefox and Safari. 158 | */ 159 | 160 | button, 161 | input, 162 | optgroup, 163 | select, 164 | textarea { 165 | font-family: inherit; /* 1 */ 166 | font-size: 100%; /* 1 */ 167 | line-height: 1.15; /* 1 */ 168 | margin: 0; /* 2 */ 169 | } 170 | 171 | /** 172 | * Show the overflow in IE. 173 | * 1. Show the overflow in Edge. 174 | */ 175 | 176 | button, 177 | input { /* 1 */ 178 | overflow: visible; 179 | } 180 | 181 | /** 182 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 183 | * 1. Remove the inheritance of text transform in Firefox. 184 | */ 185 | 186 | button, 187 | select { /* 1 */ 188 | text-transform: none; 189 | } 190 | 191 | /** 192 | * Correct the inability to style clickable types in iOS and Safari. 193 | */ 194 | 195 | button, 196 | [type="button"], 197 | [type="reset"], 198 | [type="submit"] { 199 | -webkit-appearance: button; 200 | } 201 | 202 | /** 203 | * Remove the inner border and padding in Firefox. 204 | */ 205 | 206 | button::-moz-focus-inner, 207 | [type="button"]::-moz-focus-inner, 208 | [type="reset"]::-moz-focus-inner, 209 | [type="submit"]::-moz-focus-inner { 210 | border-style: none; 211 | padding: 0; 212 | } 213 | 214 | /** 215 | * Restore the focus styles unset by the previous rule. 216 | */ 217 | 218 | button:-moz-focusring, 219 | [type="button"]:-moz-focusring, 220 | [type="reset"]:-moz-focusring, 221 | [type="submit"]:-moz-focusring { 222 | outline: 1px dotted ButtonText; 223 | } 224 | 225 | /** 226 | * Correct the padding in Firefox. 227 | */ 228 | 229 | fieldset { 230 | padding: 0.35em 0.75em 0.625em; 231 | } 232 | 233 | /** 234 | * 1. Correct the text wrapping in Edge and IE. 235 | * 2. Correct the color inheritance from `fieldset` elements in IE. 236 | * 3. Remove the padding so developers are not caught out when they zero out 237 | * `fieldset` elements in all browsers. 238 | */ 239 | 240 | legend { 241 | box-sizing: border-box; /* 1 */ 242 | color: inherit; /* 2 */ 243 | display: table; /* 1 */ 244 | max-width: 100%; /* 1 */ 245 | padding: 0; /* 3 */ 246 | white-space: normal; /* 1 */ 247 | } 248 | 249 | /** 250 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 251 | */ 252 | 253 | progress { 254 | vertical-align: baseline; 255 | } 256 | 257 | /** 258 | * Remove the default vertical scrollbar in IE 10+. 259 | */ 260 | 261 | textarea { 262 | overflow: auto; 263 | } 264 | 265 | /** 266 | * 1. Add the correct box sizing in IE 10. 267 | * 2. Remove the padding in IE 10. 268 | */ 269 | 270 | [type="checkbox"], 271 | [type="radio"] { 272 | box-sizing: border-box; /* 1 */ 273 | padding: 0; /* 2 */ 274 | } 275 | 276 | /** 277 | * Correct the cursor style of increment and decrement buttons in Chrome. 278 | */ 279 | 280 | [type="number"]::-webkit-inner-spin-button, 281 | [type="number"]::-webkit-outer-spin-button { 282 | height: auto; 283 | } 284 | 285 | /** 286 | * 1. Correct the odd appearance in Chrome and Safari. 287 | * 2. Correct the outline style in Safari. 288 | */ 289 | 290 | [type="search"] { 291 | -webkit-appearance: textfield; /* 1 */ 292 | outline-offset: -2px; /* 2 */ 293 | } 294 | 295 | /** 296 | * Remove the inner padding in Chrome and Safari on macOS. 297 | */ 298 | 299 | [type="search"]::-webkit-search-decoration { 300 | -webkit-appearance: none; 301 | } 302 | 303 | /** 304 | * 1. Correct the inability to style clickable types in iOS and Safari. 305 | * 2. Change font properties to `inherit` in Safari. 306 | */ 307 | 308 | ::-webkit-file-upload-button { 309 | -webkit-appearance: button; /* 1 */ 310 | font: inherit; /* 2 */ 311 | } 312 | 313 | /* Interactive 314 | ========================================================================== */ 315 | 316 | /* 317 | * Add the correct display in Edge, IE 10+, and Firefox. 318 | */ 319 | 320 | details { 321 | display: block; 322 | } 323 | 324 | /* 325 | * Add the correct display in all browsers. 326 | */ 327 | 328 | summary { 329 | display: list-item; 330 | } 331 | 332 | /* Misc 333 | ========================================================================== */ 334 | 335 | /** 336 | * Add the correct display in IE 10+. 337 | */ 338 | 339 | template { 340 | display: none; 341 | } 342 | 343 | /** 344 | * Add the correct display in IE 10. 345 | */ 346 | 347 | [hidden] { 348 | display: none; 349 | } 350 | 351 | ul{ 352 | list-style: none; 353 | padding: 0; 354 | margin: 0; 355 | } 356 | 357 | a{ 358 | text-decoration: none; 359 | color: #666; 360 | } 361 | 362 | input{ 363 | padding: 0; 364 | border: 0; 365 | outline: none; 366 | } -------------------------------------------------------------------------------- /src/components/main/index.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div id="content-container"> 3 | <div id="notice"> 4 | <i class="fas fa-bell" /> 5 | <carousel/> 6 | <search></search> 7 | </div> 8 | <div id="content" ref="scrollContent" @scroll="lazyLoad"> 9 | <div v-for="(tab, i) in catalogue" 10 | :key="tab.id" 11 | class="each-content" 12 | v-show="!moduleSearch.isSearch || (moduleSearch.isSearch && judgeTabIsShow(i))"> 13 | <div :id="tab.id" class="tab-title"> 14 | <i :class="['fas', `fa-${tab.icon}`, 'tab-icon']"/> 15 | <span class="tab-name">{{tab.name}}</span> 16 | <span :class="['edit-tab-name', {'tabIsEdit': tab.id == editWhich}]"> 17 | <i class="fas fa-trash-alt delete-icon" @click="deleteTab(tab.id)"/> 18 | <i class="fas fa-edit edit-icon" @click="showEditAddTab(tab)"/> 19 | </span> 20 | <span :class="['edit', {'isEdit': tab.id == editWhich}]" 21 | @click="handleEdit(tab.id)"> 22 | {{ tab.id == editWhich? '退出' : '编辑' }} 23 | </span> 24 | </div> 25 | <ul class="url-boxes" 26 | @dragstart="urlBoxDragStart" 27 | @dragend="urlBoxDragEnd"> 28 | <li v-for="(urls, j) in tab.URLS" 29 | :key="urls.id" 30 | class="each-url-box" 31 | v-show="!moduleSearch.isSearch || (moduleSearch.isSearch && judgeUrlIsShow(i, j))" 32 | :draggable="tab.id == editWhich ? true : false" 33 | @dragenter="urlBoxEnter($event, tab.id)" 34 | :data-id="urls.id"> 35 | <a :href="urls.url" target="_blank" class="url-link"> 36 | <div class="round-box"> 37 | <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAbFBMVEUAAABRUVFRUVFRUVFRUVFSUlJSUlJRUVFRUVFRUVFRUVFRUVFRUVFRUVFQUFBSUlJQUFBRUVFQUFBRUVFRUVFRUVFQUFBRUVFQUFBRUVFRUVFVVVVVVVVNTU1RUVFRUVFRUVFQUFBVVVVRUVH7fq3cAAAAI3RSTlMAi++UYjoV+fTFvauiVDIqHd/aybh4cmpcTEQkBwXo5cx8DKz3rEYAAAEaSURBVHja7dfHUsMwFEBRpfcESCWFpv//RxZkMLZs7zAz4pz13XjkZz8FAAAAAAAAAAAAAAAAAAAAAAD4NevDoj/bj9qjh+Hy8Wmwemivzr23/nK4CX/hYxC/bE8t1SHe9Vqi0fweLcahc6NJ/LZrisbbInq8NFW9IpqcQsdW8aen+ugWS2711UspWodu9WPJqjaal6NB83kUXkOnBrFsWjfMw1jxHFKbaSV6Dx0ax0LzLM+q0azlQApdDvw5Vs3T6DqtRpNrWu1iem7dOcaqfhqtY2LUPGyFfejOMiY2NSOSOCbRJY0WoZkHyf3VymbYs/n8ZvNDzGdFyWdpzGaNz+dilc9VFwAAAAAAAAAAAAAAAAAAAACA/+ETQgdy2yXwzBAAAAAASUVORK5CYII=" 38 | :data-src="urls.icon" 39 | :alt="urls.name" 40 | class="url-icon" 41 | @load="imgLoadSuccess" 42 | @error="imgLoadErr" 43 | draggable="false"> 44 | <svg t="1604809784875" class="icon url-icon err-url-icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2514" width="80%" height="80%"><path d="M511.58 513.75m-415.89 0a415.89 415.89 0 1 0 831.78 0 415.89 415.89 0 1 0-831.78 0Z" fill="#353F51" p-id="2515"></path><path d="M511.58 173.48c187.63 0 340.27 152.64 340.27 340.27S699.21 854.02 511.58 854.02 171.31 701.38 171.31 513.75s152.65-340.27 340.27-340.27m0-75.61C281.9 97.87 95.7 284.07 95.7 513.75s186.2 415.89 415.89 415.89 415.89-186.2 415.89-415.89S741.27 97.87 511.58 97.87z" fill="#70798B" p-id="2516"></path><path d="M511.58 173.48c52.68 0 132.33 135.71 132.33 340.27s-79.65 340.27-132.33 340.27-132.32-135.71-132.32-340.27 79.64-340.27 132.32-340.27m0-75.61c-114.84 0-207.94 186.2-207.94 415.89s93.1 415.89 207.94 415.89 207.94-186.2 207.94-415.89S626.43 97.87 511.58 97.87z" fill="#70798B" p-id="2517"></path><path d="M133.51 362.52h756.16v75.62H133.51zM133.51 589.37h756.16v75.62H133.51z" fill="#70798B" p-id="2518"></path></svg> 45 | </div> 46 | <span class="url-name">{{ urls.name }}</span> 47 | </a> 48 | <span :class="['edit-container', {'urlIsEdit': tab.id == editWhich}]"> 49 | <i class="fas fa-trash-alt delete-icon" @click="deleteUrl(urls.id)"/> 50 | <i class="fas fa-edit edit-icon" @click="showEditUrlAlert(urls)"/> 51 | </span> 52 | </li> 53 | <li class="each-url-box add-more" 54 | @click="showNewUrlAlert(tab.id)"> 55 | <i class="fas fa-plus"/> 56 | </li> 57 | </ul> 58 | </div> 59 | <urlAlert/> 60 | </div> 61 | </div> 62 | </template> 63 | 64 | <script> 65 | /* API */ 66 | import { inject, onMounted } from 'vue' 67 | import { useStore } from 'vuex' 68 | 69 | /* 组件 */ 70 | import urlAlert from '@/components/public/urlAlert/index' 71 | import tabAlert from '@/components/public/tabAlert/index' 72 | import carousel from './carousel' 73 | import search from './search' 74 | /* 功能模块 */ 75 | import trackImgFunction from '@/use/trackImg' 76 | import editFunction from '@/use/edit' 77 | import urlAlertFunction from '@/use/urlAlert' 78 | import tabAlertFunction from '@/use/tabAlert' 79 | import searchFunction from '@/use/search' 80 | import { throttle } from '@/utils/utils' 81 | export default { 82 | components: { 83 | urlAlert, 84 | tabAlert, 85 | carousel, 86 | search, 87 | }, 88 | setup() { 89 | const catalogue = useStore().state.catalogue 90 | const $message = inject('message') 91 | const $confirm = inject('confirm') 92 | 93 | // 一些基础的方法 94 | let { imgLoadErr, imgLoadSuccess, lazyLoad, scrollContent } = trackImgFunction() 95 | 96 | // url框编辑下的相关变量及功能 97 | let { 98 | editWhich, 99 | handleEdit, 100 | deleteTab, 101 | deleteUrl, 102 | urlBoxDragStart, 103 | urlBoxDragEnd, 104 | urlBoxEnter 105 | } = editFunction($message, $confirm) 106 | 107 | // 弹出 “新增”、“修改” url弹框 108 | let { showNewUrlAlert, showEditUrlAlert } = urlAlertFunction() 109 | 110 | // 搜索功能相关的变量及方法 111 | let { moduleSearch, judgeTabIsShow, judgeUrlIsShow } = searchFunction() 112 | 113 | // 展示修改tab的弹框 114 | let { showEditAddTab } = tabAlertFunction() 115 | 116 | onMounted(() => { 117 | lazyLoad() 118 | }) 119 | 120 | return { 121 | catalogue, 122 | showNewUrlAlert, 123 | moduleSearch, 124 | imgLoadErr, 125 | imgLoadSuccess, 126 | lazyLoad: throttle(lazyLoad, 500), 127 | scrollContent, 128 | handleEdit, 129 | showEditAddTab, 130 | deleteTab, 131 | deleteUrl, 132 | showEditUrlAlert, 133 | editWhich, 134 | judgeTabIsShow, 135 | judgeUrlIsShow, 136 | urlBoxDragStart, 137 | urlBoxDragEnd, 138 | urlBoxEnter, 139 | } 140 | } 141 | } 142 | </script> 143 | 144 | <style scoped> 145 | #content-container{ 146 | display: block; 147 | margin-left: 250px; 148 | height: 100vh; 149 | background-color: rgb(249, 249, 249); 150 | } 151 | #notice{ 152 | background-color: white; 153 | height: 80px; 154 | box-shadow: 1px 1px 5px #eee; 155 | line-height: 80px; 156 | position: relative; 157 | } 158 | .fa-bell{ 159 | color: rgb(240, 179, 12); 160 | margin-left: 20px; 161 | } 162 | #content{ 163 | height: calc(100% - 80px); 164 | overflow: auto; 165 | } 166 | .tab-title{ 167 | height: 60px; 168 | line-height: 60px; 169 | color: #837c7c; 170 | position: relative; 171 | } 172 | .tab-icon{ 173 | margin: 0 10px 0 30px; 174 | } 175 | .edit-tab-name{ 176 | display: inline-block; 177 | width: 55px; 178 | height: 20.8px; 179 | line-height: 20.8px; 180 | color: #eee; 181 | display: none; 182 | } 183 | .tabIsEdit{ 184 | display: inline-block; 185 | } 186 | .edit-icon, .delete-icon{ 187 | margin-left: 10px; 188 | color: rgb(112, 106, 106); 189 | font-size: 14px; 190 | cursor: pointer; 191 | } 192 | .edit-icon{ 193 | margin-right: 5px; 194 | } 195 | 196 | .edit-icon:hover, .delete-icon:hover{ 197 | color: rgb(194, 96, 4); 198 | } 199 | .each-content:hover .edit{ 200 | display: inline-block; 201 | } 202 | .edit{ 203 | position: absolute; 204 | right: 20px; 205 | top: 50%; 206 | transform: translate(0, -50%); 207 | color: rgb(172, 161, 161); 208 | font-size: .8em; 209 | cursor: pointer; 210 | display: none; 211 | } 212 | .edit:hover{ 213 | color: #666; 214 | } 215 | .isEdit{ 216 | display: block; 217 | } 218 | .url-boxes{ 219 | display: inline-block; 220 | position: relative; 221 | } 222 | .each-url-box{ 223 | display: inline-block; 224 | height: 150px; 225 | width: 200px; 226 | background-color: white; 227 | box-shadow: 0 0 3px 3px rgba(225, 225, 225, .1); 228 | cursor: pointer; 229 | overflow: hidden; 230 | border-radius: 10px; 231 | margin: 15px 0 15px 30px; 232 | position: relative; 233 | } 234 | .edit-container{ 235 | position: absolute; 236 | top: 0; 237 | right: -55px; 238 | display: inline-block; 239 | width: 55px; 240 | height: 25px; 241 | line-height: 25px; 242 | color: #eee; 243 | transition: all .5s ease; 244 | opacity: 0; 245 | border-top-left-radius: 8px; 246 | border-bottom-left-radius: 8px; 247 | background-color: rgb(248, 237, 237); 248 | } 249 | .urlIsEdit{ 250 | opacity: 1; 251 | transform: translate(-55px); 252 | } 253 | .each-url-box:hover{ 254 | transform: translate(0, -5px); 255 | transition: all .3s ease; 256 | box-shadow: 0 0 3px 3px rgba(225, 225, 225, .3); 257 | } 258 | .url-link{ 259 | height: 100%; 260 | width: 100%; 261 | position: relative; 262 | } 263 | .round-box{ 264 | height: 70%; 265 | display: flex; 266 | justify-content: center; 267 | align-items: center; 268 | } 269 | .url-icon{ 270 | display: block; 271 | border-radius: 50%; 272 | overflow: hidden; 273 | height: 60%; 274 | } 275 | .err-url-icon{ 276 | display: none; 277 | } 278 | .url-name{ 279 | display: block; 280 | height: 25.5%; 281 | text-align: center; 282 | color: #666; 283 | overflow: hidden; 284 | box-sizing: border-box; 285 | padding: 0 10px; 286 | word-break: break-all; 287 | word-wrap: break-word; 288 | text-overflow: ellipsis; 289 | } 290 | .add-more{ 291 | text-align: center; 292 | line-height: 150px; 293 | color: #e1e1e1; 294 | font-size: 1.5em; 295 | } 296 | </style> -------------------------------------------------------------------------------- /src/components/public/iconList/icons.js: -------------------------------------------------------------------------------- 1 | export let iconList = `ad 2 | address-book 3 | address-card 4 | adjust 5 | air-freshener 6 | align-center 7 | align-justify 8 | align-left 9 | align-right 10 | allergies 11 | ambulance 12 | american-sign-language-interpreting 13 | anchor 14 | angle-double-down 15 | angle-double-left 16 | angle-double-right 17 | angle-double-up 18 | angle-down 19 | angle-left 20 | angle-right 21 | angle-up 22 | angry 23 | ankh 24 | apple-alt 25 | archive 26 | archway 27 | arrow-alt-circle-down 28 | arrow-alt-circle-left 29 | arrow-alt-circle-right 30 | arrow-alt-circle-up 31 | arrow-circle-down 32 | arrow-circle-left 33 | arrow-circle-right 34 | arrow-circle-up 35 | arrow-down 36 | arrow-left 37 | arrow-right 38 | arrow-up 39 | arrows-alt 40 | arrows-alt-h 41 | arrows-alt-v 42 | assistive-listening-systems 43 | asterisk 44 | at 45 | atlas 46 | atom 47 | audio-description 48 | award 49 | baby 50 | baby-carriage 51 | backspace 52 | backward 53 | bacon 54 | balance-scale 55 | balance-scale-left 56 | balance-scale-right 57 | ban 58 | band-aid 59 | barcode 60 | bars 61 | baseball-ball 62 | basketball-ball 63 | bath 64 | battery-empty 65 | battery-full 66 | battery-half 67 | battery-quarter 68 | battery-three-quarters 69 | bed 70 | beer 71 | bell 72 | bell-slash 73 | bezier-curve 74 | bible 75 | bicycle 76 | biking 77 | binoculars 78 | biohazard 79 | birthday-cake 80 | blender 81 | blender-phone 82 | blind 83 | blog 84 | bold 85 | bolt 86 | bomb 87 | bone 88 | bong 89 | book 90 | book-dead 91 | book-medical 92 | book-open 93 | book-reader 94 | bookmark 95 | border-all 96 | border-none 97 | border-style 98 | bowling-ball 99 | box 100 | box-open 101 | boxes 102 | braille 103 | brain 104 | bread-slice 105 | briefcase 106 | briefcase-medical 107 | broadcast-tower 108 | broom 109 | brush 110 | bug 111 | building 112 | bullhorn 113 | bullseye 114 | burn 115 | bus 116 | bus-alt 117 | business-time 118 | calculator 119 | calendar 120 | calendar-alt 121 | calendar-check 122 | calendar-day 123 | calendar-minus 124 | calendar-plus 125 | calendar-times 126 | calendar-week 127 | camera 128 | camera-retro 129 | campground 130 | candy-cane 131 | cannabis 132 | capsules 133 | car 134 | car-alt 135 | car-battery 136 | car-crash 137 | car-side 138 | caret-down 139 | caret-left 140 | caret-right 141 | caret-square-down 142 | caret-square-left 143 | caret-square-right 144 | caret-square-up 145 | caret-up 146 | carrot 147 | cart-arrow-down 148 | cart-plus 149 | cash-register 150 | cat 151 | certificate 152 | chair 153 | chalkboard 154 | chalkboard-teacher 155 | charging-station 156 | chart-area 157 | chart-bar 158 | chart-line 159 | chart-pie 160 | check 161 | check-circle 162 | check-double 163 | check-square 164 | cheese 165 | chess 166 | chess-bishop 167 | chess-board 168 | chess-king 169 | chess-knight 170 | chess-pawn 171 | chess-queen 172 | chess-rook 173 | chevron-circle-down 174 | chevron-circle-left 175 | chevron-circle-right 176 | chevron-circle-up 177 | chevron-down 178 | chevron-left 179 | chevron-right 180 | chevron-up 181 | child 182 | church 183 | circle 184 | circle-notch 185 | city 186 | clinic-medical 187 | clipboard 188 | clipboard-check 189 | clipboard-list 190 | clock 191 | clone 192 | closed-captioning 193 | cloud 194 | cloud-download-alt 195 | cloud-meatball 196 | cloud-moon 197 | cloud-moon-rain 198 | cloud-rain 199 | cloud-showers-heavy 200 | cloud-sun 201 | cloud-sun-rain 202 | cloud-upload-alt 203 | cocktail 204 | code 205 | code-branch 206 | coffee 207 | cog 208 | cogs 209 | coins 210 | columns 211 | comment 212 | comment-alt 213 | comment-dollar 214 | comment-dots 215 | comment-medical 216 | comment-slash 217 | comments 218 | comments-dollar 219 | compact-disc 220 | compass 221 | compress 222 | compress-arrows-alt 223 | concierge-bell 224 | cookie 225 | cookie-bite 226 | copy 227 | copyright 228 | couch 229 | credit-card 230 | crop 231 | crop-alt 232 | cross 233 | crosshairs 234 | crow 235 | crown 236 | crutch 237 | cube 238 | cubes 239 | cut 240 | database 241 | deaf 242 | democrat 243 | desktop 244 | dharmachakra 245 | diagnoses 246 | dice 247 | dice-d20 248 | dice-d6 249 | dice-five 250 | dice-four 251 | dice-one 252 | dice-six 253 | dice-three 254 | dice-two 255 | digital-tachograph 256 | directions 257 | divide 258 | dizzy 259 | dna 260 | dog 261 | dollar-sign 262 | dolly 263 | dolly-flatbed 264 | donate 265 | door-closed 266 | door-open 267 | dot-circle 268 | dove 269 | download 270 | drafting-compass 271 | dragon 272 | draw-polygon 273 | drum 274 | drum-steelpan 275 | drumstick-bite 276 | dumbbell 277 | dumpster 278 | dumpster-fire 279 | dungeon 280 | edit 281 | egg 282 | eject 283 | ellipsis-h 284 | ellipsis-v 285 | envelope 286 | envelope-open 287 | envelope-open-text 288 | envelope-square 289 | equals 290 | eraser 291 | ethernet 292 | euro-sign 293 | exchange-alt 294 | exclamation 295 | exclamation-circle 296 | exclamation-triangle 297 | expand 298 | expand-arrows-alt 299 | external-link-alt 300 | external-link-square-alt 301 | eye 302 | eye-dropper 303 | eye-slash 304 | fan 305 | fast-backward 306 | fast-forward 307 | fax 308 | feather 309 | feather-alt 310 | female 311 | fighter-jet 312 | file 313 | file-alt 314 | file-archive 315 | file-audio 316 | file-code 317 | file-contract 318 | file-csv 319 | file-download 320 | file-excel 321 | file-export 322 | file-image 323 | file-import 324 | file-invoice 325 | file-invoice-dollar 326 | file-medical 327 | file-medical-alt 328 | file-pdf 329 | file-powerpoint 330 | file-prescription 331 | file-signature 332 | file-upload 333 | file-video 334 | file-word 335 | fill 336 | fill-drip 337 | film 338 | filter 339 | fingerprint 340 | fire 341 | fire-alt 342 | fire-extinguisher 343 | first-aid 344 | fish 345 | fist-raised 346 | flag 347 | flag-checkered 348 | flag-usa 349 | flask 350 | flushed 351 | folder 352 | folder-minus 353 | folder-open 354 | folder-plus 355 | font 356 | football-ball 357 | forward 358 | frog 359 | frown 360 | frown-open 361 | funnel-dollar 362 | futbol 363 | gamepad 364 | gas-pump 365 | gavel 366 | gem 367 | genderless 368 | ghost 369 | gift 370 | gifts 371 | glass-cheers 372 | glass-martini 373 | glass-martini-alt 374 | glass-whiskey 375 | glasses 376 | globe 377 | globe-africa 378 | globe-americas 379 | globe-asia 380 | globe-europe 381 | golf-ball 382 | gopuram 383 | graduation-cap 384 | greater-than 385 | greater-than-equal 386 | grimace 387 | grin 388 | grin-alt 389 | grin-beam 390 | grin-beam-sweat 391 | grin-hearts 392 | grin-squint 393 | grin-squint-tears 394 | grin-stars 395 | grin-tears 396 | grin-tongue 397 | grin-tongue-squint 398 | grin-tongue-wink 399 | grin-wink 400 | grip-horizontal 401 | grip-lines 402 | grip-lines-vertical 403 | grip-vertical 404 | guitar 405 | h-square 406 | hamburger 407 | hammer 408 | hamsa 409 | hand-holding 410 | hand-holding-heart 411 | hand-holding-usd 412 | hand-lizard 413 | hand-middle-finger 414 | hand-paper 415 | hand-peace 416 | hand-point-down 417 | hand-point-left 418 | hand-point-right 419 | hand-point-up 420 | hand-pointer 421 | hand-rock 422 | hand-scissors 423 | hand-spock 424 | hands 425 | hands-helping 426 | handshake 427 | hanukiah 428 | hard-hat 429 | hashtag 430 | hat-cowboy 431 | hat-cowboy-side 432 | hat-wizard 433 | haykal 434 | hdd 435 | heading 436 | headphones 437 | headphones-alt 438 | headset 439 | heart 440 | heart-broken 441 | heartbeat 442 | helicopter 443 | highlighter 444 | hiking 445 | hippo 446 | history 447 | hockey-puck 448 | holly-berry 449 | home 450 | horse 451 | horse-head 452 | hospital 453 | hospital-alt 454 | hospital-symbol 455 | hot-tub 456 | hotdog 457 | hotel 458 | hourglass 459 | hourglass-end 460 | hourglass-half 461 | hourglass-start 462 | house-damage 463 | hryvnia 464 | i-cursor 465 | ice-cream 466 | icicles 467 | icons 468 | id-badge 469 | id-card 470 | id-card-alt 471 | igloo 472 | image 473 | images 474 | inbox 475 | indent 476 | industry 477 | infinity 478 | info 479 | info-circle 480 | italic 481 | jedi 482 | joint 483 | journal-whills 484 | kaaba 485 | key 486 | keyboard 487 | khanda 488 | kiss 489 | kiss-beam 490 | kiss-wink-heart 491 | kiwi-bird 492 | landmark 493 | language 494 | laptop 495 | laptop-code 496 | laptop-medical 497 | laugh 498 | laugh-beam 499 | laugh-squint 500 | laugh-wink 501 | layer-group 502 | leaf 503 | lemon 504 | less-than 505 | less-than-equal 506 | level-down-alt 507 | level-up-alt 508 | life-ring 509 | lightbulb 510 | link 511 | lira-sign 512 | list 513 | list-alt 514 | list-ol 515 | list-ul 516 | location-arrow 517 | lock 518 | lock-open 519 | long-arrow-alt-down 520 | long-arrow-alt-left 521 | long-arrow-alt-right 522 | long-arrow-alt-up 523 | low-vision 524 | luggage-cart 525 | magic 526 | magnet 527 | mail-bulk 528 | male 529 | map 530 | map-marked 531 | map-marked-alt 532 | map-marker 533 | map-marker-alt 534 | map-pin 535 | map-signs 536 | marker 537 | mars 538 | mars-double 539 | mars-stroke 540 | mars-stroke-h 541 | mars-stroke-v 542 | mask 543 | medal 544 | medkit 545 | meh 546 | meh-blank 547 | meh-rolling-eyes 548 | memory 549 | menorah 550 | mercury 551 | meteor 552 | microchip 553 | microphone 554 | microphone-alt 555 | microphone-alt-slash 556 | microphone-slash 557 | microscope 558 | minus 559 | minus-circle 560 | minus-square 561 | mitten 562 | mobile 563 | mobile-alt 564 | money-bill 565 | money-bill-alt 566 | money-bill-wave 567 | money-bill-wave-alt 568 | money-check 569 | money-check-alt 570 | monument 571 | moon 572 | mortar-pestle 573 | mosque 574 | motorcycle 575 | mountain 576 | mouse 577 | mouse-pointer 578 | mug-hot 579 | music 580 | network-wired 581 | neuter 582 | newspaper 583 | not-equal 584 | notes-medical 585 | object-group 586 | object-ungroup 587 | oil-can 588 | om 589 | otter 590 | outdent 591 | pager 592 | paint-brush 593 | paint-roller 594 | palette 595 | pallet 596 | paper-plane 597 | paperclip 598 | parachute-box 599 | paragraph 600 | parking 601 | passport 602 | pastafarianism 603 | paste 604 | pause 605 | pause-circle 606 | paw 607 | peace 608 | pen 609 | pen-alt 610 | pen-fancy 611 | pen-nib 612 | pen-square 613 | pencil-alt 614 | pencil-ruler 615 | people-carry 616 | pepper-hot 617 | percent 618 | percentage 619 | person-booth 620 | phone 621 | phone-alt 622 | phone-slash 623 | phone-square 624 | phone-square-alt 625 | phone-volume 626 | photo-video 627 | piggy-bank 628 | pills 629 | pizza-slice 630 | place-of-worship 631 | plane 632 | plane-arrival 633 | plane-departure 634 | play 635 | play-circle 636 | plug 637 | plus 638 | plus-circle 639 | plus-square 640 | podcast 641 | poll 642 | poll-h 643 | poo 644 | poo-storm 645 | poop 646 | portrait 647 | pound-sign 648 | power-off 649 | pray 650 | praying-hands 651 | prescription 652 | prescription-bottle 653 | prescription-bottle-alt 654 | print 655 | procedures 656 | project-diagram 657 | puzzle-piece 658 | qrcode 659 | question 660 | question-circle 661 | quidditch 662 | quote-left 663 | quote-right 664 | quran 665 | radiation 666 | radiation-alt 667 | rainbow 668 | random 669 | receipt 670 | record-vinyl 671 | recycle 672 | redo 673 | redo-alt 674 | registered 675 | remove-format 676 | reply 677 | reply-all 678 | republican 679 | restroom 680 | retweet 681 | ribbon 682 | ring 683 | road 684 | robot 685 | rocket 686 | route 687 | rss 688 | rss-square 689 | ruble-sign 690 | ruler 691 | ruler-combined 692 | ruler-horizontal 693 | ruler-vertical 694 | running 695 | rupee-sign 696 | sad-cry 697 | sad-tear 698 | satellite 699 | satellite-dish 700 | save 701 | school 702 | screwdriver 703 | scroll 704 | sd-card 705 | search 706 | search-dollar 707 | search-location 708 | search-minus 709 | search-plus 710 | seedling 711 | server 712 | shapes 713 | share 714 | share-alt 715 | share-alt-square 716 | share-square 717 | shekel-sign 718 | shield-alt 719 | ship 720 | shipping-fast 721 | shoe-prints 722 | shopping-bag 723 | shopping-basket 724 | shopping-cart 725 | shower 726 | shuttle-van 727 | sign 728 | sign-in-alt 729 | sign-language 730 | sign-out-alt 731 | signal 732 | signature 733 | sim-card 734 | sitemap 735 | skating 736 | skiing 737 | skiing-nordic 738 | skull 739 | skull-crossbones 740 | slash 741 | sleigh 742 | sliders-h 743 | smile 744 | smile-beam 745 | smile-wink 746 | smog 747 | smoking 748 | smoking-ban 749 | sms 750 | snowboarding 751 | snowflake 752 | snowman 753 | snowplow 754 | socks 755 | solar-panel 756 | sort 757 | sort-alpha-down 758 | sort-alpha-down-alt 759 | sort-alpha-up 760 | sort-alpha-up-alt 761 | sort-amount-down 762 | sort-amount-down-alt 763 | sort-amount-up 764 | sort-amount-up-alt 765 | sort-down 766 | sort-numeric-down 767 | sort-numeric-down-alt 768 | sort-numeric-up 769 | sort-numeric-up-alt 770 | sort-up 771 | spa 772 | space-shuttle 773 | spell-check 774 | spider 775 | spinner 776 | splotch 777 | spray-can 778 | square 779 | square-full 780 | square-root-alt 781 | stamp 782 | star 783 | star-and-crescent 784 | star-half 785 | star-half-alt 786 | star-of-david 787 | star-of-life 788 | step-backward 789 | step-forward 790 | stethoscope 791 | sticky-note 792 | stop 793 | stop-circle 794 | stopwatch 795 | store 796 | store-alt 797 | stream 798 | street-view 799 | strikethrough 800 | stroopwafel 801 | subscript 802 | subway 803 | suitcase 804 | suitcase-rolling 805 | sun 806 | superscript 807 | surprise 808 | swatchbook 809 | swimmer 810 | swimming-pool 811 | synagogue 812 | sync 813 | sync-alt 814 | syringe 815 | table 816 | table-tennis 817 | tablet 818 | tablet-alt 819 | tablets 820 | tachometer-alt 821 | tag 822 | tags 823 | tape 824 | tasks 825 | taxi 826 | teeth 827 | teeth-open 828 | temperature-high 829 | temperature-low 830 | tenge 831 | terminal 832 | text-height 833 | text-width 834 | th 835 | th-large 836 | th-list 837 | theater-masks 838 | thermometer 839 | thermometer-empty 840 | thermometer-full 841 | thermometer-half 842 | thermometer-quarter 843 | thermometer-three-quarters 844 | thumbs-down 845 | thumbs-up 846 | thumbtack 847 | ticket-alt 848 | times 849 | times-circle 850 | tint 851 | tint-slash 852 | tired 853 | toggle-off 854 | toggle-on 855 | toilet 856 | toilet-paper 857 | toolbox 858 | tools 859 | tooth 860 | torah 861 | torii-gate 862 | tractor 863 | trademark 864 | traffic-light 865 | train 866 | tram 867 | transgender 868 | transgender-alt 869 | trash 870 | trash-alt 871 | trash-restore 872 | trash-restore-alt 873 | tree 874 | trophy 875 | truck 876 | truck-loading 877 | truck-monster 878 | truck-moving 879 | truck-pickup 880 | tshirt 881 | tty 882 | tv 883 | umbrella 884 | umbrella-beach 885 | underline 886 | undo 887 | undo-alt 888 | universal-access 889 | university 890 | unlink 891 | unlock 892 | unlock-alt 893 | upload 894 | user 895 | user-alt 896 | user-alt-slash 897 | user-astronaut 898 | user-check 899 | user-circle 900 | user-clock 901 | user-cog 902 | user-edit 903 | user-friends 904 | user-graduate 905 | user-injured 906 | user-lock 907 | user-md 908 | user-minus 909 | user-ninja 910 | user-nurse 911 | user-plus 912 | user-secret 913 | user-shield 914 | user-slash 915 | user-tag 916 | user-tie 917 | user-times 918 | users 919 | users-cog 920 | utensil-spoon 921 | utensils 922 | vector-square 923 | venus 924 | venus-double 925 | venus-mars 926 | vial 927 | vials 928 | video 929 | video-slash 930 | vihara 931 | voicemail 932 | volleyball-ball 933 | volume-down 934 | volume-mute 935 | volume-off 936 | volume-up 937 | vote-yea 938 | vr-cardboard 939 | walking 940 | wallet 941 | warehouse 942 | water 943 | wave-square 944 | weight 945 | weight-hanging 946 | wheelchair 947 | wifi 948 | wind 949 | window-close 950 | window-maximize 951 | window-minimize 952 | window-restore`.split('\n') --------------------------------------------------------------------------------