Commit 8a8ea2d2 by 姜雷

添加路由页签

parent c8da1460
......@@ -32,4 +32,3 @@ export default {
}
};
</script>
import Vue from 'vue';
import App from './App.vue';
import route, { routerMap } from './route';
import store from './store/index';
import rymUi from '../src/index';
import 'normalize.css/normalize.css';
......@@ -8,7 +9,10 @@ Vue.use(rymUi);
Vue.config.productionTip = false;
window[Symbol.for('vueAppStore')] = store;
new Vue({
render: h => <App route={routerMap} />,
router: route,
store,
}).$mount('#app');
import Vue from 'vue';
import Vuex from 'vuex';
import createLogger from 'vuex/dist/logger';
import app from './modules/app';
Vue.use(Vuex);
const debug = process.env.NODE_ENV !== 'production';
const store = new Vuex.Store({
strict: debug,
modules: {
app,
},
plugins: debug ? [createLogger()] : [],
});
export default store;
const FETCH_START = 'FETCH_START';
const FETCH_DONE = 'FETCH_DONE';
const state = () => ({
loading: true,
});
const getters = {
loading: state => state.loading,
};
const actions = {
fetchStart({ commit }) {
commit(FETCH_START);
},
fetchDone({ commit }) {
commit(FETCH_DONE);
},
};
const mutations = {
[FETCH_START](state) {
state.loading = true;
},
[FETCH_DONE](state) {
state.loading = false;
},
};
export default {
state,
getters,
actions,
mutations,
};
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "rym-element-ui",
"version": "0.1.4",
"version": "0.1.8",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......@@ -11490,6 +11490,11 @@
"integrity": "sha512-x3LV3wdmmERhVCYy3quqA57NJW7F3i6faas++pJQWtknWT+n7k30F4TVdHvCLn48peTJFRvCpxs3UuFPqgeELg==",
"dev": true
},
"vuex": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.0.1.tgz",
"integrity": "sha512-wLoqz0B7DSZtgbWL1ShIBBCjv22GV5U+vcBFox658g6V0s4wZV9P4YjCNyoHSyIBpj1f29JBoNQIqD82cR4O3w=="
},
"watchpack": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz",
......
{
"name": "rym-element-ui",
"version": "0.1.8",
"version": "0.1.9",
"description": "任意门组件库",
"main": "lib/rymUi.common.js",
"scripts": {
......@@ -23,7 +23,8 @@
"normalize.css": "^8.0.1",
"popmotion": "^8.5.5",
"vue": "^2.5.21",
"vue-router": "^3.0.2"
"vue-router": "^3.0.2",
"vuex": "^3.0.1"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.2.0",
......
......@@ -8,11 +8,13 @@
/>
</div>
<h1 class="com-title">后台管理系统</h1>
<slot name="title"></slot>
</div>
<div class="body-container">
<slot name="nav"></slot>
<div class="main-container">
<tags-views></tags-views>
<slot></slot>
</div>
</div>
......@@ -20,9 +22,13 @@
</template>
<script>
import TagsViews from "../TagsViews/TagsView";
export default {
name: "app-layout",
components: {
TagsViews
},
computed: {
sidebar() {
return this.$store.state.app.sidebar;
......
const ADD_VISITED_VIEWS = 'ADD_VISITED_VIEWS';
const DEL_VISITED_VIEWS = 'DEL_VISITED_VIEWS';
const DEL_OTHERS_VIEWS = 'DEL_OTHERS_VIEWS';
const DEL_ALL_VIEWS = 'DEL_ALL_VIEWS';
const state = {
visitedViews: [],
cachedViews: [],
};
const getters = {
visitedViews: state => state.visitedViews,
cachedViews: state => state.cachedViews,
};
const actions = {
addVisitedViews({ commit }, view) {
commit(ADD_VISITED_VIEWS, view);
},
delVisitedViews({ commit, state }, view) {
return new Promise(resolve => {
commit(DEL_VISITED_VIEWS, view);
resolve([...state.visitedViews]);
});
},
delOthersViews({ commit, state }, view) {
return new Promise(resolve => {
commit(DEL_OTHERS_VIEWS, view);
resolve([...state.visitedViews]);
});
},
delAllViews({ commit, state }) {
return new Promise(resolve => {
commit(DEL_ALL_VIEWS);
resolve([...state.visitedViews]);
});
},
};
const mutations = {
[ADD_VISITED_VIEWS]: (state, view) => {
if (state.visitedViews.some(v => v.path === view.path)) return;
state.visitedViews.push({
name: view.name,
path: view.path,
title: view.meta.title || 'no-name',
store: view.meta.store || null,
});
if (!view.meta.noCache) {
state.cachedViews.push(view.name);
}
},
[DEL_VISITED_VIEWS]: (state, view) => {
for (const [i, v] of state.visitedViews.entries()) {
if (v.path === view.path) {
state.visitedViews.splice(i, 1);
break;
}
}
for (const i of state.cachedViews) {
if (i === view.name) {
const index = state.cachedViews.indexOf(i);
state.cachedViews.splice(index, 1);
break;
}
}
},
[DEL_OTHERS_VIEWS]: (state, view) => {
for (const [i, v] of state.visitedViews.entries()) {
if (v.path === view.path) {
state.visitedViews = state.visitedViews.slice(i, i + 1);
break;
}
}
for (const i of state.cachedViews) {
if (i === view.name) {
const index = state.cachedViews.indexOf(i);
state.cachedViews = state.cachedViews.slice(index, i + 1);
break;
}
}
},
[DEL_ALL_VIEWS]: state => {
state.visitedViews = [];
state.cachedViews = [];
},
};
export default {
state,
getters,
actions,
mutations,
};
<template>
<div class="tags-view-container">
<scroll-pane
class="tags-view-wrapper"
ref="scrollPane"
>
<router-link
ref="tag"
class="tags-view-item"
:class="isActive(tag) ? 'active' : ''"
v-for="tag in Array.from(visitedViews)"
:to="tag.path"
:key="tag.path"
>
<span class="tags-text"> {{ tag.title }} </span>
<span
class="el-icon-close"
@click.prevent.stop="closeSelectedTag(tag)"
></span>
</router-link>
</scroll-pane>
<!-- <ul
class="contextmenu"
v-show="visible"
:style="{ left: left + 'px', top: top + 'px' }"
>
<li @click="closeSelectedTag(selectedTag)">关闭</li>
<li @click="closeOthersTags">关闭其余所有标签</li>
<li @click="closeAllTags">关闭所有标签</li>
</ul> -->
</div>
</template>
<script>
import ScrollPane from "../ScrollPane";
import { mapGetters, mapActions } from "vuex";
import store from "./store.js";
export default {
components: { ScrollPane },
created() {
store.install();
},
data() {
return {
visible: false,
top: 0,
left: 0,
selectedTag: {}
};
},
computed: {
...mapGetters(["visitedViews"])
},
watch: {
$route() {
this.addViewTags();
this.moveToCurrentTag();
}
},
mounted() {
this.addViewTags();
},
methods: {
...mapActions(["addVisitedViews", "delVisitedViews"]),
generateRoute() {
if (this.$route.name) {
return this.$route;
}
return false;
},
isActive(route) {
return route.path === this.$route.path || route.name === this.$route.name;
},
addViewTags() {
const route = this.generateRoute();
if (!route) {
return false;
}
if (route.meta.store) route.meta.store.install();
this.addVisitedViews(route);
},
moveToCurrentTag() {
const tags = this.$refs.tag;
this.$nextTick(() => {
for (const tag of tags) {
if (tag.to === this.$route.path) {
this.$refs.scrollPane.moveToTarget(tag.$el);
break;
}
}
});
},
closeSelectedTag(view) {
if (view.store) view.store.uninstall();
this.delVisitedViews(view).then(views => {
if (this.isActive(view)) {
const latestView = views.slice(-1)[0];
if (latestView) {
this.$router.push(latestView.path);
} else {
this.$router.push("/");
}
}
});
}
}
};
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.tags-view-container {
overflow: hidden;
background-color: #fff;
box-shadow: 0 2px 5px #999;
.tags-view-wrapper {
height: 30px;
overflow: inherit;
// border-bottom: 1px solid #d8dce5;
// box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
.tags-view-item {
display: inline-block;
box-sizing: border-box;
position: relative;
min-width: 80px;
height: 30px;
line-height: 30px;
color: #333;
background: #fff;
padding: 0 15px;
font-size: 12px;
text-align: center;
transition: all 0.28s;
&.active {
color: #1459fc;
border-bottom: 2px solid #1459fc;
border-color: #1459fc;
// &::before {
// content: "";
// background: #fff;
// display: inline-block;
// width: 8px;
// height: 8px;
// border-radius: 50%;
// position: relative;
// margin-right: 2px;
// }
}
}
.tags-text {
display: inline-block;
}
}
.contextmenu {
margin: 0;
background: #fff;
z-index: 2;
position: absolute;
list-style-type: none;
padding: 5px 0;
border-radius: 4px;
font-size: 12px;
font-weight: 400;
color: #333;
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
li {
margin: 0;
padding: 7px 16px;
cursor: pointer;
&:hover {
background: #eee;
}
}
}
}
</style>
<style rel="stylesheet/scss" lang="scss">
//reset element css of el-icon-close
.tags-view-wrapper {
.tags-view-item {
.el-icon-close {
position: absolute;
right: 3px;
top: 9px;
width: 12px;
height: 12px;
vertical-align: 2px;
border-radius: 50%;
text-align: center;
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
transform-origin: 100% 50%;
&:before {
transform: scale(0.6);
display: inline-block;
vertical-align: 2px;
}
&:hover {
background-color: #b4bccc;
color: #fff;
}
}
}
}
</style>
import TagsViewStore from './TagsView.js';
export default {
install() {
const store = window[Symbol.for('vueAppStore')];
if (!store.state.app) {
store.registerModule(['app'], {
namespaced: true,
});
}
if (!store.state.app.tagsView) {
store.registerModule(['app', 'tagsView'], TagsViewStore);
}
},
uninstall() {
const store = window.$store;
store.unregisterModule(['app', 'tagsView']);
},
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment