vue-admin 详细注释,必须手把手做项目系列之(一)
栏目: JavaScript · 发布时间: 6年前
内容简介:这是公司的一个项目的阉割版,可以用作模板,里面的技术点基本全部都有注释,全都有注释,全都有注释,重要事说三遍, 写注释很辛苦,给个小赞,github给个小start,鼓励鼓励码字的我,项目正在陆续的完善中。还有重申一点,我们是前端工程师,不是码农。麻雀虽小五脏俱全:[项目地址
这是公司的一个项目的阉割版,可以用作模板,里面的技术点基本全部都有注释,全都有注释,全都有注释,重要事说三遍, 写注释很辛苦,给个小赞,github给个小start,鼓励鼓励码字的我,项目正在陆续的完善中。还有重申一点,我们是前端工程师,不是码农。
麻雀虽小五脏俱全:[项目地址 github.com/whylisa/vue… )
项目功能
- 1 登录
- 2 首页
- 3 退出
- 4 table页
项目技术点
- 1,使用vue
- 2,使用echarts
- 3, 使用json-server (系列二写详细文档)
- 4, 使用node起一个简单的服务,服务于接口(系列二写详细文档)
- 5, 使用axios
- 6, vue-router的使用规则(异步加载,和同步加载)
- 7, 回话拦截的使用(localstorage or cookie)
- 8, 配合element-UI
- 9, 修改组件里面的样式里面的坑
- 10, 打包时的优化
- 11, DNS优化
- 12, 配置本地代理,使用接口(系列二写详细文档)
- 13, 使用axios配合json-server 模拟增删改查(系列二写详细文档)
- 14, 使用nprogress 插件
- 15, 鲜为人知的element-UI 的滚动条
- 16, 栅格布局,大小屏适应配合媒体查询
- 17, css使用less
- 18, 代码风格,个人风格,禁用了jslint 防止不懂得小伙伴抓狂
- 19, 兼容性的处理(系列二写详细文档)
项目搭建
-
1
vue init webpack XX
使用vue-cli 2.0
Project name :默认 Project description :默认 Author :默认 Vue build :选择 Runtime + Compiler Install vue-router? :Y Use ESLint to lint your code? :Y 选择 Standard Set up unit tests :n Setup e2e tests with Nightwatch? : n Should we run `npm install` for you after the project has been created? (recommended) : Yes, use NPM 复制代码
- 2 进入项目:cd vue-admin-stepbystep
- 3 运行项目:npm run dev
如何添加一个新的功能???
components router/index.js
在项目中使用 element-ui(其他自行gg加深映像)
- ElementUI 文档
-
安装:
npm i element-ui -S
// main.js // 导入elementui - js import ElementUI from 'element-ui' // 导入elementui - css import 'element-ui/lib/theme-chalk/index.css' // 安装插件 Vue.use(ElementUI) 复制代码
项目启动做了什么
-
1 在终端中运行:
npm run dev
,实际上就是运行了:webpack-dev-server ...
- 2 使用 webpack-dev-server 开启一个服务器
-
3 根据指定的入口
src/main.js
开始分析入口中使用到的模块 -
4 当遇到
import
的时候,webpack 就会加载这些模块内容(如果有重复模块,比如:Vue,实际上将来只会加载一次),遇到代码就执行这些代码 - 5 创建 Vue 实例,将 App 组件作为模板进行编译,并且将 App 组件中 template 的内容渲染在页面 #app 的位置
路由配置
- 1 异步加载路由
- 2 使用进度条插件
- 3 登录拦截 会话保持
import Vue from 'vue' import Router from 'vue-router' //引入nprogress进度条 import NProgress from 'nprogress' //引入nprogress进度条的样式 import 'nprogress/nprogress.css' //在打包过程中每一个组件都会打包成一个js文件,如果不使用使用/* webpackChunkName: "home" */ //在打包的时候就会生成0.js,1.js等等,使用了之后就会打包成home.js // 导入 Login 组件(注意,不要添加 .vue 后缀) //这是路由的异步加载,!important,这是优化项目必须的 //引入home组件 const Home = () => import(/* webpackChunkName: "home" */ '@/components/home') //引入登录组件 const Login = () => import(/* webpackChunkName: "home" */ '@/components/login') //引入table组件 const Table = () => import(/* webpackChunkName: "home" */ '@/components/table/table') //引入homeMain组件 const HomeMain = () => import('@/components/HomeMain') //这里是同步加载 //import Login from '@/components/login/Login' Vue.use(Router) const router = new Router({ mode: 'history',//开启了history模式,去除了#, // 在vue中,一般来说通过实例去访问某个属性的 // vm.xxxx vm.$set vm.$refs vm.$router routes: [ { path: '/', redirect: '/homeMain'//路由的重定向 }, { path: '/login', name: 'login', component: Login }, { path: '/home', name: 'home', component: Home, // children 用来配置子路由,将来匹配的组件会展示在 Home 组件的 router-view 中 // 对于子路由path来说: // 1 如果不是以 / 开头,那么,哈希值为: 父级path + / + 子级path // 也就是: /home/homeMain // 2 如果子级路由的path是以 / 开头的,那么将来的哈希值为:/users 不再带有父级的path了 // 也就是:/homeMain //这是页面中的子路由,在页面中必须声明router-view作为出口 children: [ { path: '/homeMain', name: 'homeMain', component: HomeMain }, { path: '/table', name: 'table', component:Table } ] } ] }); // 给router配置导航守卫 // to: 去哪儿 // from: from 哪儿来 // next() : next():放行 next('/login') 去login组件 // 在登录成功以后,将 token 存储到 localStorage 中 // 在 导航守卫 中先判断当前访问的页面是不是登录页面 // 如果是登录页面,直接放行(next()) // 如果不是登录页面,就从 localStorage 中获取 token,判断有没有登录 // 如果登录了,直接放行(next()) // 如果没有登录,就跳转到登录页面让用户登录(next('/login') router.beforeEach((to, from, next) => { // 开启进度条 NProgress.start() // 获取是否有token let token = localStorage.getItem('myToken') // 如果已经就是要去login了,就不需要拦截了 if (to.path === '/login' || token) { next() }else { next('/login') } }); router.afterEach(() => { // 关闭进度条 NProgress.done() }) export default router 复制代码
登录功能
npm i -S axios Login.vue
<div class="l-right"> <div class="l-l"> <!-- @tab-click="handleClick" --> <el-tabs v-model="activeName"> <el-tab-pane label="用户登录" name="first"> <!-- el-form:自定义表单组件 --> <!-- :model="form" 表单对象,用于收集收据 --> <!-- label-width="80px":label的宽度 --> <!-- el-form-item:表单项 --> <el-form ref="form" status-icon :rules="rules" :model="form" label-width="80px"> <el-form-item prop="username"> <el-input v-model="form.username" placeholder="请输入用户名" prefix-icon="iconfont icon-yonghuming"></el-input> </el-form-item> <el-form-item prop="password"> <!-- 将来我们给组件注册事件的时候,可以会注册不上 --> <!--@keyup.enter点击键盘的enter触发事件--> <!-- .native: 注册事件,给组件的根元素注册事件 --> <el-input type="password" v-model="form.password" placeholder="请输入密码" @keyup.enter.native="login" prefix-icon="iconfont icon-mima"></el-input> </el-form-item> <el-form-item> <!--使用@语法糖绑定事件--> <el-button type="primary" @click="login">登录</el-button> <el-button @click="reset">重置</el-button> </el-form-item> </el-form> </el-tab-pane> <el-tab-pane label="帅哥登录" name="second">长得很帅</el-tab-pane> </el-tabs> </div> </div> </div> 复制代码
export default { data () { return { // 定义一些变量,可以使用{{}}语法在页面中直接获取 activeName: 'first', form: { username: 'why', password: "123456" }, rules: { // 用户名的校验 username: [ // 用户名是必须 // required是否必须 // message提示信息 // trigger如何触发 { required: true, message: '请输入用户名', trigger: 'change' }, { min: 3, max: 6, message: '长度在 3 到 6 个字符', trigger: 'change' } ], // 密码的校验 password: [ { required: true, message: '请输入密码', trigger: 'change' }, { min: 6, max: 12, message: '长度在 6 到 12 个字符', trigger: 'change' } ] } } }, methods: { login () { // 先触发页面中的检验规则,不通过给提示,通过就向后台发送请求, // $refs是vue中获取页面的,在html中要写 ref="form" this.$refs.form.validate(async (valid) => { if (valid) { // 使用axios向后台发送请求 // 在es6中的箭头函数没有this绑定,可以打印出来指向的是vue实例,这点可以自行百度,加深映像 this.axios('/api/login').then( res => { console.log(res.data[0])//用来查看接口里面的数据 let lg = res.data[0] //把数据赋值给变量 console.log(lg.username,lg.password)//主要用来查看数据 if(lg.username === this.form.username && lg.password==this.form.password){ localStorage.setItem('myToken',lg.username)//设置拦截,可以用cookie等,在控制台中的Application中查看 this.$message.success('恭喜你,登录成功')//登录成功的提示 this.$router.push('homeMain') //使用编程式导航路由进行跳转 }else { this.$message.error('账号或者密码错误')//账号密码错误时的提示 } }) } }) }, reset () { this.$refs.form.resetFields()//清空输入框中的信息 // 数据被我写死了,可以自行改动 } } }; 复制代码
顶部和侧边
<el-container> <!--给el-header设置 高度--> <el-header style="height: 70px;"> <div class="logo"> <!--这里可以放一般网站的logo--> <!--<img src="../assets/main/logo.png" alt="">--> </div> <div class="header-right"> <div class="logout" @click="layout"> <!--javascript:;为了防止a标签的默认行为,--> <a href="javascript:;">退出</a> </div> <div class="people"> <!--映入iconfont 的字体图标--> <i class="iconfont icon-lianxirenwode"></i> 张三 </div> <div class="call"> <i class="iconfont icon-lianxiwomen"></i> 联系我们 </div> </div> </el-header> <el-container> <el-aside width="160px" background-color="#26292E"> <el-scrollbar style="height: 100%;"> <!-- el-menu: 导航菜单的组件 --> <!-- default-active:默认高亮的菜单 --> <!-- open close 展开和关闭的事件 --> <!-- el-submenu: 子菜单 --> <!-- el-menu-item-group: 子菜单中分组 --> <!-- el-menu-item:子菜单中的每一项 --> <!-- unique-opened: 保证只能打开一个子菜单 --> <!-- router: 如果router为true,那么index就会作为路由的连接 --> <el-menu :unique-opened='true' :router="true" text-color="#ffffff" active-text-color="#cccccc"> <el-submenu index="1"> <template slot="title"><i class="iconfont icon-shouye"></i> <span @click="gomain"> 首页 </span> </template> </el-submenu> <el-submenu index="2"> <template slot="title"><i class="iconfont icon-message-channel"></i>table</template> <el-menu-item-group> <el-menu-item index="/table">table</el-menu-item> </el-menu-item-group> </el-submenu> </el-menu> </el-scrollbar> </el-aside> <el-container> <!--使用element的自带的滚动条,官方文档没有--> <el-scrollbar style="height: 100%;width: 100%;"> <el-main> <keep-alive> <!-- 这里是会被缓存的视图组件 --> <!-- $route.meta.keepAlive:如果是true, 说明是缓存组件,通过keep-alive这个标签把缓存组件显示出来 --> <router-view v-if="$route.meta.keepAlive"> </router-view> </keep-alive> <!-- 这里是不被缓存的视图组件 --> <router-view v-if="!$route.meta.keepAlive"> </router-view> </el-main> </el-scrollbar> </el-container> </el-container> </el-container> 复制代码
export default { created() { }, data() { return { } }, methods: { gomain() { //编程式导航 this.$router.push('/homeMain') }, //退出功能 layout() { // 退出功能要移除localStorage中的myToken localStorage.removeItem('myToken') // 跳转到首页 this.$router.push('login') // 退出成功提示 this.$message.success('退出成功了') }, }, } 复制代码
首页
- 代码有点多截取一点,主要对echarts做了修改,x轴箭头呀,修改柱状图的样式呀等,还有element的栅格布局配合媒体查询
xAxis: { data: ["三月", "四月", "五月", "六月", "七月"], axisLine: { symbol: ['none', 'arrow'], lineStyle: { color: 'rgba(212,212,212,1)', // x坐标轴的轴线颜色 width: 1 //这里是坐标轴的宽度,为0就是不显示 } } }, yAxis: [{ type: 'value', axisLabel: { show: false //这行代码控制着坐标轴x轴的文字是否显示 }, splitLine: { show: false, // 网格线是否显示 // 改变样式 lineStyle: { color: '#EDEDED' // 修改网格线颜色 } }, axisLine: { lineStyle: { color: '#fff', // x坐标轴的轴线颜色 width: 0 //这里是坐标轴的宽度,为0就是不显示 } } }], 复制代码
表格的使用
<div class="table"> <div class="t-top"> <!--使用el-input 要注意,他默认占父级100%的宽度--> <el-input v-model="query" placeholder="请输入内容"></el-input> <!--el-button 绑定点击事件向后台发送数据查询--> <!--在此处通常会涉及到模糊查询,此时我们还需要绑定keyup事件,向后台请求数据,然后渲染一个小的下拉框,我们需要做的是发送查询的字段给后台, 后台使用 sql 语句模糊查询,我们渲染就可以--> <el-button type="primary" @click="search">查询</el-button> </div> <div class="t-bottom"> <!-- el-table:表格组件 --> <!-- :data='tableData' 表格显示的数据 --> <!-- el-table-column:表格的一列 --> <!-- prop: 当前列要显示的数据 ,tableData内的数据--> <!-- label:表头 --> <!-- width: 这一列的宽度 --> <!--min-width:用来设置百分比--> <!--:header-cell-style="{background:'red'}"--> <!--align="center"表格内的数据居中--> <el-table :data="tableData" style="width: 100%" :header-cell-style="{background:'red'}" > <el-table-column prop="date" label="日期" align="center" width="180"> </el-table-column> <el-table-column prop="name" label="姓名" align="center" width="180"> </el-table-column> <!--如果不设置百分比,就自动分配剩余的宽度--> <el-table-column prop="address" align="center" label="地址"> </el-table-column> </el-table> </div> </div> 复制代码
export default { data() { return { // 绑定的input 查询关键字 query: '', // 需要一个数组用来存放table的数据 // 这是element组件里面的, tableData: [] } }, mounted() { // 在vue的生命周期的mounted中调用渲染列表 this.initTable() }, methods:{ initTable() { this.axios('/api/table').then( res => { console.log(res.data)//查看接口返回时什么样的数据,要常用 this.tableData = res.data //接口返回的是一个数组,直接可以赋值给table }) }, search() { } } } 复制代码
改element-ui的样式注意!
<!--使用scoped需要注意,使用的它之后,你就无法更改elelment组件中的样式--> <style lang="less" scoped="scoped"> /*如果不想使用scoped,你就用父级的class把样式全部包裹起来,就不会相互影响页面的样式了*/ 复制代码
以下是一些概念性的东西,其他的功能系列二将会陆续完善
编程式导航
- 就是通过 JS 代码来实现路由的跳转功能
// 注意:是 router 不是 route // router用来实现路由跳转,route用来获取路由参数 // push 方法的参数为:要跳转到的路由地址(path) this.$router.push('/home') 复制代码
密码
- 给输入框组件添加 type="password" 就变为密码框状态了
<el-input type="password" v-model="loginForm.password"></el-input> 复制代码
登录拦截
- 说明:在没有登录的情况不应该让用户来访问除登录以外的任何页面
登录和拦截的整个流程说明
- 1 在登录成功以后,将 token 存储到 localStorage 中
- 2 在 导航守卫 中先判断当前访问的页面是不是登录页面
- 3 如果是登录页面,直接放行(next())
- 4 如果不是登录页面,就从 localStorage 中获取 token,判断有没有登录
- 5 如果登录了,直接放行(next())
- 6 如果没有登录,就跳转到登录页面让用户登录(next('/login'))
token 机制的说明
- 在项目中,如果登录成功了,那么,服务器会给我们返回一个 token
- 这个 token 就是登录成功的标识
- 这个 token 就相当于使用 cookie+session 机制中的 sessionid
公司人员和项目开发流程
- 1 产品经理定制项目的需求
- 2 分配任务:先将所有的任务分配到项目组,然后,再由项目组具体分配给每个开发人员
- 3 开发:拿到 产品原型 + 需求文档 + UI 设计稿 资料,转化为 HTML 页面,完成功能
- 4 功能完成后,自己测试有没有 Bug
- 5 由测试人员来测试你的功能,当测试出 Bug 后,就会通过 禅道 这样的项目管理系统,来提出 Bug
- 6 由 自己 修改 测试人员提出来的 bug
- 7 最终,没有 bug 了,项目才会上线
产品经理(Product Manager) 提需求 产出: 产品原型 + 需求文档 原型设计软件:Axure 、墨刀 UI(设计) 将 产品经理 给的 原型图 设计为 好看的UI稿 FE(前端)front-end 产品原型 + 需求文档 + UI设计稿 ===> HTML页面 BE(后端) back-end 给前端提供数据接口 测试人员 产品原型 + 需求文档 + UI设计稿 来测试我们写的功能 发现你的功能 与 需求 不一致,那就说明除Bug了,那么,测试人员就会提Bug Bug系统: 禅道 项目经理(管理技术) 技术攻坚,与其他项目组人员沟通,分配任务 等 复制代码
vue 单文件组件中的 scoped
-
作用:给
style
标签添加scoped
属性以后,样式只会对当前组件中的结构生效,而不会影响到其他组件
vue 单文件组件中的 lang
lang="less" npm i -D less less-loader
VSCode 中使用 Vetur 插件格式化单文件组件的 template
-
打开设置,配置:
"vetur.format.defaultFormatter.html": "js-beautify-html"
接口调用的说明
- 注意: 所有接口都需要传递 token,只有传递了正确的 token,服务器才会将数据返回给前端
-
如果没有传递
token
,服务器会返回401
,告诉接口调用者,没有权限来访问这个接口
cookie+session VS token
Git 使用
# 克隆仓库 git clone [仓库地址] # 推送 git push [仓库地址] master # 简化推送地址 git remote add XX [仓库地址] git push -u XX master # 第一次执行上面两条命令,以后只需要输入以下命令即可 git push XX # 拉取 git pull [仓库地址] master git pull XX master 复制代码
路由参数分页
-
1 配置分页路由参数, 参数是可选的
-
参数可选后, 路由就能够匹配:
/XX
或者/XX/3
-
参数可选后, 路由就能够匹配:
- 2 使用路由来分页, 有两种情况需要处理:
- 3 第一种: 进入页面,就要根据当前路由参数中的页码,来获取到对应页的数据
-
4 第二种: 点击分页组件获取数据, 需要做两件事:
- 4.1 获取到当前页的数据( 调用获取数据的方法 )
- 4.2 修改哈希值为当前页码 ( this.$router.push() )
-
5 点击分页按钮获取数据的第二种思路:
$route(to) {}
项目打包和优化
-
打包命令:
npm run build
按需加载
-
1 修改
router/index.js
中导入组件的语法
// 使用: const Home = () => import('@/components/home/Home') // 替换: // import Home from '@/components/home/Home' // 给打包生产的JS文件起名字 const Home = () => import(/* webpackChunkName: 'home' */ '@/components/home/Home') // chunkName相同,将 goods 和 goods-add 两个组件,打包到一起 const XX = () => import(/* webpackChunkName: 'XX' */'@/components/XX') const XXX = () => import(/* webpackChunkName: 'XX' */'@/components/XXX') 复制代码
-
2 ( 该步可省略
)修改
/build/webpack.prod.conf.js
中的chunkFilename
{ // [name] 代替 [id] chunkFilename: utils.assetsPath('js/[name].[chunkhash].js') } 复制代码
使用CDN
-
1 在
index.html
中引入CDN提供的JS文件 -
2 在
/build/webpack.base.conf.js
中(resolve前面)添加配置 externals -
注意:通过CDN引入 element-ui 的样式文件后,就不需要在 main.js 中导入 element-ui 的CSS文件了。所以,直接注释掉 main.js 中的导入 element-ui 样式即可
-
externals
配置:
externals: { // 键:表示 导入包语法 from 后面跟着的名称 // 值:表示 script 引入JS文件时,在全局环境中的变量名称 vue: 'Vue', axios: 'axios', 'vue-router': 'VueRouter', 'element-ui': 'ELEMENT', moment: 'moment', echarts: 'echarts', } import ElementUI from 'element-ui' 复制代码
常用包CDN
-
说明:
https://www.bootcdn.cn/
<!-- Include the Quill library --> <script src="https://cdn.bootcss.com/quill/1.3.4/quill.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <!-- Quill JS Vue --> <script src="https://cdn.jsdelivr.net/npm/vue-quill-editor@3.0.4/dist/vue-quill-editor.js"></script> <!-- Include stylesheet --> <link href="https://cdn.bootcss.com/quill/1.3.4/quill.core.min.css" rel="stylesheet"> <link href="https://cdn.bootcss.com/quill/1.3.4/quill.snow.min.css" rel="stylesheet"> <link href="https://cdn.bootcss.com/quill/1.3.4/quill.bubble.min.css" rel="stylesheet"> 复制代码
移除console
new webpack.optimize.UglifyJsPlugin({ compress:{ warnings: false, drop_debugger: true, drop_console: true } }) 复制代码
缓存和保留组件状态
- keep-alive
-
解决方式:使用
keep-alive
,步骤如下:
1 在需要被缓存组件的路由中添加 meta 属性 meta 属性用来给路由添加一些元信息(其实,就是一些附加信息) { path: '/', name: 'home', component: Home, // 需要被缓存 meta: { keepAlive: true } } 2 修改路由出口,替换为以下形式: 根据 meta 是否有 keepAlive 属性,决定该路由是否被缓存 <keep-alive> <!-- 这里是会被缓存的视图组件 --> <router-view v-if="$route.meta.keepAlive"> </router-view> </keep-alive> <!-- 这里是不被缓存的视图组件 --> <router-view v-if="!$route.meta.keepAlive"> </router-view> 复制代码
启用路由的 History 模式
mode: 'history'
// 去掉 # 后,地址变为: http://localhost:1111/home 那么,服务器需要正确处理 /goods 才能正确的响应内容, 但是,/home 不是服务端的接口,而是 用来在浏览器中实现 VueRouter 路由功能的 复制代码
以上所述就是小编给大家介绍的《vue-admin 详细注释,必须手把手做项目系列之(一)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- vue-admin 详细注释,必须手把手做项目系列之(二)
- YII2项目中重写PhpStorm中对方法function的注释代码
- iOS 注释方法大全 代码块加快捷键注释
- 让 MyBatis Generator 用数据库注释作 Java 注释,并支持附加注解
- 请停止代码注释
- 体面编码之代码注释评论
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Software Engineering for Internet Applications
Eve Andersson、Philip Greenspun、Andrew Grumet / The MIT Press / 2006-03-06 / USD 35.00
After completing this self-contained course on server-based Internet applications software, students who start with only the knowledge of how to write and debug a computer program will have learned ho......一起来看看 《Software Engineering for Internet Applications》 这本书的介绍吧!