前端页面添加上下Bar,路由简单配置
This commit is contained in:
parent
5845ed6c7b
commit
1d113e78ed
@ -1,5 +1,12 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: [
|
||||||
'@vue/cli-plugin-babel/preset'
|
'@vue/cli-plugin-babel/preset'
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
['import', {
|
||||||
|
libraryName: 'vant',
|
||||||
|
libraryDirectory: 'es',
|
||||||
|
style: true
|
||||||
|
}, 'vant']
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
551
na-frontend/package-lock.json
generated
551
na-frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,12 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"vue": "^2.6.14"
|
"element-ui": "^2.15.14",
|
||||||
|
"less-loader": "^12.3.0",
|
||||||
|
"vant": "^2.13.8",
|
||||||
|
"vue": "^2.6.14",
|
||||||
|
"vue-router": "^3.6.5",
|
||||||
|
"vuex": "^3.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.12.16",
|
"@babel/core": "^7.12.16",
|
||||||
@ -17,6 +22,8 @@
|
|||||||
"@vue/cli-plugin-babel": "~5.0.0",
|
"@vue/cli-plugin-babel": "~5.0.0",
|
||||||
"@vue/cli-plugin-eslint": "~5.0.0",
|
"@vue/cli-plugin-eslint": "~5.0.0",
|
||||||
"@vue/cli-service": "~5.0.0",
|
"@vue/cli-service": "~5.0.0",
|
||||||
|
"babel-plugin-component": "^1.1.1",
|
||||||
|
"babel-plugin-import": "^1.13.8",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-plugin-vue": "^8.0.3",
|
"eslint-plugin-vue": "^8.0.3",
|
||||||
"vue-template-compiler": "^2.6.14"
|
"vue-template-compiler": "^2.6.14"
|
||||||
|
@ -1,28 +1,118 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<img alt="Vue logo" src="./assets/logo.png">
|
<!-- 固定顶部导航栏 -->
|
||||||
<HelloWorld msg="Welcome to Your Vue.js App"/>
|
<NavBar class="nav-bar" />
|
||||||
|
|
||||||
|
<!-- 中间内容区:包裹路由视图,控制动画范围 -->
|
||||||
|
<div class="content-container">
|
||||||
|
<!-- 根据路由方向动态切换过渡类 -->
|
||||||
|
<transition :name="transitionName" mode="out-in">
|
||||||
|
<router-view></router-view>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 固定底部TabBar -->
|
||||||
|
<TabBar class="tab-bar" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import HelloWorld from './components/HelloWorld.vue'
|
import TabBar from './components/TabBar.vue';
|
||||||
|
import NavBar from './components/NavBar.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
HelloWorld
|
TabBar,
|
||||||
|
NavBar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style lang="less" scoped>
|
||||||
#app {
|
#app {
|
||||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
text-align: center;
|
background-color: #F8F8FF;
|
||||||
color: #2c3e50;
|
min-height: 100vh;
|
||||||
margin-top: 60px;
|
overflow: hidden;
|
||||||
|
min-width: 200px;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 固定顶部导航栏 */
|
||||||
|
.nav-bar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 100;
|
||||||
|
height: 45px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 固定底部TabBar */
|
||||||
|
.tab-bar {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 100;
|
||||||
|
height: 50px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 中间内容区:避开上下Bar的位置 */
|
||||||
|
.content-container {
|
||||||
|
position: relative;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding-top: 50px;
|
||||||
|
padding-bottom: 60px;
|
||||||
|
overflow: hidden;
|
||||||
|
/* 防止内容溢出 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 定义向左滑动动画(前进方向) */
|
||||||
|
.slide-left-enter-active,
|
||||||
|
.slide-left-leave-active {
|
||||||
|
transition: transform 0.5s ease;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-left-enter {
|
||||||
|
transform: translateX(100%);
|
||||||
|
/* 从右侧进入 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-left-leave-to {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
/* 向左离开 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 定义向右滑动动画(后退方向) */
|
||||||
|
.slide-right-enter-active,
|
||||||
|
.slide-right-leave-active {
|
||||||
|
transition: transform 0.5s ease;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-right-enter {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
/* 从左侧进入 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-right-leave-to {
|
||||||
|
transform: translateX(100%);
|
||||||
|
/* 向右离开 */
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,58 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="hello">
|
|
||||||
<h1>{{ msg }}</h1>
|
|
||||||
<p>
|
|
||||||
For a guide and recipes on how to configure / customize this project,<br>
|
|
||||||
check out the
|
|
||||||
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
|
|
||||||
</p>
|
|
||||||
<h3>Installed CLI Plugins</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
|
|
||||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
|
|
||||||
</ul>
|
|
||||||
<h3>Essential Links</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
|
|
||||||
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
|
|
||||||
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
|
|
||||||
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
|
|
||||||
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
|
|
||||||
</ul>
|
|
||||||
<h3>Ecosystem</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
|
|
||||||
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
|
|
||||||
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
|
|
||||||
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
|
|
||||||
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'HelloWorld',
|
|
||||||
props: {
|
|
||||||
msg: String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
||||||
<style scoped>
|
|
||||||
h3 {
|
|
||||||
margin: 40px 0 0;
|
|
||||||
}
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: #42b983;
|
|
||||||
}
|
|
||||||
</style>
|
|
28
na-frontend/src/components/NavBar.vue
Normal file
28
na-frontend/src/components/NavBar.vue
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<template>
|
||||||
|
<div class="nav-bar">
|
||||||
|
<van-nav-bar title="标题" left-text="返回" :placeholder="true" :safe-area-inset-top="true" z-index="99">
|
||||||
|
<template #right>
|
||||||
|
<van-icon name="search" size="18" />
|
||||||
|
</template>
|
||||||
|
</van-nav-bar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
components: {},
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
},
|
||||||
|
created() { },
|
||||||
|
mounted() { }
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
43
na-frontend/src/components/TabBar.vue
Normal file
43
na-frontend/src/components/TabBar.vue
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<div class="tab-bar">
|
||||||
|
<van-tabbar v-model="active" route :placeholder="true">
|
||||||
|
<van-tabbar-item replace to="/">
|
||||||
|
<span>主页</span>
|
||||||
|
<template #icon="props">
|
||||||
|
<img :src="props.active ? icon.active : icon.inactive" />
|
||||||
|
</template>
|
||||||
|
</van-tabbar-item>
|
||||||
|
<van-tabbar-item replace to="/portfolio" icon="search"><span>作品集</span>
|
||||||
|
<template #icon="props">
|
||||||
|
<img :src="props.active ? icon.active : icon.inactive" />
|
||||||
|
</template></van-tabbar-item>
|
||||||
|
<van-tabbar-item replace to="/sampleCollection" icon="setting-o"><span>样品集</span>
|
||||||
|
<template #icon="props">
|
||||||
|
<img :src="props.active ? icon.active : icon.inactive" />
|
||||||
|
</template></van-tabbar-item>
|
||||||
|
</van-tabbar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'TabBar',
|
||||||
|
components: {},
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
active: 0,
|
||||||
|
icon: {
|
||||||
|
active: 'https://img01.yzcdn.cn/vant/user-active.png',
|
||||||
|
inactive: 'https://img01.yzcdn.cn/vant/user-inactive.png',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {},
|
||||||
|
methods: {},
|
||||||
|
created() { },
|
||||||
|
mounted() { }
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped></style>
|
@ -1,8 +1,28 @@
|
|||||||
import Vue from 'vue'
|
import Vue from "vue";
|
||||||
import App from './App.vue'
|
import Vuex from 'vuex'
|
||||||
|
import App from "./App.vue";
|
||||||
|
import router from "./router";
|
||||||
|
import store from "./store";
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false;
|
||||||
|
import { Tabbar, TabbarItem } from "vant";
|
||||||
|
import { NavBar } from "vant";
|
||||||
|
import { Toast } from 'vant';
|
||||||
|
import { Popup } from 'vant';
|
||||||
|
import { Icon } from 'vant';
|
||||||
|
import { Button } from 'vant';
|
||||||
|
|
||||||
|
Vue.use(Button);
|
||||||
|
Vue.use(Icon);
|
||||||
|
Vue.use(Popup);
|
||||||
|
Vue.use(Toast);
|
||||||
|
Vue.use(NavBar);
|
||||||
|
Vue.use(Tabbar);
|
||||||
|
Vue.use(TabbarItem);
|
||||||
|
Vue.use(Vuex);
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
render: h => h(App),
|
store,
|
||||||
}).$mount('#app')
|
router,
|
||||||
|
render: (h) => h(App),
|
||||||
|
}).$mount("#app");
|
||||||
|
36
na-frontend/src/pages/HomePage.vue
Normal file
36
na-frontend/src/pages/HomePage.vue
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="homepage">
|
||||||
|
<h1>主页</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'HomePage',
|
||||||
|
components: {
|
||||||
|
|
||||||
|
},
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {},
|
||||||
|
methods: {},
|
||||||
|
created() {},
|
||||||
|
mounted() {}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.homepage {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
</style>
|
25
na-frontend/src/pages/PortfolioPage.vue
Normal file
25
na-frontend/src/pages/PortfolioPage.vue
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<div class="portfolio-page">
|
||||||
|
<h1>作品集</h1>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "PortfolioPage",
|
||||||
|
components: {},
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
created() { },
|
||||||
|
mounted() { }
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped></style>
|
25
na-frontend/src/pages/SampleCollectionPage.vue
Normal file
25
na-frontend/src/pages/SampleCollectionPage.vue
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<div class="sample-collection-page">
|
||||||
|
<h1>Sample Collection Page</h1>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'SampleCollectionPage',
|
||||||
|
components: {},
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
created() { },
|
||||||
|
mounted() { }
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped></style>
|
44
na-frontend/src/router/index.js
Normal file
44
na-frontend/src/router/index.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import Vue from "vue";
|
||||||
|
import VueRouter from "vue-router";
|
||||||
|
import HomePage from "@/pages/HomePage.vue";
|
||||||
|
import PortfolioPage from "@/pages/PortfolioPage.vue";
|
||||||
|
import SampleCollectionPage from "@/pages/SampleCollectionPage.vue";
|
||||||
|
import {store} from "@/store";
|
||||||
|
Vue.use(VueRouter);
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
name: "HomePage",
|
||||||
|
component: HomePage,
|
||||||
|
meta: { direction: "back" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/portfolio",
|
||||||
|
name: "PortfolioPage",
|
||||||
|
component: PortfolioPage,
|
||||||
|
meta: { direction: "forward" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/sampleCollection",
|
||||||
|
name: "SampleCollectionPage",
|
||||||
|
component: SampleCollectionPage,
|
||||||
|
meta: { direction: "forward" },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const router = new VueRouter({
|
||||||
|
mode: "history",
|
||||||
|
routes,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 全局前置守卫
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
// 避免重复记录相同路径(如刷新页面)
|
||||||
|
if (to.path !== from.path) {
|
||||||
|
store.dispatch("routeHistory/pushRoute", to);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
52
na-frontend/src/store/index.js
Normal file
52
na-frontend/src/store/index.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
const state = {
|
||||||
|
history: [], // 存储路由历史
|
||||||
|
};
|
||||||
|
|
||||||
|
const mutations = {
|
||||||
|
// 添加路由到历史记录
|
||||||
|
PUSH_ROUTE(state, route) {
|
||||||
|
state.history.push(route);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 重置历史记录
|
||||||
|
RESET_HISTORY(state) {
|
||||||
|
state.history = [];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const actions = {
|
||||||
|
pushRoute({ commit }, route) {
|
||||||
|
commit("PUSH_ROUTE", route);
|
||||||
|
},
|
||||||
|
|
||||||
|
resetHistory({ commit }) {
|
||||||
|
commit("RESET_HISTORY");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const getters = {
|
||||||
|
// 判断当前是否为后退操作
|
||||||
|
isBack(state) {
|
||||||
|
if (state.history.length < 2) return false;
|
||||||
|
|
||||||
|
const current = state.history[state.history.length - 1];
|
||||||
|
const previous = state.history[state.history.length - 2];
|
||||||
|
|
||||||
|
// 通过比较路径判断是否为后退
|
||||||
|
return previous.path === current.path;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取历史记录长度
|
||||||
|
historyLength(state) {
|
||||||
|
return state.history.length;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
namespaced: true, // 使用命名空间
|
||||||
|
state,
|
||||||
|
mutations,
|
||||||
|
actions,
|
||||||
|
getters,
|
||||||
|
};
|
@ -1,4 +1,10 @@
|
|||||||
const { defineConfig } = require('@vue/cli-service')
|
const { defineConfig } = require('@vue/cli-service')
|
||||||
module.exports = defineConfig({
|
module.exports = defineConfig({
|
||||||
transpileDependencies: true
|
transpileDependencies: true,
|
||||||
|
devServer: {
|
||||||
|
host: 'localhost',
|
||||||
|
port: 8080,
|
||||||
|
historyApiFallback: true,
|
||||||
|
allowedHosts: "all"
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user