前端页面添加上下Bar,路由简单配置
This commit is contained in:
parent
5845ed6c7b
commit
1d113e78ed
@ -1,5 +1,12 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@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": {
|
||||
"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": {
|
||||
"@babel/core": "^7.12.16",
|
||||
@ -17,6 +22,8 @@
|
||||
"@vue/cli-plugin-babel": "~5.0.0",
|
||||
"@vue/cli-plugin-eslint": "~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-plugin-vue": "^8.0.3",
|
||||
"vue-template-compiler": "^2.6.14"
|
||||
|
@ -1,28 +1,118 @@
|
||||
<template>
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HelloWorld from './components/HelloWorld.vue'
|
||||
import TabBar from './components/TabBar.vue';
|
||||
import NavBar from './components/NavBar.vue';
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
HelloWorld
|
||||
TabBar,
|
||||
NavBar
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style lang="less" scoped>
|
||||
#app {
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
margin-top: 60px;
|
||||
background-color: #F8F8FF;
|
||||
min-height: 100vh;
|
||||
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 App from './App.vue'
|
||||
import Vue from "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({
|
||||
render: h => h(App),
|
||||
}).$mount('#app')
|
||||
store,
|
||||
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')
|
||||
module.exports = defineConfig({
|
||||
transpileDependencies: true
|
||||
transpileDependencies: true,
|
||||
devServer: {
|
||||
host: 'localhost',
|
||||
port: 8080,
|
||||
historyApiFallback: true,
|
||||
allowedHosts: "all"
|
||||
}
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user