# heimatoutiao_admin **Repository Path**: Daazzer/heimatoutiao_admin ## Basic Information - **Project Name**: heimatoutiao_admin - **Description**: No description available - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-10-31 - **Last Updated**: 2021-01-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 黑马头条后台 ## 介绍 对[黑马头条前台](https://gitee.com/Daazzer/heimatoutiao)项目进行管理 - 项目页面 - 登录页面 - 欢迎页面 - 文章发布页 - 文章编辑页 - 文章表格数据页 - 项目使用技术 - [vue](https://github.com/vuejs/vue) - web 框架 - [vue-router](https://github.com/vuejs/vue-router) - 页面路由 - [element-ui](https://element.eleme.cn/#/zh-CN/) - UI 框架 - [axios](https://github.com/axios/axios) - http 请求 - [sass](https://github.com/sass/sass) - 预编译样式 - [vue-word-editor](https://github.com/hsian/vue-word-editor) - 富文本编辑 - 版本管理 - [git](https://git-scm.com/) - 项目 `src` 目录结构 ```powershell src ├─api # 项目服务器 api ├─assets # 静态资源目录 │ └─fonts ├─components # 项目封装的组件 ├─router # 视图路由 ├─styles ├─utils # 通用性 js 文件 └─views # 路由视图 └─index # 首页目录 ``` ## 使用方法 项目依赖安装 ``` npm install ``` 开发服务器,编译与热重载 ``` npm start ``` 编译打包到生产环境 ``` npm run build ``` ## 项目格式化配置 自定义的 vscode 编辑器配置:`/.vscode/settings.json` - 给函数名与函数括号之间添加一个空格 - 移除分号 ```json { "javascript.format.insertSpaceBeforeFunctionParenthesis": true, "javascript.format.semicolons": "remove" } ``` 自定义的 .editorconfig 配置文件:[`/.editorconfig` ](.editorconfig) [editorconfig 规范](https://editorconfig.org/) - 默认 `utf-8` 字符集 - 空格缩进类型 - 两个缩进 - 去掉行尾空格 - 空行结束 ```tex # 这个文件可以配合 vscode 的 editorconfig 插件自动格式化你指定好的文件 # http://editorconfig.org [*] charset = utf-8 indent_style = space end_of_line = lf [*.{js,jsx,ts,tsx,vue}] indent_size = 2 trim_trailing_whitespace = true insert_final_newline = true ``` ## 项目数据服务器 - 配置服务器基本路径:[@/utils/axios_http-config.js](src/utils/axios_http-config.js) - 服务器 api:[@/api](src/api) 服务器基地址配置例子: ```js import axios from 'axios' axios.defaults.baseURL = 'http://localhost:3000' export default axios ``` api 配置例子: ```js import axios from '@/utils/axios_http-config' /** * 文章列表 * @param {Object} [params] 参数对象 * @param {number} [data.category] 栏目id * @param {number} [data.pageIndex] 当前页码 * @param {number} [data.pageSize] 每页显示数据条数 * @returns {Promise} */ const getArticle = params => axios.get('/post', { params }).then(res => [null, res]).catch(err => [err]) /** * 发布文章 * @param {Object} data 参数对象 * @param {string} data.title 文章标题 * @param {string} data.content 文章内容 * @param {Array} data.categories 所属栏目ID集合 * @param {Array} data.cover 封面图片ID集合 * @param {number} data.type 1为文章,2为视频 * @returns {Promise} */ const publishArticle = data => axios.post('/post', data).then(res => [null, res]).catch(err => [err]) const getArticleById = id => axios.get(`/post/${id}`).then(res => [null, res]).catch(err => [err]) export default { getArticle, publishArticle, getArticleById } ``` 为了使用 api 时不使用引入,将 api 方法挂载到 vue 根实例原型上 [@/main.js](src/main.js) ```js import api from './api' Vue.prototype.$api = api ``` ## 项目路由 项目路由配置:[@/router](src/router) | URL | 描述 | | --------------------------- | --------------------------------- | | `/login` | [登录页](#LoginPage) | | `/index/welcome` | [欢迎页](#IndexWelcomePage) | | `/index/articleList` | [文章列表页](#articleListPage) | | `/index/articlePublish` | [文章发布页](#articlePublishPage) | | `/index/articlePublish/:id` | [文章编辑页](#articlePublishPage) | | `*` | [404 页面](#NotFoundPage) | ## 404 页面 考虑到如果什么页面都找不到,应该返回 404 页面 ### 添加 404 页的路由 ```js // ... const routes = [ // ... { name: 'NotFound', path: '*', component: () => import(/* webpackChunkName: "notFound" */ '@/views/NotFound.vue') } ] // ... ``` 404 页面视图:[@/views/NotFound.vue](src/views/NotFound.vue) ## 登录页的实现 [@/views/Login.vue](src/views/Login.vue) ### 添加登录页的路由 有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 [命名 chunk](https://webpack.js.org/guides/code-splitting-require/#chunkname),一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4),之后的部分与此相同。[参考](https://router.vuejs.org/zh/guide/advanced/lazy-loading.html#%E6%8A%8A%E7%BB%84%E4%BB%B6%E6%8C%89%E7%BB%84%E5%88%86%E5%9D%97) ```js const routes = [ // ... { name: 'Login', path: '/login', component: () => import(/* webpackChunkName: "login" */ '@/views/Login.vue') }, // ... ] ``` ### 实现登录页的视图结构 #### 登录效果图 ![登录页](src/assets/i/loginPage.png) #### 登录页模板 技术实现: - 使用 element-ui 的 `Container`、`Form`、`Avatar`、`FormItem`、`Input` 组件 ```vue ``` #### 登录页样式 技术实现: - 使用了 BEM 类名规范定义样式类名,配合 scss 的父选择器 ```vue ``` ### 实现登录页动态数据交互 技术实现: - 使用 `Form` 组件 `rules` 属性绑定[校验规则](https://github.com/yiminghe/async-validator) - 使用了 `Input` 组件的 `focus` 事件重置校验规则 - 输入框不能为空的限制 - 用户名要求为 4-5 位非空字符,或者是合法的 11 为手机号码 - 点击登录按钮会进行登录 - 如果验证不通过,则阻止登录,并在输入框底下出现提示 - 如果本地存储有 token,则表示已经登录,阻止登录,并提示用户 - 如果响应出错,则提示用户,并阻止登录 - 登录成功后,存储 token 到 `localStorage` 并且跳转路由到首页 ```vue ``` ## 设置路由守卫检测登录状态 [@/router](src/router) 技术实现: - vue-router 的[全局前置守卫方法](https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%85%A8%E5%B1%80%E5%89%8D%E7%BD%AE%E5%AE%88%E5%8D%AB) `router.beforeEach` 实现路由拦截 - 如果用户跳到非登录页,则都要检测是否有 token,如果没有,则强制跳回登录页 ```js // ... import { Message } from 'element-ui' // ... // 全局路由守卫 router.beforeEach((to, from, next) => { // 除了登录页,去其他页面都要验证 token const toRouteName = to.name const token = JSON.parse(localStorage.getItem('heimatoutiao_admin_userInfo') || '{}').token if (toRouteName !== 'Login' && !token && toRouteName !== 'NotFound') { Message.warning('你没有权限查看,请登录') next('/login') } next() }) // ... ``` ## 首页与欢迎页的实现 ### 添加首页与欢迎页路由 [@/router](src/router) 技术实现: - 欢迎页由首页嵌套着,所以欢迎页在 `Index` 的 `children` 属性下,默认首页和欢迎页一同显示 - 由于首页的结构是一个路由嵌套结构,所以包含多个子路由,所以专门建立了一个[index 目录](#directory)表示当前视图有多个子路由视图 - 用 [URL 正则](https://github.com/pillarjs/path-to-regexp) 匹配首页的路由,匹配 `/index` 或 `/index.html` 或 `/` - 给 `Index` 路由组件重定向到欢迎页,默认显示欢迎页 ```js // ... const routes = [ { name: 'Index', path: '/(index|index.html)?', redirect: '/index/welcome', component: () => import(/* webpackChunkName: "index" */ '@/views/index'), children: [ { name: 'Welcome', path: '/index/welcome', component: () => import(/* webpackChunkName: "index" */ '@/views/index/Welcome.vue') }, // ... ] } // ... ] // ... ``` ### 实现首页视图结构 [@views/index](src/views/index) #### 首页与欢迎页效果图 ![首页](src/assets/i/indexPage.png) #### 首页模板 技术实现: - 使用 `Container`、`Aside` 、`Header`、`Main` 划分页面结构 - 使用 `Image` 组件放置 logo - 使用 `Menu`、`SubMenu`、`MenuItem` 组件进行导航 - 使用 `Breadcrumb` 组件显示导航路径 ```vue ``` > **注意:** > > `Menu` 组件需要设置 `router` 属性为 `true` 时,才能点击 `MenuItem` 组件的 `index` 属性跳转页面 > > 当 Vue Loader 编译单文件组件中的 `