├── .env
├── .env.prod
├── .env.test
├── .gitignore
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── public
├── favicon.ico
└── index.html
├── src
├── App.vue
├── api
│ ├── api.js
│ └── request.js
├── assets
│ ├── css
│ │ ├── normalize.css
│ │ └── public.css
│ ├── icon
│ │ ├── demo.css
│ │ ├── demo_index.html
│ │ ├── iconfont.css
│ │ ├── iconfont.eot
│ │ ├── iconfont.js
│ │ ├── iconfont.svg
│ │ ├── iconfont.ttf
│ │ ├── iconfont.woff
│ │ └── iconfont.woff2
│ ├── img
│ │ └── tou.jpg
│ ├── js
│ │ └── common.js
│ ├── logo.png
│ └── scss
│ │ └── global.scss
├── components
│ ├── TreeTable
│ │ ├── eval.js
│ │ ├── index.vue
│ │ └── readme.md
│ └── showAside.vue
├── element-variables.scss
├── main.js
├── plugins
│ └── element.js
├── router
│ └── router.js
├── store
│ ├── actions.js
│ ├── getters.js
│ ├── mutations.js
│ ├── state.js
│ └── store.js
└── views
│ ├── charts
│ └── cricle.vue
│ ├── component
│ ├── countTo.vue
│ ├── customEval.js
│ ├── editor.vue
│ ├── tree.vue
│ ├── treeSelect.vue
│ └── treeTable.vue
│ ├── draggable
│ ├── draglist.vue
│ └── dragtable.vue
│ ├── home
│ └── index.vue
│ ├── icons
│ └── index.vue
│ ├── layout
│ ├── Layout.vue
│ └── components
│ │ ├── Aside.vue
│ │ ├── Header.vue
│ │ ├── Main.vue
│ │ └── Tags.vue
│ └── login
│ └── index.vue
└── vue.config.js
/.env:
--------------------------------------------------------------------------------
1 | NODE_ENV="development"
2 | BASE_URL="http://localhost:3000/"
--------------------------------------------------------------------------------
/.env.prod:
--------------------------------------------------------------------------------
1 | NODE_ENV="production"
2 | BASE_URL="https://www.jubao56.com/"
--------------------------------------------------------------------------------
/.env.test:
--------------------------------------------------------------------------------
1 | NODE_ENV="test"
2 | BASE_URL="http://localhost:3000/"
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw*
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | **由于最近公司要开发一个后台管理系统,查阅了很多vue框架,本人觉得element简洁,方便,于是选择它作为我们的首选框架,并分享给大家,如果您觉得有需要改进的地方可以提出来一起探讨,[掘金](https://juejin.im/post/5caab6f0f265da24c1118d90)。本文篇幅比较长,希望同学们可以耐心的读下去,如有不懂可以下方留言**
3 |
4 | # 一、目录
5 | | 目录 |
6 | | -------------------- |
7 | | 1.目录 |
8 | | 2.初始化项目 |
9 | | 3.文件目录介绍与整理 |
10 | | 4.开发环境与线上环境配置 |
11 | | 5.vue.config.js配置 |
12 | | 6.ElementUI引入 |
13 | | 7.vue-router路由介绍 |
14 | | 8.axios引入并封装 |
15 | | 9.vuex引入 |
16 | | 10.首页布局介绍 |
17 | | 11.结语 |
18 |
19 | # 二、初始化项目
20 | 首先全局安装vue脚手架,当前是第三版本vue-cli3.x,这里是用的npm包管理工具来安装的,如果你的网不是很好的话可以先安装淘宝镜像 `npm install -g cnpm -registry=https://registry.npm.taobao.org`,然后通过cnpm来安装
21 | ```vue
22 | cnpm install -g @vue/cli or npm install -g @vue/cli
23 | ```
24 | 安装完成后,你还可以用这个命令来检查其版本是否正确 (3.x):
25 | ```vue
26 | vue --version
27 | ```
28 | 安装脚手架后开始创建我们的项目
29 | ```vue
30 | vue create vue-admin-project
31 | ```
32 | 随后会出现两个选项
33 |
34 | 
35 |
36 |
37 | 选择第二项并继续,并选择自己需要配置的功能,完成后并继续,然后开始生成项目
38 |
39 | 
40 |
41 | 项目初始化成功
42 |
43 | 
44 | 接下来按照上面的提示运行`cd app`以及启动本地服务器`npm run serve`,当运行完成之后会提示你打来本地端口`http://localhost:8080`,会出现欢迎页面,此时代表你的vue项目初始化完成。
45 |
46 | 
47 |
48 | # 三、文件目录介绍与整理
49 | 整理前的初始目录
50 |
51 | |-- vue-admin-project
52 | |-- .gitignore //git项目忽视文件
53 | |-- babel.config.js //babel 配置文件
54 | |-- package-lock.json //记录安装包的具体版本号
55 | |-- package.json //包的类型
56 | |-- README.md
57 | |-- public //项目打包后的目录
58 | | |-- favicon.ico
59 | | |-- index.html
60 | |-- src //项目开发目录
61 | |-- App.vue //主入口文件
62 | |-- main.js //主入口文件
63 | |-- router.js //vue-router文件
64 | |-- store.js //vuex
65 | |-- assets //静态文件
66 | |-- logo.png
67 | |-- components //组件存放目录
68 | |-- HelloWorld.vue
69 | |-- views //视图目录
70 | |-- About.vue
71 | |-- Home.vue
72 | 整理后的目录,主要更改``/src``文件夹下的目录
73 |
74 | |-- vue-admin-project
75 | |-- .gitignore
76 | |-- babel.config.js
77 | |-- package-lock.json
78 | |-- package.json
79 | |-- README.md
80 | |-- public
81 | |-- favicon.ico
82 | |-- index.html
83 | |-- src
84 | |-- App.vue
85 | |-- main.js
86 | |-- assets
87 | |-- logo.png
88 | |-- components
89 | |-- HelloWorld.vue
90 | |-- router //路由配置文件夹
91 | |-- router.js
92 | |-- store //状态管理文件夹
93 | |-- store.js
94 | |-- views
95 | |-- About.vue
96 | |-- Home.vue
97 | # 四、开发环境与线上环境配置
98 | vue-cli 3.0x与vue-cli 2.0x最主要的区别是项目结构目录精简化,这也带来了许多问题,很多配置需要自己配置,由于2.0x版本中直接在`cofig/`文件夹下面配置开发环境与线上环境,3.0x则需要自己配置。
99 | 首先配置开发环境,在项目根目录下新建一个文件`.env`文件。
100 | ```javascript
101 | NODE_ENV="development" //开发环境
102 | BASE_URL="http://localhost:3000/" //开发环境接口地址
103 | ```
104 | 接下来我们配置线上环境,同样在项目根目录新建一个文件`.env.prod`这就表明是生产环境。
105 | ```javascript
106 | NODE_ENV="production" //生产环境
107 | BASE_URL="url" //生产环境的地址
108 | ```
109 | 现在我们如何在项目中判断当前环境呢?
110 | 我们可以根据`process.env.BASE_URL`来获取它是线上环境还是开发环境,后面会有运用
111 | ```javascript
112 | if(process.env.NODE_ENV='development'){
113 | console.log( process.env.BASE_URL) //http://localhost:3000/
114 | }else{
115 | console.log( process.env.BASE_URL) //url
116 | }
117 | ```
118 | 至此,我们成功的配置好了开发环境与线上环境。
119 |
120 | # 五、vue.config.js配置
121 | 讲到`vue.config.js`项目配置文件,又不得不说下3.x和2.x的区别,2.x里面webpack相关的配置项直接在项目的`build/webpack.base.conf.js`里面配置,而3.x完全在`vue.config.js`中配置,这使得整个项目看起来更加简洁明了,项目运行速度更快。
122 | 由于项目初始化的时候没有`vue.config.js`配置文件,因此我们需要在项目根目录下新建一个`vue.config.js`配置项。
123 | 在这个配置项里面,本项目主要是配置三个东西,第一个就是目录别名`alias`,另一个是项目启动时自动打开浏览器,最后一个就是处理引入的全局scss文件。当然有`vue.config.js`的配置远远不止这几项,有兴趣的同学可以去看看[vue.config.js](https://cli.vuejs.org/zh/guide/webpack.html)具体配置,具体代码如下。
124 | ```javascript
125 | let path=require('path');
126 | function resolve(dir){
127 | return path.join(__dirname,dir)
128 | }
129 | module.exports = {
130 | chainWebpack: config => {
131 | //设置别名
132 | config.resolve.alias
133 | .set('@',resolve('src'))
134 | },
135 | devServer: {
136 | open:true //打开浏览器窗口
137 | },
138 | //定义scss全局变量
139 | css: {
140 | loaderOptions: {
141 | sass: {
142 | data: `@import "@/assets/scss/global.scss";`
143 | }
144 | }
145 | }
146 | }
147 | ```
148 | # 六、ElementUI引入
149 | 开始安装ElementUI
150 | ```javascript
151 | vue add element
152 | ```
153 | 接下来两个选项,第一个是全部引入,第二个是按需引入,我选择第一个`Fully import`,大家可以按照自己的项目而定。接下来会询问是否引入scss,这里选择是,语言选择zh-cn。
154 | 接下来会提示安装成功,并在项目首页有一个element样式的按钮。
155 | # 七、vue-router路由介绍入
156 | 路由管理也是本项目核心部分。
157 | 1.引入文件
158 | ```javascript
159 | import Vue from 'vue'
160 | import Router from 'vue-router'
161 | import store from '../store/store' //引入状态管理
162 | import NProgress from 'nprogress' //引入进度条组件 cnpm install nprogress --save
163 | import 'nprogress/nprogress.css'
164 | Vue.use(Router)
165 | ```
166 | 2.路由懒加载
167 | ```javascript
168 | /**
169 | *@parma {String} name 文件夹名称
170 | *@parma {String} component 视图组件名称
171 | */
172 | const getComponent = (name,component) => () => import(`@/views/${name}/${component}.vue`);
173 | ```
174 | 3.路由配置
175 | ```javascript
176 | const myRouter=new Router({
177 | routes: [
178 | {
179 | path: '/',
180 | redirect: '/home',
181 | component: getComponent('login','index')
182 | },
183 | {
184 | path: '/login',
185 | name: 'login',
186 | component: getComponent('login','index')
187 | },
188 | {
189 | path: '/',
190 | component:getComponent('layout','Layout'),
191 | children:[{
192 | path:'/home',
193 | name:'home',
194 | component: getComponent('home','index'),
195 | meta:{title:'首页'}
196 | },
197 | {
198 | path:'/icon',
199 | component: getComponent('icons','index'),
200 | name:'icon',
201 | meta:{title:'自定义图标'}
202 | },
203 | {
204 | path:'/editor',
205 | component: getComponent('component','editor'),
206 | name:'editor',
207 | meta:{title:'富文本编译器'}
208 | },
209 | {
210 | path:'/countTo',
211 | component: getComponent('component','countTo'),
212 | name:'countTo',
213 | meta:{title:'数字滚动'}
214 | },
215 | {
216 | path:'/tree',
217 | component: getComponent('component','tree'),
218 | name:'tree',
219 | meta:{title:'自定义树'}
220 | },
221 | {
222 | path:'/treeTable',
223 | component: getComponent('component','treeTable'),
224 | name:'treeTable',
225 | meta:{title:'表格树'}
226 | },
227 | {
228 | path:'/treeSelect',
229 | component: getComponent('component','treeSelect'),
230 | name:'treeSelect',
231 | meta:{title:'下拉树'}
232 | },
233 | {
234 | path:'/draglist',
235 | component: getComponent('draggable','draglist'),
236 | name:'draglist',
237 | meta:{title:'拖拽列表'}
238 | },
239 | {
240 | path:'/dragtable',
241 | component: getComponent('draggable','dragtable'),
242 | name:'dragtable',
243 | meta:{title:'拖拽表格'}
244 | },
245 | {
246 | path:'/cricle',
247 | component: getComponent('charts','cricle'),
248 | name:'cricle',
249 | meta:{title:'饼图'}
250 | },
251 | ]
252 | }
253 | ]
254 | })
255 | ```
256 | 4.本项目存在一个token,来验证权限问题,因此进入页面的时候需要判断是否存在token,如果不存在则跳转到登陆页面
257 | ```javascript
258 | //判断是否存在token
259 | myRouter.beforeEach((to,from,next)=>{
260 | NProgress.start()
261 | if (to.path !== '/login' && !store.state.token) {
262 | next('/login') //跳转登录
263 | NProgress.done() // 结束Progress
264 | }
265 | next()
266 | })
267 | myRouter.afterEach(() => {
268 | NProgress.done() // 结束Progress
269 | })
270 | ```
271 | 5.导出路由
272 | ```javascript
273 | export default myRouter
274 | ```
275 | # 八、axios引入并封装
276 | 1.接口处理我选择的是axios,由于它遵循promise规范,能很好的避免回调地狱。现在我们开始安装
277 | ```javascript
278 | cnpm install axios -S
279 | ```
280 | 2.在`src`目录下新建文件夹命名为`api`,里面新建两个文件,一个是`api.js`,用于接口的整合,另一个是`request.js`,根据相关业务封装axios请求。
281 | + request.js
282 | 1.引入依赖
283 | ```javascript
284 | import axios from "axios";
285 | import router from "../router/router";
286 | import {
287 | Loading
288 | } from "element-ui";
289 | import {messages} from '../assets/js/common.js' //封装的提示文件
290 | import store from '../store/store' //引入vuex
291 | ```
292 | 2.编写axios基本设置
293 | ```javascript
294 | axios.defaults.timeout = 60000; //设置接口超时时间
295 | axios.defaults.baseURL = process.env.BASE_URL; //根据环境设置基础路径
296 | axios.defaults.headers.post["Content-Type"] =
297 | "application/x-www-form-urlencoded;charset=UTF-8"; //设置编码
298 | let loading = null; //初始化loading
299 | ```
300 | 3.编写请求拦截,也就是说在请求接口前要做的事情
301 | ```javascript
302 | /*
303 | *请求前拦截
304 | *用于处理需要请求前的操作
305 | */
306 | axios.interceptors.request.use(
307 | config => {
308 | loading = Loading.service({
309 | text: "正在加载中......",
310 | fullscreen: true
311 | });
312 | if (store.state.token) {
313 | config.headers["Authorization"] = "Bearer " + store.state.token;
314 | }
315 | return config;
316 | },
317 | error => {
318 | return Promise.reject(error);
319 | }
320 | );
321 | ```
322 | 4.编写请求响应拦截,用于处理数据返回操作
323 | ```javascript
324 | /*
325 | *请求响应拦截
326 | *用于处理数据返回后的操作
327 | */
328 | axios.interceptors.response.use(
329 | response => {
330 | return new Promise((resolve, reject) => {
331 | //请求成功后关闭加载框
332 | if (loading) {
333 | loading.close();
334 | }
335 | const res = response.data;
336 | if (res.err_code === 0) {
337 | resolve(res)
338 | } else{
339 | reject(res)
340 | }
341 | })
342 | },
343 | error => {
344 | console.log(error)
345 | //请求成功后关闭加载框
346 | if (loading) {
347 | loading.close();
348 | }
349 | //断网处理或者请求超时
350 | if (!error.response) {
351 | //请求超时
352 | if (error.message.includes("timeout")) {
353 | console.log("超时了");
354 | messages("error", "请求超时,请检查互联网连接");
355 | } else {
356 | //断网,可以展示断网组件
357 | console.log("断网了");
358 | messages("error", "请检查网络是否已连接");
359 | }
360 | return;
361 | }
362 | const status = error.response.status;
363 | switch (status) {
364 | case 500:
365 | messages("error", "服务器内部错误");
366 | break;
367 | case 404:
368 | messages(
369 | "error",
370 | "未找到远程服务器"
371 | );
372 | break;
373 | case 401:
374 | messages("warning", "用户登陆过期,请重新登陆");
375 | localStorage.removeItem("token");
376 | setTimeout(() => {
377 | router.replace({
378 | path: "/login",
379 | query: {
380 | redirect: router.currentRoute.fullPath
381 | }
382 | });
383 | }, 1000);
384 | break;
385 | case 400:
386 | messages("error", "数据异常,详情请咨询聚保服务热线");
387 | break;
388 | default:
389 | messages("error", error.response.data.message);
390 | }
391 | return Promise.reject(error);
392 | }
393 | );
394 | ```
395 | 5.请求相关的事情已经完成,现在开始封装get,post请求
396 | ```javascript
397 | /*
398 | *get方法,对应get请求
399 | *@param {String} url [请求的url地址]
400 | *@param {Object} params [请求时候携带的参数]
401 | */
402 | export function get(url, params) {
403 | return new Promise((resolve, reject) => {
404 | axios
405 | .get(url, {
406 | params
407 | })
408 | .then(res => {
409 | resolve(res);
410 | })
411 | .catch(err => {
412 | reject(err);
413 | });
414 | });
415 | }
416 | /*
417 | *post方法,对应post请求
418 | *@param {String} url [请求的url地址]
419 | *@param {Object} params [请求时候携带的参数]
420 | */
421 | export function post(url, params) {
422 | return new Promise((resolve, reject) => {
423 | axios
424 | .post(url, params)
425 | .then(res => {
426 | resolve(res);
427 | })
428 | .catch(err => {
429 | reject(err);
430 | });
431 | });
432 | }
433 | ```
434 | + api.js
435 | 封装好axios的业务逻辑之后自然要开始,运用,首先引入`get`以及`post`方法
436 | ```javascript
437 | import {get,post} from './request';
438 | ```
439 | 接下来开始封装接口,并导出
440 | ```javascript
441 | //登陆
442 | export const login=(login)=>post('/api/post/user/login',login)
443 | //上传
444 | export const upload=(upload)=>get('/api/get/upload',upload)
445 | ```
446 | 那我们如何调用接口呢?以登陆页面为例。
447 | ```javascript
448 | import { login } from "@/api/api.js"; //引入login
449 | ```
450 | ```javascript
451 | /**
452 | * @oarma {Object} login 接口传递的参数
453 | */
454 | login(login)
455 | .then(res => {
456 | //成功之后要做的事情
457 | })
458 | .catch(err => {
459 | //出错时要做的事情
460 | });
461 | ```
462 | 接口相关的逻辑已经处理完。
463 | # 九、vuex引入
464 | 由于vue项目中组件之间传递数据比较复杂,因此官方引入了一个全局状态管理的东东,也就是现在要说的vuex,vuex能更好的管理数据,方便组件之间的通信。
465 | 现在在store文件夹下面新建四个文件`state.js`,`mutations.js`,`getter.js`,`action.js`。
466 | + state.js
467 | state就是Vuex中的公共的状态, 我是将state看作是所有组件的data, 用于保存所有组件的公共数据.
468 | ```javascript
469 | const state = {
470 | token: '',//权限验证
471 | tagsList: [], //打开的标签页个数,
472 | isCollapse: false, //侧边导航是否折叠
473 | }
474 | export default state //导出
475 | ```
476 | + mutations.js
477 | 我将mutaions理解为store中的methods, mutations对象中保存着更改数据的回调函数,该函数名官方规定叫type, 第一个参数是state, 第二参数是payload, 也就是自定义的参数.改变state的值必须经过mutations
478 | ```javascript
479 | const mutations = {
480 | //保存token
481 | COMMIT_TOKEN(state, object) {
482 | state.token = object.token;
483 | },
484 | //保存标签
485 | TAGES_LIST(state, arr) {
486 | state.tagsList = arr;
487 | },
488 | IS_COLLAPSE(state, bool) {
489 | state.isCollapse = bool;
490 | }
491 | }
492 | export default mutations
493 | ```
494 | + getter.js
495 | 我将getters属性理解为所有组件的computed属性,也就是计算属性。vuex的官方文档也是说到可以将getter理解为store的计算属性, getters的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
496 | ```javascript
497 | const getters={
498 | //你要计算的属性
499 | }
500 | export default getters
501 | ```
502 | + action.js
503 | actions 类似于 mutations,不同在于:
504 | 1.actions提交的是mutations而不是直接变更状态
505 | 2.actions中可以包含异步操作, mutations中绝对不允许出现异步
506 | 3.actions中的回调函数的第一个参数是context, 是一个与store实例具有相同属性和方法的对象
507 | ```javascript
508 | const actions={
509 |
510 | }
511 | export default actions
512 | ```
513 | + store.js
514 | store.js是vuex模块整合文件,由于刷新页面会造成vuex数据丢失,所以这里引入了一个vuex数据持久话插件,将state里面的数据保存到localstorage。
515 | 安装`vuex-persistedstate `
516 | ```javascript
517 | npm install vuex-persistedstate --save
518 | ```
519 | ```javascript
520 | import Vue from 'vue'
521 | import Vuex from 'vuex'
522 | import state from "./state";
523 | import mutations from "./mutations";
524 | import actions from "./actions";
525 | import getters from "./getters";
526 | //引入vuex 数据持久化插件
527 | import createPersistedState from "vuex-persistedstate"
528 | Vue.use(Vuex)
529 |
530 | export default new Vuex.Store({
531 | state,
532 | mutations,
533 | actions,
534 | getters,
535 | plugins: [createPersistedState()]
536 | })
537 | ```
538 | 至此vuex引入完毕,如同学们还有不明白的可以去翻阅[vuex](https://vuex.vuejs.org/zh/)文档。
539 | # 十、首页布局介绍
540 | 现在我们开始进行页面的布局。首先我们来分析下首页的情况
541 | 
542 | 1. 侧边栏
543 | 2. 顶部栏
544 | 3. 内容部分
545 | 首先我们在`view`文件夹下面新建一个`layout`文件夹,里面再添加一个`layout.vue`,以及`compentents`文件夹。
546 | + 侧边栏
547 | 在compentents文件夹下面新建一个`Aside.vue`文件,实现路由跳转相关的逻辑,运用了element导航菜单的路由模式,如有不明白的可以去[ElementUI导航菜单](http://element-cn.eleme.io/2.0/#/zh-CN/component/menu)去看看。
548 | ```html
549 |
550 |
551 |
588 |
589 |
590 | ```
591 | ```javascript
592 | import { mapState } from "vuex";
593 | export default {
594 | data() {
595 | return {
596 | //配置目录
597 | items: [
598 | {
599 | icon: "el-icon-edit-outline",
600 | index: "home",
601 | title: "系统首页"
602 | },
603 | {
604 | icon: "el-icon-edit-outline",
605 | index: "icon",
606 | title: "自定义图标"
607 | },
608 | {
609 | icon: "el-icon-edit-outline",
610 | index: "component",
611 | title: "组件",
612 | subs: [
613 | {
614 | index: "editor",
615 | title: "富文本编译器"
616 | },
617 | {
618 | index: "countTo",
619 | title: "数字滚动"
620 | },
621 | {
622 | index: "trees",
623 | title: "树形控件",
624 | subs: [
625 | {
626 | index: "tree",
627 | title: "自定义树"
628 | },
629 | {
630 | index: "treeSelect",
631 | title: "下拉树"
632 | }
633 | // ,{
634 | // index:'treeTable',
635 | // title:'表格树',
636 | // }
637 | ]
638 | },
639 | ]
640 | },
641 | {
642 | icon: "el-icon-edit-outline",
643 | index: "draggable",
644 | title: "拖拽",
645 | subs: [
646 | {
647 | index: "draglist",
648 | title: "拖拽列表"
649 | },
650 | {
651 | index: "dragtable",
652 | title: "拖拽表格"
653 | }
654 | ]
655 | },
656 | {
657 | icon: "el-icon-edit-outline",
658 | index: "charts",
659 | title: "图表",
660 | subs: [
661 | {
662 | index: "cricle",
663 | title: "饼图"
664 | },
665 | ]
666 | },
667 | {
668 | icon: "el-icon-edit-outline",
669 | index: "7",
670 | title: "错误处理",
671 | subs: [
672 | {
673 | index: "permission",
674 | title: "权限测试"
675 | },
676 | {
677 | index: "404",
678 | title: "404页面"
679 | }
680 | ]
681 | },
682 | ]
683 | };
684 | },
685 | computed: {
686 | onRoutes() {
687 | return this.$route.path.replace("/", "");
688 | },
689 | ...mapState(["isCollapse"]) //从vuex里面获取菜单是否折叠
690 | },
691 | methods: {
692 | //下拉展开
693 | handleOpen(key, keyPath) {
694 | console.log(key, keyPath);
695 | },
696 | //下来关闭
697 | handleClose(key, keyPath) {
698 | console.log(key, keyPath);
699 | }
700 | }
701 | };
702 | ```
703 | + 顶部栏
704 | 在`view/compentents`文件夹下面新建一个`Header.vue`
705 | ```html
706 |
707 |
708 |
711 |
749 |
750 |
751 | ```
752 | ```javascript
753 | import showAside from "@/components/showAside.vue";//引入了一个侧边栏是否折叠的组件
754 | export default {
755 | // name:'header',
756 | components: {
757 | showAside
758 | },
759 | data() {
760 | return {
761 | fullscreen: false,
762 | name: "linxin",
763 | message: 2,
764 | username: "zyh"
765 | };
766 | },
767 | computed: {
768 | isCollapse: {
769 | get: function() {
770 | return this.$store.state.isCollapse;
771 | },
772 | set: function(newValue) {
773 | console.log(newValue);
774 | this.$store.commit("IS_COLLAPSE", newValue);//提交到vuex
775 | }
776 | }
777 | },
778 | methods: {
779 | toggleClick() {
780 | this.isCollapse = !this.isCollapse;
781 | },
782 | // 用户名下拉菜单选择事件
783 | logout(command) {
784 | this.$router.push("/login");
785 | },
786 | // 全屏事件
787 | handleFullScreen() {
788 | let element = document.documentElement;
789 | if (this.fullscreen) {
790 | if (document.exitFullscreen) {
791 | document.exitFullscreen();
792 | } else if (document.webkitCancelFullScreen) {
793 | document.webkitCancelFullScreen();
794 | } else if (document.mozCancelFullScreen) {
795 | document.mozCancelFullScreen();
796 | } else if (document.msExitFullscreen) {
797 | document.msExitFullscreen();
798 | }
799 | } else {
800 | if (element.requestFullscreen) {
801 | element.requestFullscreen();
802 | } else if (element.webkitRequestFullScreen) {
803 | element.webkitRequestFullScreen();
804 | } else if (element.mozRequestFullScreen) {
805 | element.mozRequestFullScreen();
806 | } else if (element.msRequestFullscreen) {
807 | // IE11
808 | element.msRequestFullscreen();
809 | }
810 | }
811 | this.fullscreen = !this.fullscreen;
812 | }
813 | }
814 | };
815 | ```
816 | 现在在`src/components`文件夹下面新建一个`showAside.vue`组件
817 | ```html
818 |
819 |
824 |
825 | ```
826 | ```javascript
827 | export default {
828 | name: "showAside",
829 | props: {
830 | toggleClick: {
831 | type: Function,
832 | default: null
833 | }
834 | }
835 | };
836 | ```
837 | + 顶部导航栏标签组件
838 | 在`view/compentents`文件夹下面新建一个`Tags.vue`
839 | ```html
840 |
841 |
842 |
869 |
870 | ```
871 | ```javascript
872 | import { messages } from "@/assets/js/common.js";
873 | export default {
874 | created() {
875 | //判断标签里面是否有值 有的话直接加载
876 | if (this.tagsList.length == 0) {
877 | this.setTags(this.$route);
878 | }
879 | },
880 | computed: {
881 | //computed 方法里面没有set方法因此不能使用mapState,需要重新定义set方法
882 | tagsList: {
883 | get: function() {
884 | return this.$store.state.tagsList;
885 | },
886 | set: function(newValue) {
887 | this.$store.commit("TAGES_LIST", newValue);
888 | // this.$store.state.tagsList = newValue;
889 | }
890 | }
891 | },
892 | watch: {
893 | //监听路由变化
894 | $route(newValue, oldValue) {
895 | this.setTags(newValue);
896 | }
897 | },
898 | methods: {
899 | //选中的高亮
900 | isActive(path) {
901 | return path === this.$route.fullPath;
902 | },
903 | handleCommand(command) {
904 | if (command == "closeOther") {
905 | // 关闭其他标签
906 | const curItem = this.tagsList.filter(item => {
907 | return item.path === this.$route.fullPath;
908 | });
909 | this.tagsList = curItem;
910 | }
911 | },
912 | //添加标签
913 | setTags(route) {
914 | let isIn = this.tagsList.some(item => {
915 | //判断标签是否存在
916 | return item.path === route.fullPath;
917 | });
918 | //不存在
919 | if (!isIn) {
920 | // 判断当前的标签个数
921 | if (this.tagsList.length >= 10) {
922 | messages("warning", "当标签大于10个,请关闭后再打开");
923 | } else {
924 | this.tagsList.push({
925 | title: route.meta.title,
926 | path: route.fullPath,
927 | name: route.name
928 | });
929 | //存到vuex
930 | this.$store.commit("TAGES_LIST", this.tagsList);
931 | }
932 | }
933 | },
934 | closeTags(index) {
935 | console.log(this.tagsList.length);
936 | if (this.tagsList.length == 1) {
937 | messages("warning", "不可全都关闭");
938 | } else {
939 | //删除当前
940 | let tags = this.tagsList.splice(index, 1);
941 | this.$store.commit("TAGES_LIST", this.tagsList);
942 | }
943 | }
944 | }
945 | };
946 | ```
947 | 接下来在`view/compentents`文件夹下面新建一个`Main.vue`,主要是将顶部导航标签栏以及内容部分结合起来。
948 | ```html
949 |
950 |
951 |
952 |
953 |
954 |
955 |
956 |
957 |
958 |
959 | ```
960 | ```javascript
961 | import Tags from './Tags.vue'
962 | export default {
963 | components:{
964 | Tags
965 | }
966 | }
967 | ```
968 | 相关组件写好,在layout组件中汇总
969 | ```html
970 |
971 |
972 |
973 |
974 |
975 |
976 |
977 |
978 |
979 | ```
980 | ```javascript
981 | import Aside from "./components/Aside.vue";
982 | import Header from "./components/Header.vue";
983 | import Main from "./components/Main.vue";
984 | import { mapState } from "vuex";
985 | export default {
986 | name: "Layout",
987 | components: {
988 | Aside,
989 | Header,
990 | Main
991 | },
992 | computed: {
993 | ...mapState(["isCollapse"])
994 | }
995 | };
996 | ```
997 | 至此首页布局已经规划完成。
998 | # 十一、结语
999 | 管理系统是多种多样的,每家公司都有不同的业务逻辑,本篇文章也只是抛砖引玉,还有许多需要修正改进的地方,如果同学们有更好的想法可以提出来希望大家一起完善本项目。
1000 |
1001 | |-- vue-admin-project
1002 | |-- .env
1003 | |-- .env.prod
1004 | |-- .env.test
1005 | |-- .gitignore
1006 | |-- babel.config.js
1007 | |-- package-lock.json
1008 | |-- package.json
1009 | |-- README.md
1010 | |-- vue.config.js
1011 | |-- public
1012 | | |-- favicon.ico
1013 | | |-- index.html
1014 | |-- src
1015 | |-- App.vue
1016 | |-- element-variables.scss
1017 | |-- main.js
1018 | |-- api
1019 | | |-- api.js
1020 | | |-- request.js
1021 | |-- assets
1022 | | |-- logo.png
1023 | | |-- css
1024 | | | |-- normalize.css
1025 | | | |-- public.css
1026 | | |-- icon
1027 | | | |-- demo.css
1028 | | | |-- demo_index.html
1029 | | | |-- iconfont.css
1030 | | | |-- iconfont.eot
1031 | | | |-- iconfont.js
1032 | | | |-- iconfont.svg
1033 | | | |-- iconfont.ttf
1034 | | | |-- iconfont.woff
1035 | | | |-- iconfont.woff2
1036 | | |-- img
1037 | | | |-- tou.jpg
1038 | | |-- js
1039 | | | |-- common.js
1040 | | |-- scss
1041 | | |-- global.scss
1042 | |-- components
1043 | | |-- showAside.vue
1044 | |-- plugins
1045 | | |-- element.js
1046 | |-- router
1047 | | |-- router.js
1048 | |-- store
1049 | | |-- actions.js
1050 | | |-- getters.js
1051 | | |-- mutations.js
1052 | | |-- state.js
1053 | | |-- store.js
1054 | |-- views
1055 | |-- layout
1056 | | |-- Layout.vue
1057 | | |-- components
1058 | | |-- Aside.vue
1059 | | |-- Header.vue
1060 | | |-- Main.vue
1061 | | |-- Tags.vue
1062 | 最后项目目录文件结构
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "my_project",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build"
8 | },
9 | "dependencies": {
10 | "@riophae/vue-treeselect": "^0.0.38",
11 | "axios": "^0.18.0",
12 | "echarts": "^4.2.1",
13 | "element-ui": "^2.4.5",
14 | "elementui_treegrid": "^0.0.3",
15 | "nprogress": "^0.2.0",
16 | "vue": "^2.6.6",
17 | "vue-count-to": "^1.0.13",
18 | "vue-json-viewer": "^2.1.4",
19 | "vue-router": "^3.0.1",
20 | "vue2-editor": "^2.6.6",
21 | "vuedraggable": "^2.20.0",
22 | "vuex": "^3.0.1",
23 | "vuex-persistedstate": "^2.5.4"
24 | },
25 | "devDependencies": {
26 | "@vue/cli-plugin-babel": "^3.4.0",
27 | "@vue/cli-service": "^3.4.0",
28 | "compression-webpack-plugin": "^2.0.0",
29 | "node-sass": "^4.9.2",
30 | "sass-loader": "^7.1.0",
31 | "vue-cli-plugin-element": "^1.0.1",
32 | "vue-template-compiler": "^2.5.21"
33 | },
34 | "postcss": {
35 | "plugins": {
36 | "autoprefixer": {}
37 | }
38 | },
39 | "browserslist": [
40 | "> 1%",
41 | "last 2 versions",
42 | "not ie <= 8"
43 | ]
44 | }
45 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaotian2017/vue-cli3-admin/789182f5a9375628e3dd5b11cdd0e5777bdac0d3/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | my_project
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
24 |
--------------------------------------------------------------------------------
/src/api/api.js:
--------------------------------------------------------------------------------
1 | import {get,post} from './request';
2 | //登陆
3 | export const login=(login)=>post('/api/post/user/login',login)
4 | //上传
5 | export const upload=(upload)=>get('/api/get/upload',upload)
--------------------------------------------------------------------------------
/src/api/request.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import router from "../router/router";
3 | import {
4 | Loading
5 | } from "element-ui";
6 | import {messages} from '../assets/js/common.js'
7 | import store from '../store/store'
8 | axios.defaults.timeout = 60000;
9 | axios.defaults.baseURL = process.env.BASE_URL;
10 | axios.defaults.headers.post["Content-Type"] =
11 | "application/x-www-form-urlencoded;charset=UTF-8";
12 | let loading = null;
13 | /*
14 | *请求前拦截
15 | *用于处理需要请求前的操作
16 | */
17 | axios.interceptors.request.use(
18 | config => {
19 | loading = Loading.service({
20 | text: "正在加载中......",
21 | fullscreen: true
22 | });
23 | if (store.state.token) {
24 | config.headers["Authorization"] = "Bearer " + store.state.token;
25 | }
26 | return config;
27 | },
28 | error => {
29 | return Promise.reject(error);
30 | }
31 | );
32 | /*
33 | *请求响应拦截
34 | *用于处理数据返回后的操作
35 | */
36 | axios.interceptors.response.use(
37 | response => {
38 | return new Promise((resolve, reject) => {
39 | //请求成功后关闭加载框
40 | if (loading) {
41 | loading.close();
42 | }
43 | const res = response.data;
44 | if (res.err_code === 0) {
45 | resolve(res)
46 | } else{
47 | reject(res)
48 | }
49 | })
50 | },
51 | error => {
52 | console.log(error)
53 | //请求成功后关闭加载框
54 | if (loading) {
55 | loading.close();
56 | }
57 | //断网处理或者请求超时
58 | if (!error.response) {
59 | //请求超时
60 | if (error.message.includes("timeout")) {
61 | console.log("超时了");
62 | messages("error", "请求超时,请检查互联网连接");
63 | } else {
64 | //断网,可以展示断网组件
65 | console.log("断网了");
66 | messages("error", "请检查网络是否已连接");
67 | }
68 | return;
69 | }
70 | const status = error.response.status;
71 | switch (status) {
72 | case 500:
73 | messages("error", "服务器内部错误");
74 | break;
75 | case 404:
76 | messages(
77 | "error",
78 | "未找到远程服务器"
79 | );
80 | break;
81 | case 401:
82 | messages("warning", "用户登陆过期,请重新登陆");
83 | localStorage.removeItem("token");
84 | setTimeout(() => {
85 | router.replace({
86 | path: "/login",
87 | query: {
88 | redirect: router.currentRoute.fullPath
89 | }
90 | });
91 | }, 1000);
92 | break;
93 | case 400:
94 | messages("error", "数据异常,详情请咨询聚保服务热线");
95 | break;
96 | default:
97 | messages("error", error.response.data.message);
98 | }
99 | return Promise.reject(error);
100 | }
101 | );
102 | /*
103 | *get方法,对应get请求
104 | *@param {String} url [请求的url地址]
105 | *@param {Object} params [请求时候携带的参数]
106 | */
107 | export function get(url, params) {
108 | return new Promise((resolve, reject) => {
109 | axios
110 | .get(url, {
111 | params
112 | })
113 | .then(res => {
114 | resolve(res);
115 | })
116 | .catch(err => {
117 | reject(err);
118 | });
119 | });
120 | }
121 | /*
122 | *post方法,对应post请求
123 | *@param {String} url [请求的url地址]
124 | *@param {Object} params [请求时候携带的参数]
125 | */
126 | export function post(url, params) {
127 | return new Promise((resolve, reject) => {
128 | axios
129 | .post(url, params)
130 | .then(res => {
131 | resolve(res);
132 | })
133 | .catch(err => {
134 | reject(err);
135 | });
136 | });
137 | }
--------------------------------------------------------------------------------
/src/assets/css/normalize.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 |
--------------------------------------------------------------------------------
/src/assets/css/public.css:
--------------------------------------------------------------------------------
1 | .el-form-item__label{
2 | color: white ;
3 | }
4 | /*
5 | * =====================================================
6 | * 页面公共样式、主体样式
7 | * =====================================================
8 | */
9 |
10 | /*初始化类*/
11 | @charset "UTF-8";
12 | html {
13 | font-family: "微软雅黑", Tahoma, Helvetica, Arial, sans-serif;
14 | /*去掉谷歌字体最小为12px的问题*/
15 | -webkit-text-size-adjust: 100%;
16 | /*超链接的去除高亮*/
17 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
18 | }
19 | *{
20 | margin: 0;
21 | padding: 0;
22 | box-sizing: border-box;
23 | -webkit-box-sizing: border-box;
24 | }
25 | input[type=button], input[type=submit], input[type=file], button {
26 | cursor: pointer;
27 | /*去除表单元素点击时的外框*/
28 | -webkit-appearance: none;
29 | outline: none;
30 | }
31 | body {
32 | margin: 0;
33 | padding: 0;
34 | line-height: normal;
35 | font-size: 0.24rem;
36 | /*下滑更流畅*/
37 | -webkit-overflow-scrolling: touch;
38 | }
39 |
40 | img {
41 | border: 0;
42 | vertical-align: middle;
43 | }
44 |
45 | *:focus{
46 | outline: medium;
47 | }
48 |
49 | article,
50 | aside,
51 | details,
52 | figcaption,
53 | figure,
54 | footer,
55 | header,
56 | hgroup,
57 | main,
58 | nav,
59 | section,
60 | summary {
61 | display: block;
62 | }
63 | a{
64 | text-decoration: none;
65 | color: white;
66 | }
67 | audio,
68 | canvas,
69 | progress,
70 | video {
71 | display: block;
72 | }
73 |
74 | a {
75 | background: transparent;
76 | text-decoration: none;
77 | }
78 |
79 | ol, ul, li {
80 | list-style: outside none none;
81 | }
82 |
83 | table {
84 | border-collapse: collapse;
85 | border-spacing: 0;
86 | }
87 |
88 | a:active {
89 | opacity: 0.5;
90 | -webkit-transition: 0.3s;
91 | transition: 0.3s;
92 | }
93 |
94 | select,
95 | textarea,
96 | input,
97 | button {
98 | border:1px solid #c8c7cc;
99 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
100 | -webkit-appearance: none !important;
101 | }
102 |
103 | /*主样式*/
104 | .pull-left {
105 | float: left !important;
106 | }
107 |
108 | .pull-right {
109 | float: right !important;
110 | }
111 |
112 | .clearfix:before, .clearfix:after {
113 | display: table;
114 | content: ' ';
115 | }
116 | .clearfix:after {
117 | clear: both;
118 | }
119 |
120 | .ellipsis {
121 | overflow: hidden;
122 | white-space: nowrap;
123 | text-overflow: ellipsis;
124 | }
125 |
126 | .ellipsis-2 {
127 | display: -webkit-box;
128 | overflow: hidden;
129 | white-space: normal !important;
130 | text-overflow: ellipsis;
131 | word-wrap: break-word;
132 | -webkit-line-clamp: 2;
133 | -webkit-box-orient: vertical;
134 | }
135 |
136 | .dcenter {
137 | margin-left: auto;
138 | margin-right: auto;
139 | }
140 |
141 | /*解决移动端1px边框变粗样式*/
142 | .border-t,
143 | .border-b,
144 | .border-l,
145 | .border-r,
146 | .border-tb,
147 | .border {
148 | position: relative;
149 | }
150 | .border-t:after,
151 | .border-b:after,
152 | .border-l:after,
153 | .border-r:after,
154 | .border-tb:after,
155 | .border:after {
156 | display: block;
157 | content: '';
158 | position: absolute;
159 | top: 0;
160 | right: 0;
161 | bottom: 0;
162 | left: 0;
163 | -webkit-transform-origin: 0 0;
164 | -webkit-transform: scale(1);
165 | pointer-events: none;
166 | }
167 | .border-l:after {
168 | border-left: 1px solid #c8c7cc;
169 | }
170 | .border-r:after {
171 | border-right: 1px solid #c8c7cc;
172 | }
173 | .border-t:after {
174 | border-top: 1px solid #c8c7cc;
175 | }
176 | .border-b:after {
177 | border-bottom: 1px solid #c8c7cc;
178 | }
179 | .border-tb:after {
180 | border-top: 1px solid #c8c7cc;
181 | border-bottom: 1px solid #c8c7cc;
182 | }
183 | .border:after {
184 | border:1px solid #c8c7cc;
185 | }
186 | .border.border-radius:after {
187 | border-radius: 6px;
188 | }
189 | @media screen and (-webkit-min-device-pixel-ratio:1.5) {
190 | .border-t:after,
191 | .border-b:after,
192 | .border-l:after,
193 | .border-r:after,
194 | .border-tb:after,
195 | .border:after {
196 | right: -100%;
197 | bottom: -100%;
198 | -webkit-transform: scale(0.5);
199 | }
200 | }
201 |
202 | /*仿IOS开关*/
203 | .switch {
204 | -webkit-appearance: none;
205 | -moz-appearance: none;
206 | appearance: none;
207 | position: relative;
208 | width: 52px;
209 | height: 32px;
210 | border: 1px solid #DFDFDF;
211 | outline: 0;
212 | border-radius: 16px;
213 | box-sizing: border-box;
214 | background: #DFDFDF;
215 | }
216 | .switch:before {
217 | content: " ";
218 | position: absolute;
219 | top: 0;
220 | left: 0;
221 | width: 50px;
222 | height: 30px;
223 | border-radius: 15px;
224 | background-color: #FDFDFD;
225 | -webkit-transition: -webkit-transform .3s;
226 | transition: -webkit-transform .3s;
227 | transition: transform .3s;
228 | transition: transform .3s, -webkit-transform .3s;
229 | }
230 | .switch:after {
231 | content: " ";
232 | position: absolute;
233 | top: 0;
234 | left: 0;
235 | width: 30px;
236 | height: 30px;
237 | border-radius: 15px;
238 | background-color: #FFFFFF;
239 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
240 | -webkit-transition: -webkit-transform .3s;
241 | transition: -webkit-transform .3s;
242 | transition: transform .3s;
243 | transition: transform .3s, -webkit-transform .3s;
244 | }
245 | .switch:checked {
246 | border-color: #04BE02;
247 | background-color: #04BE02;
248 | }
249 | .switch:checked:before {
250 | -webkit-transform: scale(0);
251 | transform: scale(0);
252 | }
253 | .switch:checked:after {
254 | -webkit-transform: translateX(20px);
255 | transform: translateX(20px);
256 | }
--------------------------------------------------------------------------------
/src/assets/icon/demo.css:
--------------------------------------------------------------------------------
1 | /* Logo 字体 */
2 | @font-face {
3 | font-family: "iconfont logo";
4 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
5 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
6 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
7 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
8 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
9 | }
10 |
11 | .logo {
12 | font-family: "iconfont logo";
13 | font-size: 160px;
14 | font-style: normal;
15 | -webkit-font-smoothing: antialiased;
16 | -moz-osx-font-smoothing: grayscale;
17 | }
18 |
19 | /* tabs */
20 | .nav-tabs {
21 | position: relative;
22 | }
23 |
24 | .nav-tabs .nav-more {
25 | position: absolute;
26 | right: 0;
27 | bottom: 0;
28 | height: 42px;
29 | line-height: 42px;
30 | color: #666;
31 | }
32 |
33 | #tabs {
34 | border-bottom: 1px solid #eee;
35 | }
36 |
37 | #tabs li {
38 | cursor: pointer;
39 | width: 100px;
40 | height: 40px;
41 | line-height: 40px;
42 | text-align: center;
43 | font-size: 16px;
44 | border-bottom: 2px solid transparent;
45 | position: relative;
46 | z-index: 1;
47 | margin-bottom: -1px;
48 | color: #666;
49 | }
50 |
51 |
52 | #tabs .active {
53 | border-bottom-color: #f00;
54 | color: #222;
55 | }
56 |
57 | .tab-container .content {
58 | display: none;
59 | }
60 |
61 | /* 页面布局 */
62 | .main {
63 | padding: 30px 100px;
64 | width: 960px;
65 | margin: 0 auto;
66 | }
67 |
68 | .main .logo {
69 | color: #333;
70 | text-align: left;
71 | margin-bottom: 30px;
72 | line-height: 1;
73 | height: 110px;
74 | margin-top: -50px;
75 | overflow: hidden;
76 | *zoom: 1;
77 | }
78 |
79 | .main .logo a {
80 | font-size: 160px;
81 | color: #333;
82 | }
83 |
84 | .helps {
85 | margin-top: 40px;
86 | }
87 |
88 | .helps pre {
89 | padding: 20px;
90 | margin: 10px 0;
91 | border: solid 1px #e7e1cd;
92 | background-color: #fffdef;
93 | overflow: auto;
94 | }
95 |
96 | .icon_lists {
97 | width: 100% !important;
98 | overflow: hidden;
99 | *zoom: 1;
100 | }
101 |
102 | .icon_lists li {
103 | width: 100px;
104 | margin-bottom: 10px;
105 | margin-right: 20px;
106 | text-align: center;
107 | list-style: none !important;
108 | cursor: default;
109 | }
110 |
111 | .icon_lists li .code-name {
112 | line-height: 1.2;
113 | }
114 |
115 | .icon_lists .icon {
116 | display: block;
117 | height: 100px;
118 | line-height: 100px;
119 | font-size: 42px;
120 | margin: 10px auto;
121 | color: #333;
122 | -webkit-transition: font-size 0.25s linear, width 0.25s linear;
123 | -moz-transition: font-size 0.25s linear, width 0.25s linear;
124 | transition: font-size 0.25s linear, width 0.25s linear;
125 | }
126 |
127 | .icon_lists .icon:hover {
128 | font-size: 100px;
129 | }
130 |
131 | .icon_lists .svg-icon {
132 | /* 通过设置 font-size 来改变图标大小 */
133 | width: 1em;
134 | /* 图标和文字相邻时,垂直对齐 */
135 | vertical-align: -0.15em;
136 | /* 通过设置 color 来改变 SVG 的颜色/fill */
137 | fill: currentColor;
138 | /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
139 | normalize.css 中也包含这行 */
140 | overflow: hidden;
141 | }
142 |
143 | .icon_lists li .name,
144 | .icon_lists li .code-name {
145 | color: #666;
146 | }
147 |
148 | /* markdown 样式 */
149 | .markdown {
150 | color: #666;
151 | font-size: 14px;
152 | line-height: 1.8;
153 | }
154 |
155 | .highlight {
156 | line-height: 1.5;
157 | }
158 |
159 | .markdown img {
160 | vertical-align: middle;
161 | max-width: 100%;
162 | }
163 |
164 | .markdown h1 {
165 | color: #404040;
166 | font-weight: 500;
167 | line-height: 40px;
168 | margin-bottom: 24px;
169 | }
170 |
171 | .markdown h2,
172 | .markdown h3,
173 | .markdown h4,
174 | .markdown h5,
175 | .markdown h6 {
176 | color: #404040;
177 | margin: 1.6em 0 0.6em 0;
178 | font-weight: 500;
179 | clear: both;
180 | }
181 |
182 | .markdown h1 {
183 | font-size: 28px;
184 | }
185 |
186 | .markdown h2 {
187 | font-size: 22px;
188 | }
189 |
190 | .markdown h3 {
191 | font-size: 16px;
192 | }
193 |
194 | .markdown h4 {
195 | font-size: 14px;
196 | }
197 |
198 | .markdown h5 {
199 | font-size: 12px;
200 | }
201 |
202 | .markdown h6 {
203 | font-size: 12px;
204 | }
205 |
206 | .markdown hr {
207 | height: 1px;
208 | border: 0;
209 | background: #e9e9e9;
210 | margin: 16px 0;
211 | clear: both;
212 | }
213 |
214 | .markdown p {
215 | margin: 1em 0;
216 | }
217 |
218 | .markdown>p,
219 | .markdown>blockquote,
220 | .markdown>.highlight,
221 | .markdown>ol,
222 | .markdown>ul {
223 | width: 80%;
224 | }
225 |
226 | .markdown ul>li {
227 | list-style: circle;
228 | }
229 |
230 | .markdown>ul li,
231 | .markdown blockquote ul>li {
232 | margin-left: 20px;
233 | padding-left: 4px;
234 | }
235 |
236 | .markdown>ul li p,
237 | .markdown>ol li p {
238 | margin: 0.6em 0;
239 | }
240 |
241 | .markdown ol>li {
242 | list-style: decimal;
243 | }
244 |
245 | .markdown>ol li,
246 | .markdown blockquote ol>li {
247 | margin-left: 20px;
248 | padding-left: 4px;
249 | }
250 |
251 | .markdown code {
252 | margin: 0 3px;
253 | padding: 0 5px;
254 | background: #eee;
255 | border-radius: 3px;
256 | }
257 |
258 | .markdown strong,
259 | .markdown b {
260 | font-weight: 600;
261 | }
262 |
263 | .markdown>table {
264 | border-collapse: collapse;
265 | border-spacing: 0px;
266 | empty-cells: show;
267 | border: 1px solid #e9e9e9;
268 | width: 95%;
269 | margin-bottom: 24px;
270 | }
271 |
272 | .markdown>table th {
273 | white-space: nowrap;
274 | color: #333;
275 | font-weight: 600;
276 | }
277 |
278 | .markdown>table th,
279 | .markdown>table td {
280 | border: 1px solid #e9e9e9;
281 | padding: 8px 16px;
282 | text-align: left;
283 | }
284 |
285 | .markdown>table th {
286 | background: #F7F7F7;
287 | }
288 |
289 | .markdown blockquote {
290 | font-size: 90%;
291 | color: #999;
292 | border-left: 4px solid #e9e9e9;
293 | padding-left: 0.8em;
294 | margin: 1em 0;
295 | }
296 |
297 | .markdown blockquote p {
298 | margin: 0;
299 | }
300 |
301 | .markdown .anchor {
302 | opacity: 0;
303 | transition: opacity 0.3s ease;
304 | margin-left: 8px;
305 | }
306 |
307 | .markdown .waiting {
308 | color: #ccc;
309 | }
310 |
311 | .markdown h1:hover .anchor,
312 | .markdown h2:hover .anchor,
313 | .markdown h3:hover .anchor,
314 | .markdown h4:hover .anchor,
315 | .markdown h5:hover .anchor,
316 | .markdown h6:hover .anchor {
317 | opacity: 1;
318 | display: inline-block;
319 | }
320 |
321 | .markdown>br,
322 | .markdown>p>br {
323 | clear: both;
324 | }
325 |
326 |
327 | .hljs {
328 | display: block;
329 | background: white;
330 | padding: 0.5em;
331 | color: #333333;
332 | overflow-x: auto;
333 | }
334 |
335 | .hljs-comment,
336 | .hljs-meta {
337 | color: #969896;
338 | }
339 |
340 | .hljs-string,
341 | .hljs-variable,
342 | .hljs-template-variable,
343 | .hljs-strong,
344 | .hljs-emphasis,
345 | .hljs-quote {
346 | color: #df5000;
347 | }
348 |
349 | .hljs-keyword,
350 | .hljs-selector-tag,
351 | .hljs-type {
352 | color: #a71d5d;
353 | }
354 |
355 | .hljs-literal,
356 | .hljs-symbol,
357 | .hljs-bullet,
358 | .hljs-attribute {
359 | color: #0086b3;
360 | }
361 |
362 | .hljs-section,
363 | .hljs-name {
364 | color: #63a35c;
365 | }
366 |
367 | .hljs-tag {
368 | color: #333333;
369 | }
370 |
371 | .hljs-title,
372 | .hljs-attr,
373 | .hljs-selector-id,
374 | .hljs-selector-class,
375 | .hljs-selector-attr,
376 | .hljs-selector-pseudo {
377 | color: #795da3;
378 | }
379 |
380 | .hljs-addition {
381 | color: #55a532;
382 | background-color: #eaffea;
383 | }
384 |
385 | .hljs-deletion {
386 | color: #bd2c00;
387 | background-color: #ffecec;
388 | }
389 |
390 | .hljs-link {
391 | text-decoration: underline;
392 | }
393 |
394 | /* 代码高亮 */
395 | /* PrismJS 1.15.0
396 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
397 | /**
398 | * prism.js default theme for JavaScript, CSS and HTML
399 | * Based on dabblet (http://dabblet.com)
400 | * @author Lea Verou
401 | */
402 | code[class*="language-"],
403 | pre[class*="language-"] {
404 | color: black;
405 | background: none;
406 | text-shadow: 0 1px white;
407 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
408 | text-align: left;
409 | white-space: pre;
410 | word-spacing: normal;
411 | word-break: normal;
412 | word-wrap: normal;
413 | line-height: 1.5;
414 |
415 | -moz-tab-size: 4;
416 | -o-tab-size: 4;
417 | tab-size: 4;
418 |
419 | -webkit-hyphens: none;
420 | -moz-hyphens: none;
421 | -ms-hyphens: none;
422 | hyphens: none;
423 | }
424 |
425 | pre[class*="language-"]::-moz-selection,
426 | pre[class*="language-"] ::-moz-selection,
427 | code[class*="language-"]::-moz-selection,
428 | code[class*="language-"] ::-moz-selection {
429 | text-shadow: none;
430 | background: #b3d4fc;
431 | }
432 |
433 | pre[class*="language-"]::selection,
434 | pre[class*="language-"] ::selection,
435 | code[class*="language-"]::selection,
436 | code[class*="language-"] ::selection {
437 | text-shadow: none;
438 | background: #b3d4fc;
439 | }
440 |
441 | @media print {
442 |
443 | code[class*="language-"],
444 | pre[class*="language-"] {
445 | text-shadow: none;
446 | }
447 | }
448 |
449 | /* Code blocks */
450 | pre[class*="language-"] {
451 | padding: 1em;
452 | margin: .5em 0;
453 | overflow: auto;
454 | }
455 |
456 | :not(pre)>code[class*="language-"],
457 | pre[class*="language-"] {
458 | background: #f5f2f0;
459 | }
460 |
461 | /* Inline code */
462 | :not(pre)>code[class*="language-"] {
463 | padding: .1em;
464 | border-radius: .3em;
465 | white-space: normal;
466 | }
467 |
468 | .token.comment,
469 | .token.prolog,
470 | .token.doctype,
471 | .token.cdata {
472 | color: slategray;
473 | }
474 |
475 | .token.punctuation {
476 | color: #999;
477 | }
478 |
479 | .namespace {
480 | opacity: .7;
481 | }
482 |
483 | .token.property,
484 | .token.tag,
485 | .token.boolean,
486 | .token.number,
487 | .token.constant,
488 | .token.symbol,
489 | .token.deleted {
490 | color: #905;
491 | }
492 |
493 | .token.selector,
494 | .token.attr-name,
495 | .token.string,
496 | .token.char,
497 | .token.builtin,
498 | .token.inserted {
499 | color: #690;
500 | }
501 |
502 | .token.operator,
503 | .token.entity,
504 | .token.url,
505 | .language-css .token.string,
506 | .style .token.string {
507 | color: #9a6e3a;
508 | background: hsla(0, 0%, 100%, .5);
509 | }
510 |
511 | .token.atrule,
512 | .token.attr-value,
513 | .token.keyword {
514 | color: #07a;
515 | }
516 |
517 | .token.function,
518 | .token.class-name {
519 | color: #DD4A68;
520 | }
521 |
522 | .token.regex,
523 | .token.important,
524 | .token.variable {
525 | color: #e90;
526 | }
527 |
528 | .token.important,
529 | .token.bold {
530 | font-weight: bold;
531 | }
532 |
533 | .token.italic {
534 | font-style: italic;
535 | }
536 |
537 | .token.entity {
538 | cursor: help;
539 | }
540 |
--------------------------------------------------------------------------------
/src/assets/icon/demo_index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IconFont Demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | - Unicode
22 | - Font class
23 | - Symbol
24 |
25 |
26 |
查看项目
27 |
28 |
29 |
30 |
31 |
32 |
33 | -
34 |
35 |
流量
36 | 
37 |
38 |
39 | -
40 |
41 |
眼睛
42 | 
43 |
44 |
45 | -
46 |
47 |
消息
48 | 
49 |
50 |
51 | -
52 |
53 |
用户
54 | 
55 |
56 |
57 |
58 |
59 |
Unicode 引用
60 |
61 |
62 |
Unicode 是字体在网页端最原始的应用方式,特点是:
63 |
64 | - 兼容性最好,支持 IE6+,及所有现代浏览器。
65 | - 支持按字体的方式去动态调整图标大小,颜色等等。
66 | - 但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。
67 |
68 |
69 | 注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式
70 |
71 |
Unicode 使用步骤如下:
72 |
第一步:拷贝项目下面生成的 @font-face
73 |
@font-face {
75 | font-family: 'iconfont';
76 | src: url('iconfont.eot');
77 | src: url('iconfont.eot?#iefix') format('embedded-opentype'),
78 | url('iconfont.woff2') format('woff2'),
79 | url('iconfont.woff') format('woff'),
80 | url('iconfont.ttf') format('truetype'),
81 | url('iconfont.svg#iconfont') format('svg');
82 | }
83 |
84 |
第二步:定义使用 iconfont 的样式
85 |
.iconfont {
87 | font-family: "iconfont" !important;
88 | font-size: 16px;
89 | font-style: normal;
90 | -webkit-font-smoothing: antialiased;
91 | -moz-osx-font-smoothing: grayscale;
92 | }
93 |
94 |
第三步:挑选相应图标并获取字体编码,应用于页面
95 |
96 | <span class="iconfont">3</span>
98 |
99 |
100 | "iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。
101 |
102 |
103 |
104 |
105 |
106 |
107 | -
108 |
109 |
110 | 流量
111 |
112 | .icon-liuliang
113 |
114 |
115 |
116 | -
117 |
118 |
119 | 眼睛
120 |
121 | .icon-yanjing
122 |
123 |
124 |
125 | -
126 |
127 |
128 | 消息
129 |
130 | .icon-xiaoxi
131 |
132 |
133 |
134 | -
135 |
136 |
137 | 用户
138 |
139 | .icon-yonghu
140 |
141 |
142 |
143 |
144 |
145 |
font-class 引用
146 |
147 |
148 |
font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。
149 |
与 Unicode 使用方式相比,具有如下特点:
150 |
151 | - 兼容性良好,支持 IE8+,及所有现代浏览器。
152 | - 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
153 | - 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
154 | - 不过因为本质上还是使用的字体,所以多色图标还是不支持的。
155 |
156 |
使用步骤如下:
157 |
第一步:引入项目下面生成的 fontclass 代码:
158 |
<link rel="stylesheet" href="./iconfont.css">
159 |
160 |
第二步:挑选相应图标并获取类名,应用于页面:
161 |
<span class="iconfont icon-xxx"></span>
162 |
163 |
164 | "
165 | iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。
166 |
167 |
168 |
169 |
170 |
171 |
172 | -
173 |
176 |
流量
177 | #icon-liuliang
178 |
179 |
180 | -
181 |
184 |
眼睛
185 | #icon-yanjing
186 |
187 |
188 | -
189 |
192 |
消息
193 | #icon-xiaoxi
194 |
195 |
196 | -
197 |
200 |
用户
201 | #icon-yonghu
202 |
203 |
204 |
205 |
206 |
Symbol 引用
207 |
208 |
209 |
这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章
210 | 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:
211 |
212 | - 支持多色图标了,不再受单色限制。
213 | - 通过一些技巧,支持像字体那样,通过
font-size, color 来调整样式。
214 | - 兼容性较差,支持 IE9+,及现代浏览器。
215 | - 浏览器渲染 SVG 的性能一般,还不如 png。
216 |
217 |
使用步骤如下:
218 |
第一步:引入项目下面生成的 symbol 代码:
219 |
<script src="./iconfont.js"></script>
220 |
221 |
第二步:加入通用 CSS 代码(引入一次就行):
222 |
<style>
223 | .icon {
224 | width: 1em;
225 | height: 1em;
226 | vertical-align: -0.15em;
227 | fill: currentColor;
228 | overflow: hidden;
229 | }
230 | </style>
231 |
232 |
第三步:挑选相应图标并获取类名,应用于页面:
233 |
<svg class="icon" aria-hidden="true">
234 | <use xlink:href="#icon-xxx"></use>
235 | </svg>
236 |
237 |
238 |
239 |
240 |
241 |
242 |
261 |
262 |
263 |
--------------------------------------------------------------------------------
/src/assets/icon/iconfont.css:
--------------------------------------------------------------------------------
1 | @font-face {font-family: "iconfont";
2 | src: url('iconfont.eot?t=1551687312467'); /* IE9 */
3 | src: url('iconfont.eot?t=1551687312467#iefix') format('embedded-opentype'), /* IE6-IE8 */
4 | url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAARUAAsAAAAACKQAAAQHAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDMgqEPIQDATYCJAMUCwwABCAFhG0HThuVB8gekiSBEBQESIhQAUaIAForqx7YgQ0B6bADIhVWwBLBEwrHQjHvBWXy73aoTpsJ1QY9zvNY0dtkImwmNb9HIjjoKTw+zXTD9/85lnqZYPmv7Vyyak17Axwl0ICiS2i6gWyivGV4q0t12FcTUOpiFTgxt7ga8CTITgFhnclAAV7CJanoDnJBpeDIRDgmlUf7oyc46v18+GVE4BFJY2TP6WtzdCC9BhpuM4frey12ENTDBcAfR4xBgISwpTC0DjMoDcJUqn/HMhZQykWimlr72vKGq/N1NN2GLCX9h0cQiySECtLZCIzF5YQaS0qg1l5KTK1/QOTa1EjzYK6UghJV3AL8j1B6uV8QS0Wjq6Iiz1tXYZuir3bNOtXc+uE1waXPWVi/Zo1qv7mCdWcg3HdWWDe3VjmnCQhxZ0UWNK1fr6w65gjzzmjNGovXqzn9rCYQ2O6v9/trA4E6X2Jtr7d2z5Xhq3PXR65ZKtmGamHghU1YkSh/6qt2G+GmO7NXNHK/LqgmDXOhbk59+frCs0Gw93bMjmGvQHTgORx5Ebj9XOg7WDf39KbP1/py2DvrHwnMxYW2bWDGRVXbSYWtMG3Fwva1ysUPcwqV55drqHPs0ON72qc5KJvOtsjPpZpJWRiaeLLpe5WL7mblKLvaF1L7lINP7eXU2CudVu+N7Mv/0OVn4LWUyp210av/DSezYWM9zIRZYM8GSBExs2Bmw4cXXUldydaZQNzzjQVx9XtYVAW7vGiyLVDBojR5xr7xt7x3IQZtm2brlYsK+ajmxaL5SngDsOxjRfnyM/2nl3/hvc5dUV/pVvmunn9koh/2JqSXh14ZYq+ZsCovVZflnV42IeOa6V92Ow+P45ZeD716iRAUBluRZ8V7o+sQP4imqWMeitVAfWYpU/5D/I472o7yNmny37yagJfn5o95yToWaK56q2aq+vWrG85KNC1xp4ky3VIpkdToG2eK1AUlXnqshU/DWFo37iTItY4gkukMsVwvZIIdBKmqUVCRGwOlgfKOr2qJxhSSAgNMAATNHIdIE3ch1sxTZIL9CKk2fkFFs8CE0twQdMaqPsEkyKIxRbAOdfQgk9Zh15teIvC7K7HBY6XouNZj1WLabcqiiCHD0tU8bMf0EPu4Ow2RhOiRnnbYUC5cD1utDuSkHWasJaFGQpyJYUPXFn1SqNZhAwIT0DAKgekgHXogJloOdnpnfkKQ+f5KmIGHFYWumFGVrYXR3EyrRyKECm+AzDPZG824lOe4dTKIRBB6iB7NwQbJhQBmpSUHxFm8mRmmRYQydig4JQrDc+mbmkKnt9ju8QookT3TEIU4JCENFfk6k8fMU3YDt8fuN5vsBk63iXJYw5weh91g9AAAAA==') format('woff2'),
5 | url('iconfont.woff?t=1551687312467') format('woff'),
6 | url('iconfont.ttf?t=1551687312467') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
7 | url('iconfont.svg?t=1551687312467#iconfont') format('svg'); /* iOS 4.1- */
8 | }
9 |
10 | .iconfont {
11 | font-family: "iconfont" !important;
12 | font-size: 16px;
13 | font-style: normal;
14 | -webkit-font-smoothing: antialiased;
15 | -moz-osx-font-smoothing: grayscale;
16 | }
17 |
18 | .icon-liuliang:before {
19 | content: "\e600";
20 | }
21 |
22 | .icon-yanjing:before {
23 | content: "\e629";
24 | }
25 |
26 | .icon-xiaoxi:before {
27 | content: "\e619";
28 | }
29 |
30 | .icon-yonghu:before {
31 | content: "\e7bd";
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/src/assets/icon/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaotian2017/vue-cli3-admin/789182f5a9375628e3dd5b11cdd0e5777bdac0d3/src/assets/icon/iconfont.eot
--------------------------------------------------------------------------------
/src/assets/icon/iconfont.js:
--------------------------------------------------------------------------------
1 | !function(s){var e,l='',t=(e=document.getElementsByTagName("script"))[e.length-1].getAttribute("data-injectcss");if(t&&!s.__iconfont__svg__cssinject__){s.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(e){console&&console.log(e)}}!function(e){if(document.addEventListener)if(~["complete","loaded","interactive"].indexOf(document.readyState))setTimeout(e,0);else{var t=function(){document.removeEventListener("DOMContentLoaded",t,!1),e()};document.addEventListener("DOMContentLoaded",t,!1)}else document.attachEvent&&(n=e,c=s.document,o=!1,i=function(){o||(o=!0,n())},(l=function(){try{c.documentElement.doScroll("left")}catch(e){return void setTimeout(l,50)}i()})(),c.onreadystatechange=function(){"complete"==c.readyState&&(c.onreadystatechange=null,i())});var n,c,o,i,l}(function(){var e,t,n,c,o,i;(e=document.createElement("div")).innerHTML=l,l=null,(t=e.getElementsByTagName("svg")[0])&&(t.setAttribute("aria-hidden","true"),t.style.position="absolute",t.style.width=0,t.style.height=0,t.style.overflow="hidden",n=t,(c=document.body).firstChild?(o=n,(i=c.firstChild).parentNode.insertBefore(o,i)):c.appendChild(n))})}(window);
--------------------------------------------------------------------------------
/src/assets/icon/iconfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
39 |
--------------------------------------------------------------------------------
/src/assets/icon/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaotian2017/vue-cli3-admin/789182f5a9375628e3dd5b11cdd0e5777bdac0d3/src/assets/icon/iconfont.ttf
--------------------------------------------------------------------------------
/src/assets/icon/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaotian2017/vue-cli3-admin/789182f5a9375628e3dd5b11cdd0e5777bdac0d3/src/assets/icon/iconfont.woff
--------------------------------------------------------------------------------
/src/assets/icon/iconfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaotian2017/vue-cli3-admin/789182f5a9375628e3dd5b11cdd0e5777bdac0d3/src/assets/icon/iconfont.woff2
--------------------------------------------------------------------------------
/src/assets/img/tou.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaotian2017/vue-cli3-admin/789182f5a9375628e3dd5b11cdd0e5777bdac0d3/src/assets/img/tou.jpg
--------------------------------------------------------------------------------
/src/assets/js/common.js:
--------------------------------------------------------------------------------
1 | import {Message} from "element-ui";
2 | export const messages = function (type, message) {
3 | Message({
4 | type: type,
5 | message: message
6 | });
7 | };
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaotian2017/vue-cli3-admin/789182f5a9375628e3dd5b11cdd0e5777bdac0d3/src/assets/logo.png
--------------------------------------------------------------------------------
/src/assets/scss/global.scss:
--------------------------------------------------------------------------------
1 | $base-color:#bdb7ff;
2 | $base-white:white;
3 | $base-bule1:#4d79f6;
4 | $base-gray1:#f0f2f5;
5 | $base-ye:#F0B600;
6 | $base-green:#34A853;
7 | $base-pink:#E2918C;
8 | $base-f8:#f8f8f8;
9 | $base-666:#666;
10 |
--------------------------------------------------------------------------------
/src/components/TreeTable/eval.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: jianglei
3 | * @Date: 2017-10-12 12:06:49
4 | */
5 | 'use strict'
6 | import Vue from 'vue'
7 | export default function treeToArray(data, expandAll, parent = null, level = null) {
8 | let tmp = []
9 | Array.from(data).forEach(function(record) {
10 | if (record._expanded === undefined) {
11 | Vue.set(record, '_expanded', expandAll)
12 | }
13 | let _level = 1
14 | if (level !== undefined && level !== null) {
15 | _level = level + 1
16 | }
17 | Vue.set(record, '_level', _level)
18 | // 如果有父元素
19 | if (parent) {
20 | Vue.set(record, 'parent', parent)
21 | }
22 | tmp.push(record)
23 | if (record.children && record.children.length > 0) {
24 | const children = treeToArray(record.children, expandAll, record, _level)
25 | tmp = tmp.concat(children)
26 | }
27 | })
28 | return tmp
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/TreeTable/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | {{ scope.$index }}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | {{ scope.row[column.value] }}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
86 |
96 |
97 |
128 |
--------------------------------------------------------------------------------
/src/components/TreeTable/readme.md:
--------------------------------------------------------------------------------
1 | ## 写在前面
2 | 此组件仅提供一个创建TreeTable的解决思路
3 |
4 | ## prop说明
5 | #### *data*
6 | **必填**
7 |
8 | 原始数据,要求是一个数组或者对象
9 | ```javascript
10 | [{
11 | key1: value1,
12 | key2: value2,
13 | children: [{
14 | key1: value1
15 | },
16 | {
17 | key1: value1
18 | }]
19 | },
20 | {
21 | key1: value1
22 | }]
23 | ```
24 | 或者
25 | ```javascript
26 | {
27 | key1: value1,
28 | key2: value2,
29 | children: [{
30 | key1: value1
31 | },
32 | {
33 | key1: value1
34 | }]
35 | }
36 | ```
37 |
38 | #### columns
39 | 列属性,要求是一个数组
40 |
41 | 1. text: 显示在表头的文字
42 | 2. value: 对应data的key。treeTable将显示相应的value
43 | 3. width: 每列的宽度,为一个数字(可选)
44 |
45 | 如果你想要每个字段都有自定义的样式或者嵌套其他组件,columns可不提供,直接像在el-table一样写即可,如果没有自定义内容,提供columns将更加的便捷方便
46 |
47 | 如果你有几个字段是需要自定义的,几个不需要,那么可以将不需要自定义的字段放入columns,将需要自定义的内容放入到slot中,详情见后文
48 | ```javascript
49 | [{
50 | value:string,
51 | text:string,
52 | width:number
53 | },{
54 | value:string,
55 | text:string,
56 | width:number
57 | }]
58 | ```
59 |
60 | #### expandAll
61 | 是否默认全部展开,boolean值,默认为false
62 |
63 | #### evalFunc
64 | 解析函数,function,非必须
65 |
66 | 如果不提供,将使用默认的[evalFunc](./eval.js)
67 |
68 | 如果提供了evalFunc,那么会用提供的evalFunc去解析data,并返回treeTable渲染所需要的值。如何编写一个evalFunc,请参考[*eval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/components/TreeTable/eval.js)或[*customEval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customEval.js)
69 |
70 | #### evalArgs
71 | 解析函数的参数,是一个数组
72 |
73 | **请注意,自定义的解析函数参数第一个为this.data,第二个参数为, this.expandAll,你不需要在evalArgs填写。一定记住,这两个参数是强制性的,并且位置不可颠倒** *this.data为需要解析的数据,this.expandAll为是否默认展开*
74 |
75 | 如你的解析函数需要的参数为`(this.data, this.expandAll,1,2,3,4)`,那么你只需要将`[1,2,3,4]`赋值给`evalArgs`就可以了
76 |
77 | 如果你的解析函数参数只有`(this.data, this.expandAll)`,那么就可以不用填写evalArgs了
78 |
79 | 具体可参考[*customEval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customEval.js)的函数参数和[customTreeTable](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customTreeTable.vue)的`evalArgs`属性值
80 |
81 | ## slot
82 | 这是一个自定义列的插槽。
83 |
84 | 默认情况下,treeTable只有一行行展示数据的功能。但是一般情况下,我们会要给行加上一个操作按钮或者根据当行数据展示不同的样式,这时我们就需要自定义列了。请参考[customTreeTable](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customTreeTable.vue),[实例效果](https://panjiachen.github.io/vue-element-admin/#/table/tree-table)
85 |
86 | `slot`和`columns属性`可同时存在,columns里面的数据列会在slot自定义列的左边展示
87 |
88 | ## 其他
89 | 如果有其他的需求,请参考[el-table](http://element-cn.eleme.io/#/en-US/component/table)的api自行修改index.vue
90 |
--------------------------------------------------------------------------------
/src/components/showAside.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
29 |
30 |
--------------------------------------------------------------------------------
/src/element-variables.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Write your variables here. All available variables can be
3 | found in element-ui/packages/theme-chalk/src/common/var.scss.
4 | For example, to overwrite the theme color:
5 | */
6 | $--color-primary: #409EFF;
7 |
8 | /* icon font path, required */
9 | $--font-path: '~element-ui/lib/theme-chalk/fonts';
10 |
11 | @import "~element-ui/packages/theme-chalk/src/index";
12 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router/router'
4 | import store from './store/store'
5 | import './plugins/element.js'
6 | import './assets/css/normalize.css'
7 | import './assets/css/public.css'
8 | import '@/element-variables.scss'
9 | import {messages} from './assets/js/common'
10 | // import './assets/scss/global.scss'
11 | // 引入字体文件
12 | import '@/assets/icon/iconfont.css'
13 | Vue.config.productionTip = false
14 | //全局挂载提示框
15 | Vue.prototype.$message=messages
16 | new Vue({
17 | router,
18 | store,
19 | render: h => h(App)
20 | }).$mount('#app')
21 |
--------------------------------------------------------------------------------
/src/plugins/element.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Element from 'element-ui'
3 | import '../element-variables.scss'
4 |
5 | Vue.use(Element)
6 |
--------------------------------------------------------------------------------
/src/router/router.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import store from '../store/store'
4 | import NProgress from 'nprogress' //进度条
5 | import 'nprogress/nprogress.css'
6 | Vue.use(Router)
7 | // 路由懒加载
8 | const getComponent = (name,component) => () => import(`@/views/${name}/${component}.vue`);
9 | const myRouter=new Router({
10 | routes: [
11 | {
12 | path: '/',
13 | redirect: '/home',
14 | component: getComponent('login','index')
15 | },
16 | {
17 | path: '/login',
18 | name: 'login',
19 | component: getComponent('login','index')
20 | },
21 | {
22 | path: '/',
23 | component:getComponent('layout','Layout'),
24 | children:[{
25 | path:'/home',
26 | name:'home',
27 | component: getComponent('home','index'),
28 | meta:{title:'首页'}
29 | },
30 | {
31 | path:'/icon',
32 | component: getComponent('icons','index'),
33 | name:'icon',
34 | meta:{title:'自定义图标'}
35 | },
36 | {
37 | path:'/editor',
38 | component: getComponent('component','editor'),
39 | name:'editor',
40 | meta:{title:'富文本编译器'}
41 | },
42 | {
43 | path:'/countTo',
44 | component: getComponent('component','countTo'),
45 | name:'countTo',
46 | meta:{title:'数字滚动'}
47 | },
48 | {
49 | path:'/tree',
50 | component: getComponent('component','tree'),
51 | name:'tree',
52 | meta:{title:'自定义树'}
53 | },
54 | {
55 | path:'/treeTable',
56 | component: getComponent('component','treeTable'),
57 | name:'treeTable',
58 | meta:{title:'表格树'}
59 | },
60 | {
61 | path:'/treeSelect',
62 | component: getComponent('component','treeSelect'),
63 | name:'treeSelect',
64 | meta:{title:'下拉树'}
65 | },
66 | {
67 | path:'/draglist',
68 | component: getComponent('draggable','draglist'),
69 | name:'draglist',
70 | meta:{title:'拖拽列表'}
71 | },
72 | {
73 | path:'/dragtable',
74 | component: getComponent('draggable','dragtable'),
75 | name:'dragtable',
76 | meta:{title:'拖拽表格'}
77 | },
78 | {
79 | path:'/cricle',
80 | component: getComponent('charts','cricle'),
81 | name:'cricle',
82 | meta:{title:'饼图'}
83 | },
84 | ]
85 | }
86 | ]
87 | })
88 | //判断是否存在token
89 | myRouter.beforeEach((to,from,next)=>{
90 | NProgress.start()
91 | if (to.path !== '/login' && !store.state.token) {
92 | next('/login')
93 | NProgress.done() // 结束Progress
94 | }
95 | next()
96 | })
97 | myRouter.afterEach(() => {
98 | NProgress.done() // 结束Progress
99 | })
100 | export default myRouter
--------------------------------------------------------------------------------
/src/store/actions.js:
--------------------------------------------------------------------------------
1 | const actions={
2 |
3 | }
4 | export default actions
--------------------------------------------------------------------------------
/src/store/getters.js:
--------------------------------------------------------------------------------
1 | const getters={
2 |
3 | }
4 | export default getters
--------------------------------------------------------------------------------
/src/store/mutations.js:
--------------------------------------------------------------------------------
1 | const mutations = {
2 | //保存token
3 | COMMIT_TOKEN(state, object) {
4 | state.token = object.token;
5 | },
6 | //保存标签
7 | TAGES_LIST(state, arr) {
8 | state.tagsList = arr;
9 | },
10 | IS_COLLAPSE(state, bool) {
11 | state.isCollapse = bool;
12 | }
13 | }
14 | export default mutations
--------------------------------------------------------------------------------
/src/store/state.js:
--------------------------------------------------------------------------------
1 | const state = {
2 | token: '',
3 | role_id: '',
4 | tagsList: [], //打开的标签页个数,
5 | isCollapse: false, //侧边导航是否折叠
6 | }
7 | export default state
--------------------------------------------------------------------------------
/src/store/store.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import state from "./state";
4 | import mutations from "./mutations";
5 | import actions from "./actions";
6 | import getters from "./getters";
7 | //引入vuex 数据持久化插件
8 | import createPersistedState from "vuex-persistedstate"
9 | Vue.use(Vuex)
10 |
11 | export default new Vuex.Store({
12 | state,
13 | mutations,
14 | actions,
15 | getters,
16 | plugins: [createPersistedState()]
17 | })
18 |
--------------------------------------------------------------------------------
/src/views/charts/cricle.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
120 |
134 |
135 |
--------------------------------------------------------------------------------
/src/views/component/countTo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 数字滚动插件我们选择了vue-count-to,请参考相关
5 | 文档
9 |
10 |
11 | Vue CountTo
12 |
13 |
14 |
simple example
15 |
<count-to :startVal='0' :endVal='2018' :duration=4000></count-to>
16 |
23 |
start
24 |
change end-val
25 |
incremental update
26 |
27 |
28 |
count down example
29 |
<count-to :startVal='2017' :endVal='0' :duration=8000></count-to>
30 |
31 |
start
32 |
33 |
34 |
custom example
35 |
47 |
80 |
81 | <count-to :start-val='{{_startVal}}' :end-val='{{_endVal}}' :duration='{{_duration}}' :decimals='{{_decimals}}'
82 | :separator='{{_separator}}' :prefix='{{_prefix}}' :suffix='{{_suffix}}' :autoplay=false>
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
176 |
370 |
--------------------------------------------------------------------------------
/src/views/component/customEval.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: jianglei
3 | * @Date: 2017-10-12 12:06:49
4 | */
5 | 'use strict'
6 | import Vue from 'vue'
7 | export default function treeToArray(data, expandAll, parent, level, item) {
8 | const marLTemp = []
9 | let tmp = []
10 | Array.from(data).forEach(function(record) {
11 | if (record._expanded === undefined) {
12 | Vue.set(record, '_expanded', expandAll)
13 | }
14 | let _level = 1
15 | if (level !== undefined && level !== null) {
16 | _level = level + 1
17 | }
18 | Vue.set(record, '_level', _level)
19 | // 如果有父元素
20 | if (parent) {
21 | Vue.set(record, 'parent', parent)
22 | // 如果父元素有偏移量,需要计算在this的偏移量中
23 | // 偏移量还与前面同级元素有关,需要加上前面所有元素的长度和
24 | if (!marLTemp[_level]) {
25 | marLTemp[_level] = 0
26 | }
27 | Vue.set(record, '_marginLeft', marLTemp[_level] + parent._marginLeft)
28 | Vue.set(record, '_width', record[item] / parent[item] * parent._width)
29 | // 在本次计算过偏移量后加上自己长度,以供下一个元素使用
30 | marLTemp[_level] += record._width
31 | } else {
32 | // 如果为根
33 | // 初始化偏移量存储map
34 | marLTemp[record.id] = []
35 | // map中是一个数组,存储的是每级的长度和
36 | // 初始情况下为0
37 | marLTemp[record.id][_level] = 0
38 | Vue.set(record, '_marginLeft', 0)
39 | Vue.set(record, '_width', 1)
40 | }
41 | tmp.push(record)
42 | if (record.children && record.children.length > 0) {
43 | const children = treeToArray(record.children, expandAll, record, _level, item)
44 | tmp = tmp.concat(children)
45 | }
46 | })
47 | return tmp
48 | }
49 |
--------------------------------------------------------------------------------
/src/views/component/editor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
富文本编辑器是重要并且核心的功能,我们最终选择了vue2-editor,轻量高效,详细请见官方文档
4 |
5 |
6 |
7 |
38 |
39 |
58 |
59 |
--------------------------------------------------------------------------------
/src/views/component/tree.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 | 通过 node 获取
15 | 通过 key 获取
16 | 通过 node 设置
17 | 通过 key 设置
18 | 清空
19 |
20 |
21 |
22 |
23 |
120 |
128 |
--------------------------------------------------------------------------------
/src/views/component/treeSelect.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 输入模糊匹配:
5 |
23 | {{value}}
24 |
25 |
26 |
27 |
30 |
33 |
36 |
39 |
40 |
41 |
44 |
47 |
48 |
49 |
52 |
55 |
56 |
57 |
60 |
63 |
64 |
65 |
66 |
67 |
68 |
145 |
165 |
--------------------------------------------------------------------------------
/src/views/component/treeTable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Documentation
6 |
7 |
8 |
9 |
10 |
11 | {{ scope.row.event }}
12 | {{ scope.row.timeLine+'ms' }}
13 |
14 |
15 |
16 |
17 |
18 |
27 |
28 |
29 |
30 |
31 |
32 | 点击
33 |
34 |
35 |
36 |
37 |
38 |
39 |
139 |
--------------------------------------------------------------------------------
/src/views/draggable/draglist.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
本项目参考vueDraggable详细请参考文档
4 |
5 |
6 | {{item.name}}
7 |
8 |
9 | {{list}}
10 |
11 |
12 |
13 |
14 |
15 |
56 |
83 |
--------------------------------------------------------------------------------
/src/views/draggable/dragtable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | | Id |
8 | Name |
9 | Sport |
10 |
11 |
12 |
13 |
14 | | {{ item.id }} |
15 | {{ item.name }} |
16 | {{ item.sport }} |
17 |
18 |
19 |
20 |
21 |
22 | {{list}}
23 |
24 |
25 |
26 |
27 |
49 |
--------------------------------------------------------------------------------
/src/views/home/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
13 |
14 |
15 |
16 |
17 | - 用户
18 | -
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
36 |
37 |
38 |
39 |
40 | - 消息
41 | -
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
59 |
60 |
61 |
62 |
63 | - 今日访问
64 | -
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
82 |
83 |
84 |
85 |
86 | - 总访问量
87 | -
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | - 我的账户
103 | -
104 |
105 |
106 |
107 | zyh
108 |
109 | 超级管理员
110 |
111 |
112 | - 手机号:18111111111
113 |
114 | - 系统版本:1.0.0
115 | - 天气:晴
116 | - 当前时间:2019-03-05
117 | - 上次登陆:2019-03-05
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 | {{item.todo}}
140 |
141 |
142 |
143 |
144 |
145 |
146 |
269 |
413 |
414 |
--------------------------------------------------------------------------------
/src/views/icons/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | el-icon-upload
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | el-icon-error
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | el-icon-success
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | el-icon-warning
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | el-icon-sort-down
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | el-icon-sort-up
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | el-icon-arrow-left
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | el-icon-circle-plus
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | el-icon-circle-plus-outline
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | el-icon-arrow-down
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | el-icon-arrow-right
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | el-icon-arrow-up
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | el-icon-back
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | el-icon-circle-close
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 | el-icon-date
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 | el-icon-circle-close-outline
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 | el-icon-caret-left
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 | el-icon-caret-bottom
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 | el-icon-caret-top
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 | el-icon-caret-right
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 | el-icon-close
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 | el-icon-d-arrow-left
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 | el-icon-check
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 | el-icon-delete
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 | el-icon-d-arrow-right
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 | el-icon-document
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 | el-icon-d-caret
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 | el-icon-edit-outline
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 | el-icon-download
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 | el-icon-goods
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 | el-icon-search
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 | el-icon-info
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 | el-icon-message
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 | el-icon-edit
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 | el-icon-location
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 | el-icon-loading
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 | el-icon-location-outline
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 | el-icon-menu
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 | el-icon-minus
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 | el-icon-bell
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 | el-icon-mobile-phone
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 | el-icon-news
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 | el-icon-more
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 | el-icon-more-outline
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 | el-icon-phone
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 | el-icon-phone-outline
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 | el-icon-picture
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 | el-icon-picture-outline
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 | el-icon-plus
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 | el-icon-printer
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 | el-icon-rank
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 | el-icon-refresh
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 | el-icon-question
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 | el-icon-remove
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 | el-icon-share
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 | el-icon-star-on
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 | el-icon-setting
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 | el-icon-circle-check
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 | el-icon-service
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 | el-icon-sold-out
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 | el-icon-remove-outline
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 | el-icon-star-off
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 | el-icon-circle-check-outline
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 | el-icon-tickets
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 | el-icon-sort
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 | el-icon-zoom-in
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 | el-icon-time
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 | el-icon-view
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 | el-icon-upload2
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 | el-icon-zoom-out
631 |
632 |
633 |
634 |
635 |
636 |
637 |
640 |
674 |
675 |
--------------------------------------------------------------------------------
/src/views/layout/Layout.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
27 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/views/layout/components/Aside.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
40 |
41 |
42 |
152 |
174 |
--------------------------------------------------------------------------------
/src/views/layout/components/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
44 |
45 |
46 |
110 |
212 |
213 |
214 |
--------------------------------------------------------------------------------
/src/views/layout/components/Main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
19 |
--------------------------------------------------------------------------------
/src/views/layout/components/Tags.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
30 |
31 |
108 |
181 |
182 |
--------------------------------------------------------------------------------
/src/views/login/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 后台管理系统
7 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | 提交
23 | 重置
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
95 |
119 |
120 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | let path=require('path');
2 | function resolve(dir){
3 | return path.join(__dirname,dir)
4 | }
5 | module.exports = {
6 | chainWebpack: config => {
7 | //这里是对环境的配置,不同的环境对应不同的BASE_URL
8 | config.plugin('define').tap(args => {
9 | args[0]['process.env'].BASE_URL = JSON.stringify(process.env.BASE_URL)
10 | return args;
11 | });
12 | //设置别名
13 | config.resolve.alias
14 | .set('@',resolve('src'))
15 | },
16 | devServer: {
17 | open:true
18 | // 设置代理
19 | // lintOnSave: true,
20 | // devServer: {
21 | // proxy: {
22 | // // proxy all requests starting with /api to jsonplaceholder
23 | // '/api': {
24 | // target: 'http://test.jubao56.com/', //代理接口
25 | // changeOrigin: true,
26 | // pathRewrite: {
27 | // '^/api': '' //代理的路径
28 | // }
29 | // }
30 | // }
31 | // }
32 | // proxy: 'http://test.jubao56.com/'
33 | },
34 | //定义scss全局变量
35 | css: {
36 | loaderOptions: {
37 | sass: {
38 | data: `@import "@/assets/scss/global.scss";`
39 | }
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------