调整 & 优化

调整样式、调整页面结构、优化移动端显示效果
This commit is contained in:
2021-02-10 01:33:23 +08:00
parent 8ce492cee8
commit f4deeeafd5
3 changed files with 308 additions and 81 deletions

View File

@@ -4,25 +4,138 @@
<!-- Header --> <!-- Header -->
<el-header class="main-header shadow-1"> <el-header class="main-header shadow-1">
<!-- LOGO --> <!-- LOGO -->
<el-avatar class="logo" shape="square" size="small" src="./favicon.ico"></el-avatar> <el-avatar class="logo" shape="square" size="small" src="./favicon.ico"></el-avatar>
<!-- 菜单 --> <!-- 菜单 -->
<el-menu class="menu" default-active="home" mode="horizontal"> <el-menu class="menu" :default-active="headerDefaultActive" mode="horizontal" router>
<el-menu-item index="title" class="title" disabled>Frost 网址导航</el-menu-item>
<el-menu-item index="home">主页</el-menu-item> <!-- 标题 -->
<el-menu-item index="tools" disabled>小工具</el-menu-item> <el-menu-item v-show="config.storage.showSiteTitle"
<el-menu-item index="settings" disabled>设置</el-menu-item> index="title" class="title" disabled
>Frost 网址导航</el-menu-item>
<!-- 菜单项 -->
<el-menu-item v-for="item in headerMenuItems" :key="item.id"
class="item-normal" :index="item.id" :route="{ name: item.routeName }"
>{{ item.label }}</el-menu-item>
<!-- 切换下拉菜单 -->
<el-menu-item class="item-dropdown" @click="showHeaderDropdown = !showHeaderDropdown">
<i class="el-icon-s-fold"></i>
</el-menu-item>
</el-menu> </el-menu>
</el-header> </el-header>
<!-- 下拉菜单 -->
<el-menu :class="['header-dropdown', 'shadow-2', { show: showHeaderDropdown }]"
:default-active="headerDefaultActive" router
>
<!-- 菜单项 -->
<el-menu-item v-for="item in headerMenuItems" :key="item.id"
class="item-normal" :index="item.id" :route="{ name: item.routeName }"
>{{ item.label }}</el-menu-item>
</el-menu>
<!-- Container --> <!-- Container -->
<keep-alive>
<router-view class="main-container" /> <router-view class="main-container" />
</keep-alive>
</el-container> </el-container>
</div> </div>
</template> </template>
<script>
export default {
name: 'App',
data() {
return {
config: this.$root.config,
debounce: {
saveConfig: null,
updateConfig: null
},
// Header 菜单项
headerMenuItems: [
{
id: 'home',
label: '主页',
routeName: 'Home'
},
{
id: 'tools',
label: '小工具',
routeName: 'Tools'
},
{
id: 'settings',
label: '设置',
routeName: 'Settings'
}
],
// 显示下拉菜单
showHeaderDropdown: false
}
},
computed: {
// Header 默认激活的菜单项
headerDefaultActive() {
var routeName = this.$route.name;
var item = '';
if (routeName) {
item = routeName.toLowerCase();
}
return item;
}
},
watch: {
'$route.name': {
handler() {
// 切换路由时隐藏下拉菜单
this.showHeaderDropdown = false;
}
},
'config.storage': {
handler(obj) {
clearTimeout(this.debounce.saveConfig);
this.debounce.saveConfig = setTimeout(() => {
localStorage.setItem('config', JSON.stringify(obj));
}, 2000);
},
deep: true
},
'config.storage.fontSize': {
handler(value) {
clearTimeout(this.debounce.updateConfig);
this.debounce.updateConfig = setTimeout(() => {
// 改变字体大小
document.documentElement.style.fontSize = value + 'px';
}, 1000);
}
}
},
mounted() {
var configStr = localStorage.getItem('config');
var configObj = {};
if (configStr != null) {
configObj = JSON.parse(configStr);
Object.assign(this.config.storage, configObj);
}
}
}
</script>
<style lang="less"> <style lang="less">
.main-header { .main-header {
display: flex; display: flex;
@@ -31,11 +144,48 @@
height: @headerHeight !important; height: @headerHeight !important;
background-color: #FFF; background-color: #FFF;
@media screen and (min-width: 30rem) {
.menu .item-dropdown {
display: none;
}
}
@media screen and (max-width: 30rem) {
.logo {
display: none;
}
.menu { .menu {
.item-normal {
display: none;
}
.item-dropdown {
position: absolute;
right: 0;
margin: 0;
padding: 0;
line-height: 2.2rem;
i {
font-size: 2em;
}
}
}
}
.logo {
flex-shrink: 0;
margin-right: 1rem;
}
.menu {
flex-grow: 1;
height: 2.5rem; height: 2.5rem;
border: none !important; border: none !important;
> li { > li {
padding: 0 1rem;
height: 100%; height: 100%;
line-height: 2.5rem; line-height: 2.5rem;
@@ -46,6 +196,7 @@
} }
.title { .title {
padding-left: 0;
font-size: 1.2rem; font-size: 1.2rem;
color: @colorPrimary; color: @colorPrimary;
opacity: 1; opacity: 1;
@@ -54,6 +205,21 @@
} }
} }
.header-dropdown {
position: absolute !important;
z-index: 150;
top: @headerHeight;
left: 0;
width: 100%;
overflow: hidden;
transform: translateY(-100%);
transition: transform @transitionTime;
&.show {
transform: translateY(0);
}
}
.main-container { .main-container {
height: calc(100vh - @headerHeight); height: calc(100vh - @headerHeight);
} }

View File

@@ -8,11 +8,13 @@
@colorSecondary: #67C23A; @colorSecondary: #67C23A;
@colorWhite: #F9F9F9; @colorWhite: #F9F9F9;
@transitionTime: .25s;
// 滚动条 // 滚动条
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 0.5rem; width: .5rem;
height: 0.5rem; height: .5rem;
} }
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
@@ -30,6 +32,10 @@
// 标签 // 标签
html {
transition: font-size @transitionTime;
}
body { body {
user-select: none; user-select: none;
overflow: hidden; overflow: hidden;
@@ -50,21 +56,42 @@ body {
.limitLine(1); .limitLine(1);
} }
// 背景居中
.bgCenter() {
background-position: center;
background-repeat: no-repeat;
}
.bg-center-contain {
.bgCenter();
background-size: contain;
}
.bg-center-cover {
.bgCenter();
background-size: cover;
}
// 阴影 // 阴影
.shadow-1 { .shadow-1 {
box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.1); box-shadow: 0 0 .5rem rgba(0, 0, 0, .1);
} }
.shadow-2 { .shadow-2 {
box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05); box-shadow: 0 .2rem .5rem rgba(0, 0, 0, .05);
}
.shadow-3 {
box-shadow: 0 .5rem 1rem -0.4rem rgba(0, 0, 0, .12);
} }
// 载入中(链接列表) // 载入中(链接列表)
.loading-link { .loading-link {
background-color: rgba(255, 255, 255, 0.5) !important; background-color: rgba(255, 255, 255, .5) !important;
backdrop-filter: blur(0.2rem); backdrop-filter: blur(.2rem);
.el-icon-loading { .el-icon-loading {
font-size: 2rem !important; font-size: 2rem !important;

View File

@@ -3,7 +3,7 @@
<!-- 侧边栏 --> <!-- 侧边栏 -->
<el-aside class="home-aside"> <el-aside class="home-aside">
<el-menu class="side-nav" default-active="search" @select="changeCategory"> <el-menu class="side-nav" default-active="search" :collapse="config.sideMenuCollapse" @select="changeCategory">
<!-- 搜索引擎 --> <!-- 搜索引擎 -->
<el-menu-item index="search"> <el-menu-item index="search">
@@ -18,7 +18,7 @@
</el-menu-item> </el-menu-item>
<!-- 分类 --> <!-- 分类 -->
<el-menu-item v-for="(item, itemIndex) in navLinks" :key="'list-' + itemIndex" :index="itemIndex.toString()"> <el-menu-item v-for="(item, itemIndex) in navLinks.list" :key="'list-' + itemIndex" :index="itemIndex.toString()">
<i class="el-icon-link"></i> <i class="el-icon-link"></i>
<span slot="title">{{ item.title }}</span> <span slot="title">{{ item.title }}</span>
</el-menu-item> </el-menu-item>
@@ -28,12 +28,13 @@
<!-- 内容 --> <!-- 内容 -->
<el-main class="home-content"> <el-main class="home-content">
<div class="wrapper">
<!-- 搜索引擎 --> <!-- 搜索引擎 -->
<div v-show="show.searchEngine" class="search-engine"> <div v-show="show.searchEngine" class="search-engine">
<!-- 搜索栏 --> <!-- 搜索栏 -->
<div class="search-bar shadow-2"> <div class="search-bar shadow-3">
<!-- 输入 --> <!-- 输入 -->
<input v-model="searchEngine.keyword" class="input" type="text" <input v-model="searchEngine.keyword" class="input" type="text"
@@ -55,12 +56,13 @@
</div> </div>
<!-- 选择搜索引擎 --> <!-- 选择搜索引擎 -->
<el-radio-group v-model="searchEngine.type" class="search-type" size="small"> <el-radio-group v-model="config.searchEngine" class="search-type" size="small">
<!-- 自动生成 --> <!-- 自动生成 -->
<el-radio v-for="item in searchEngine.types" :key="item.name" <el-radio v-for="item in searchEngine.types" :key="item.name"
:label="item.name" class="shadow-2" :label="item.name" class="shadow-2"
> >
<Icon :path="item.icon || 'website/default.svg'" size="1.2em" />
<i class="name">{{ item.name }}</i> <i class="name">{{ item.name }}</i>
<i class="desc">{{ item.desc }}</i> <i class="desc">{{ item.desc }}</i>
</el-radio> </el-radio>
@@ -87,26 +89,34 @@
<el-tree v-show="show.linkTree" ref="linkTree" class="link-tree shadow-2" <el-tree v-show="show.linkTree" ref="linkTree" class="link-tree shadow-2"
:data="currentLinks" node-key="id" empty-text="" :data="currentLinks" node-key="id" empty-text=""
:props="{ label: 'title', children: 'sub' }" :filter-node-method="searchLink" :props="{ label: 'title', children: 'sub' }" :filter-node-method="searchLink"
:default-expand-all="false" :expand-on-click-node="false" :default-expand-all="false" :expand-on-click-node="true"
> >
<div slot-scope="{ node, data }" class="link-item" :title="data.update" <div slot-scope="{ node, data }" class="link-item" :title="data.update"
@click="openLink(data.link, data.showOnly)" @click="openLink(data.link, data.showOnly)"
> >
<span class="title limit-line-1">{{ node.label }}</span> <span class="title">{{ node.label }}</span>
<span class="link limit-line-1">{{ data.link }}</span> <span class="link">{{ data.link }}</span>
</div> </div>
</el-tree> </el-tree>
</div>
</el-main> </el-main>
</el-container> </el-container>
</template> </template>
<script> <script>
import Icon from '@/components/Icon.vue';
export default { export default {
name: 'Home', name: 'Home',
components: {
Icon
},
data() { data() {
return { return {
config: this.$root.config.storage,
utils: this.$root.utils,
// 显示的内容 // 显示的内容
show: { show: {
searchEngine: true, searchEngine: true,
@@ -116,10 +126,9 @@ export default {
// 搜索引擎 // 搜索引擎
searchEngine: { searchEngine: {
keyword: '', keyword: '',
type: this.$root.config.searchEngine.default, types: this.$root.config.searchEngines
types: this.$root.config.searchEngine.list
}, },
// 所有链接 // 导航链接
navLinks: this.$root.navLinks, navLinks: this.$root.navLinks,
// 当前显示的链接 // 当前显示的链接
currentLinks: [], currentLinks: [],
@@ -159,12 +168,12 @@ export default {
this.show.linkSearch = false; this.show.linkSearch = false;
this.show.linkTree = false; this.show.linkTree = false;
} else if (index == 'all') { } else if (index == 'all') {
this.currentLinks = this.navLinks; this.currentLinks = this.navLinks.list;
this.show.searchEngine = false; this.show.searchEngine = false;
this.show.linkSearch = true; this.show.linkSearch = true;
this.show.linkTree = true; this.show.linkTree = true;
} else { } else {
this.currentLinks = this.navLinks[Number(index)].sub; this.currentLinks = this.navLinks.list[Number(index)].sub;
this.show.searchEngine = false; this.show.searchEngine = false;
this.show.linkSearch = true; this.show.linkSearch = true;
this.show.linkTree = true; this.show.linkTree = true;
@@ -240,8 +249,11 @@ export default {
return result; return result;
} }
}, },
// beforeRouteEnter(from, to, next) { beforeRouteEnter(to, from, next) {
// }, next(vm => {
vm.utils.changeTitle();
});
}
} }
</script> </script>
@@ -257,10 +269,18 @@ export default {
} }
.home-content { .home-content {
display: flex;
flex-direction: column;
align-items: center;
position: relative; position: relative;
padding: 1rem; padding: 1rem;
background-color: @colorWhite; background-color: @colorWhite;
.wrapper {
width: 100%;
max-width: 60rem;
}
/deep/ .search-engine { /deep/ .search-engine {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -274,6 +294,7 @@ export default {
top: 0.5rem; top: 0.5rem;
z-index: 100; z-index: 100;
width: 100%; width: 100%;
min-width: 16rem;
max-width: 40rem; max-width: 40rem;
height: 2.8rem; height: 2.8rem;
border-radius: 0.25rem; border-radius: 0.25rem;
@@ -283,6 +304,7 @@ export default {
.input { .input {
flex-grow: 1; flex-grow: 1;
padding-left: 1rem; padding-left: 1rem;
width: 0;
height: 100%; height: 100%;
outline: none; outline: none;
} }
@@ -302,7 +324,7 @@ export default {
.btn-clear { .btn-clear {
width: 2rem; width: 2rem;
opacity: 0.5; opacity: 0.5;
transition: opacity 0.25s; transition: opacity @transitionTime;
&:hover { &:hover {
opacity: 1; opacity: 1;
@@ -311,7 +333,7 @@ export default {
.btn-search { .btn-search {
color: @colorPrimary; color: @colorPrimary;
transition: background 0.25s, color 0.25s; transition: background @transitionTime, color @transitionTime;
&:hover { &:hover {
background-color: @colorPrimary; background-color: @colorPrimary;
@@ -333,11 +355,13 @@ export default {
margin-top: 0; margin-top: 0;
padding: 1em; padding: 1em;
width: 45%; width: 45%;
min-width: 16em; min-width: 18em;
border-bottom: solid 0.15rem transparent;
border-radius: 0.25em; border-radius: 0.25em;
background-color: #FFF; background-color: #FFF;
text-align: left; text-align: left;
font-weight: normal; font-weight: normal;
transition: border @transitionTime;
// 隐藏占位元素 // 隐藏占位元素
&:last-child { &:last-child {
@@ -348,6 +372,10 @@ export default {
&:last-child:nth-child(odd) { &:last-child:nth-child(odd) {
display: none; display: none;
} }
&.is-checked {
border-bottom-color: @colorPrimary;
}
} }
.el-radio__input { .el-radio__input {
@@ -356,11 +384,17 @@ export default {
.el-radio__label { .el-radio__label {
padding: 0; padding: 0;
transition: color @transitionTime;
i { i {
vertical-align: middle;
font-style: normal; font-style: normal;
} }
.fn-icon {
margin-right: 0.4em;
}
.desc { .desc {
margin-left: 0.5em; margin-left: 0.5em;
font-size: 0.8em; font-size: 0.8em;