复习
- 熟悉ElementUI
- 前后端通信
- formatter 绑定函数
- 日期处理
- 分页
- js发展
- 服务端、桌面端、web端、app端
- nodejs js运行时环境,脱离web浏览器运行js
- js现代工具链
- nodejs
- npm 包管理器,管理依赖
- webpack 打包工具,构建工具
- 现代前端技术
- pug
- sass / less
- coffeescript / typescript
- npm命令
- npm -v
- npm init 创建一个node项目
- npm install 安装一个依赖
-g全局安装 - npm run 运行指令
- package.json文件 类似于maven中的pom.xml
- 坐标
- 依赖
- 脚本命令 serve
- vue-cli 脚手架工具
- vue create / vue ui
解析脚手架项目
node_modules node下载的依赖
public
src 源码
- assets 图片等资源
- components 组件
- router 路由配置
- views 视图,界面
- App.vue 应用的容器
- main.js 整个项目的入口 ```javascript //从vue依赖包当中导入Vue对象 import Vue from ‘vue’ //导入一个组件App import App from ‘./App.vue’ //导入vue-router,路由器 import router from ‘./router’
//关闭生产环境 Vue.config.productionTip = false
//实例化vue new Vue({ router, //引入路由器 render: h => h(App)//渲染App组件 }) .$mount(‘#app’)//挂载到App组件内部id为app的元素上
package.json 项目管理文件约定:<br />在文件夹下的index.js, 当引入文件夹时,默认读取index.js<a name="pAMB6"></a>## 包js内部,封装多个方法或者类的一个工具,类似于java包<br />在包内部,导出数据和方法```javascriptfunction helloPlus(){hello();}function hello(){alert('123');}//导出的内容export default {delta : 1.99,sayHello: helloPlus}
需要使用时,引入
import a from './a.js'a.sayHello();
单文件组件 .vue文件
before :
Vue.component('todo-item',{template:`<li style="list-style:none"><input type="checkbox" name="" v-model="todo.state" id=""><span contenteditable @keydown.esc='handleCancel' @focus="save" @blur='handleChange' >{{todo.text}}</span><span style='color:red;cursor:pointer' @click='del(todo)'>x</span></li>`,//html的内容props:['todo'],//属性,data:function(){return {prev:this.todo.text}},methods:{del(todo){this.$emit("del",todo);//(1)在组件内触发一个自定义的事件,名为del,事件对象(事件内容)todo},handleChange(e){console.log("changing:"+this.prev +" canceled:"+this.canceled)this.todo.text=e.target.innerText;},handleCancel(e){console.log("cancel:"+this.prev)this.todo.text=this.prev;e.target.innerText=this.prev;e.target.blur();},save(){console.log("saving:"+this.todo.text)this.prev=this.todo.text}},mounted(){}});
after:
现在我们获得:
一个 .vue 文件,就是一个组件
vue-router 路由器
单页面应用 Single Page Application SPA
不切换页面的情况下更新内容,极佳的用户体验,类似于App的使用体验,成为潮流
map.baidu.com
juejin.im
实例
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><div id="app"><!-- 使用 router-link 组件来导航. --><!-- 通过传入 `to` 属性指定链接. --><!-- <router-link> 默认会被渲染成一个 `<a>` 标签 --><router-link to='/idx'>首页</router-link><router-link to='/ctr'>个人中心</router-link><!-- 路由出口 --><!-- 路由匹配到的组件将渲染在这里 --><router-view></router-view></div><script src="https://unpkg.com/vue/dist/vue.js"></script><script src="https://unpkg.com/vue-router/dist/vue-router.js"></script><script>//1. 定义两个组件let index = Vue.component('index',{template:'<div><h1>首页</h1></div>'});let center = Vue.component('center',{template:'<div><h1>个人中心</h1></div>'});//2. 定义路径与组件之间的映射关系const routes=[{path:'/idx',component:index},{path:'/ctr',component:center}]//3. 创建路由对象const router = new VueRouter({routes});//4.将路由对象设置到Vue实例中,使之生效new Vue({router}).$mount('#app');</script></body></html>
动态路由
根据路径动态匹配组件
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><div id="app"><!-- 使用 router-link 组件来导航. --><!-- 通过传入 `to` 属性指定链接. --><!-- <router-link> 默认会被渲染成一个 `<a>` 标签 --><router-link to='/idx'>首页</router-link><router-link to='/ctr'>个人中心</router-link><router-link to='/product/bottle'>产品介绍</router-link><!-- 路由出口 --><!-- 路由匹配到的组件将渲染在这里 --><router-view></router-view></div><script src="https://unpkg.com/vue/dist/vue.js"></script><script src="https://unpkg.com/vue-router/dist/vue-router.js"></script><script>//1. 定义两个组件let index = Vue.component('index',{template:'<div><h1>首页</h1></div>'});let center = Vue.component('center',{template:'<div><h1>个人中心</h1></div>'});let product = Vue.component('product',{template:'<div><h1>产品介绍:{{$route.params.productName}}</h1></div>'});//2. 定义路径与组件之间的映射关系const routes=[{path:'/idx',component:index},{path:'/ctr',component:center},{path:'/product/:productName',component:product}]//3. 创建路由对象const router = new VueRouter({routes});//4.将路由对象设置到Vue实例中,使之生效new Vue({router}).$mount('#app');</script></body></html>
嵌套路由
在组件内部存在路由链接及路由视图
在routes路由表中使用children表示嵌套的路由关系
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><div id="app"><!-- 使用 router-link 组件来导航. --><!-- 通过传入 `to` 属性指定链接. --><!-- <router-link> 默认会被渲染成一个 `<a>` 标签 --><router-link to='/idx'>首页</router-link><router-link to='/ctr'>个人中心</router-link><!-- 路由出口 --><!-- 路由匹配到的组件将渲染在这里 --><router-view></router-view></div><script src="https://unpkg.com/vue/dist/vue.js"></script><script src="https://unpkg.com/vue-router/dist/vue-router.js"></script><script>//1. 定义两个组件let index = Vue.component('index',{template:'<div><h1>首页</h1></div>'});let center = Vue.component('center',{template:`<div><h1>个人中心</h1><!-- 嵌套路由的链接 --><router-link to='/center/intro'>intro</router-link><router-link to='/center/modify'>modify</router-link><!-- 嵌套路由的出口 --><router-view></router-view></div>`});//嵌套路由的组件let intro = Vue.component('intro',{template:`<h2>个人介绍:大帅哥一个</h2>`})let modify = Vue.component('modify',{template:`<h2>修改个人信息</h2>`})//2. 定义路径与组件之间的映射关系const routes=[{path:'/idx',component:index},{path:'/ctr',component:center,children:[{path:'/center/intro', component: intro},{path:'/center/modify', component: modify}]},]//3. 创建路由对象const router = new VueRouter({routes});//4.将路由对象设置到Vue实例中,使之生效new Vue({router}).$mount('#app');</script></body></html>
编程式路由导航
调用this.$router.push方法进行跳转
- 直接传链接
传对象 ```html <!DOCTYPE html>
<!-- 使用 router-link 组件来导航. --><!-- 通过传入 `to` 属性指定链接. --><!-- <router-link> 默认会被渲染成一个 `<a>` 标签 --><router-link to='/login'>登录</router-link><router-link to='/reg'>注册</router-link><!-- 路由出口 --><!-- 路由匹配到的组件将渲染在这里 --><router-view></router-view>
</div><script src="https://unpkg.com/vue/dist/vue.js"></script><script src="https://unpkg.com/vue-router/dist/vue-router.js"></script><script>//1. 定义两个组件let reg = Vue.component('reg',{template:`<div><h1>注册</h1><input type="text" v-model='regForm.username' id=""><input type="password" v-model='regForm.password' id=""><button @click='doReg'>注册</button></div>`,data(){return{regForm:{username:'',password:''}}},methods:{doReg(){console.log(this.regForm);alert('注册成功');console.log(this.$router);// this.$router.push('/login'); //直接传链接this.$router.push({path:'/login',query:{username:'zhangsan'}});//传对象}}});let login = Vue.component('login',{template:'<div><h1>登录 {{$route.query.username}}</h1></div>'});//2. 定义路径与组件之间的映射关系const routes=[{path:'/login',component:login},{path:'/reg',component:reg}]//3. 创建路由对象const router = new VueRouter({routes});//4.将路由对象设置到Vue实例中,使之生效new Vue({router}).$mount('#app');</script>
<a name="AvJBr"></a>### 路由守卫在跳转过程中检查是否有权限跳转到目标链接<br />全局:前置守卫、解析守卫、后置钩子<br />局部:单个路由内部、组件内部<br />完整的导航流程 : [https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%AE%8C%E6%95%B4%E7%9A%84%E5%AF%BC%E8%88%AA%E8%A7%A3%E6%9E%90%E6%B5%81%E7%A8%8B](https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%AE%8C%E6%95%B4%E7%9A%84%E5%AF%BC%E8%88%AA%E8%A7%A3%E6%9E%90%E6%B5%81%E7%A8%8B)```javascript//添加全局的前置守卫router.beforeEach((to,from,next)=>{if(to.path=='/reg'){alert("目前尚未开放注册!")return;}//放行next();});
路由的参数:
每个守卫方法接收三个参数:
**to: Route**: 即将要进入的目标 路由对象**from: Route**: 当前导航正要离开的路由**next: Function**: 一定要调用该方法来resolve这个钩子。执行效果依赖next方法的调用参数。**next()**: 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。**next(false)**: 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到from路由对应的地址。**next('/')**或者**next({ path: '/' })**: 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向next传递任意位置对象,且允许设置诸如replace: true、name: 'home'之类的选项以及任何用在[router-link](https://router.vuejs.org/zh/api/#to)的[to](https://router.vuejs.org/zh/api/#to)prop 或[router.push](https://router.vuejs.org/zh/api/#router-push)中的选项。**next(error)**: (2.4.0+) 如果传入next的参数是一个Error实例,则导航会被终止且该错误会被传递给[router.onError()](https://router.vuejs.org/zh/api/#router-onerror)注册过的回调。
代码
main.js
- 实例化Vue
- 挂载到App.vue
- 导入router文件夹 引入了vue-router
App.vue
- 页面骨架 router-link 、 router-view
router文件夹 index.js
- 配置路由器,提供了路由表 (路径 和 组件映射)
- 根据路由表将多个组件组织起来
/=> Home- Home.vue
- 引入了HelloWorld组件(import Helloworld ; 在 组件的实例中使用 components注册)
- Home.vue
开发一个页面
- 编写页面
```vue
{{person.name}}
2. 在 App.vue增加链接```vue<router-link to="/">Home</router-link> |<router-link to="/about">About</router-link> |>>>>> <router-link to="/center">个人中心</router-link>
- 在router/index.js中配置路径映

使用axios
- 在项目根目录(package.json所在目录)下
npm add axios(本质是在package.json中添加axios依赖,并执行install拉取) - 在main.js中引入并绑定到vue上 ```javascript import axios from ‘axios’
//定制axios 具体可以定制的选项,参考https://www.kancloud.cn/yunye/axios/234845 请求配置一节 var instance = axios.create({ baseURL: ‘http://localhost:8000‘, timeout: 1000 }); //将axios绑定到Vue上,全局变量 Vue.prototype.$http=instance;
3. 在其他组件即可使用```jsonthis.$http.get("/getPersonInfo",{params:{id:1}}).then(resp=>{if(resp.status==200&&resp.data.success){this.person=resp.data.data;}}).catch(error=>{console.error("加载出错",error);})
如果报依赖缺失,执行 cnpm install
These dependencies were not found:* core-js/modules/es.object.to-string.js in ./src/router/index.js* core-js/modules/es.string.iterator.js in ./src/router/index.js* core-js/modules/web.dom-collections.iterator.js in ./src/router/index.js
使用elementUI
- 添加依赖
cnpm i element-ui -S - 在main.js中启用element ```javascript //引入element import ElementUI from ‘element-ui’; import ‘element-ui/lib/theme-chalk/index.css’;
Vue.use(ElementUI);
3. 使用elementUI```vue<template><div class="about"><el-container><el-header><el-menu default-active="1" class="el-menu-demo" mode="horizontal"><el-menu-item index="1">处理中心</el-menu-item><el-submenu index="2"><template slot="title">我的工作台</template><el-menu-item index="2-1">选项1</el-menu-item><el-menu-item index="2-2">选项2</el-menu-item><el-menu-item index="2-3">选项3</el-menu-item><el-submenu index="2-4"><template slot="title">选项4</template><el-menu-item index="2-4-1">选项1</el-menu-item><el-menu-item index="2-4-2">选项2</el-menu-item><el-menu-item index="2-4-3">选项3</el-menu-item></el-submenu></el-submenu><el-menu-item index="3" disabled>消息中心</el-menu-item><el-menu-item index="4"><a href="https://www.ele.me" target="_blank">订单管理</a></el-menu-item></el-menu></el-header><el-main><el-form :inline="true" :model="searchForm" class="demo-form-inline"><el-form-item label="教师姓名"><el-input v-model="searchForm.teacherName" placeholder="教师姓名"></el-input></el-form-item><el-form-item label="审核状态"><el-select clearable v-model="searchForm.state" placeholder="审核状态"><el-option label="待审核" value="wait"></el-option><el-option label="审核通过" value="normal"></el-option><el-option label="审核失败" value="fail"></el-option></el-select></el-form-item><el-form-item><el-button type="primary" @click="search">查询</el-button><el-button type="success" @click="addTeacherDialogVisible=true" icon="el-icon-plus" circle></el-button></el-form-item></el-form><el-row><el-col ><el-table:data="tableData"style="width: 100%"><el-table-columnprop="teacherId"label="教师ID"width="180"></el-table-column><el-table-columnprop="teacherName"label="教师姓名"width="180"></el-table-column><!-- 格式化器 --><el-table-columnprop="state":formatter="stateFormatter"label="状态"></el-table-column><el-table-columnprop="email"label="邮箱"></el-table-column><el-table-columnlabel="操作"><template slot-scope='scope'><el-button v-if='scope.row.state=="wait"' @click="audit(scope.row,true)" type="text" size="small">审核通过</el-button><el-button v-if='scope.row.state=="wait"' @click="audit(scope.row,false)" type="text" size="small">审核失败</el-button><el-button v-if='scope.row.state=="normal"' @click="fire(scope.row)" type="text" size="small">开除</el-button><el-button v-if='scope.row.state=="normal"' @click="modifyTeacher(scope.row)" type="text" size="small">修改</el-button></template></el-table-column></el-table><el-paginationbackgroundlayout="prev, pager, next,sizes":total="page.total":current-page='page.current':page-size='page.size'@current-change='search'></el-pagination></el-col></el-row></el-main></el-container><el-dialog title="新增讲师" :visible.sync="addTeacherDialogVisible"><el-form :model="addTeacherForm"><el-row><el-col :span='15'><el-form-item label="讲师姓名" label-width="180px"><el-input v-model="addTeacherForm.teacherName" autocomplete="off"></el-input></el-form-item></el-col></el-row><el-row><el-col :span='15'><el-form-item label="生日" label-width="180px"><el-date-pickerv-model="addTeacherForm.birthday"type="date"format="yyyy-MM-dd"value-format="yyyy-MM-dd HH:mm:ss"placeholder="选择生日"></el-date-picker></el-form-item></el-col></el-row><el-form-item label="email" label-width="180px"><el-input v-model="addTeacherForm.email" autocomplete="off"></el-input></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button @click="addTeacherDialogVisible = false">取 消</el-button><el-button type="primary" @click="addTeacher">新增</el-button></div></el-dialog><el-dialog title="修改讲师" :visible.sync="modifyTeacherDialogVisible"><el-form :model="modifyTeacherForm"><el-row><el-col :span='15'><el-form-item label="讲师姓名" label-width="180px"><el-input v-model="modifyTeacherForm.teacherName" autocomplete="off"></el-input></el-form-item></el-col></el-row><el-row><el-col :span='15'><el-form-item label="生日" label-width="180px"><el-date-pickerv-model="modifyTeacherForm.birthday"type="date"format="yyyy-MM-dd"value-format="yyyy-MM-dd HH:mm:ss"placeholder="选择生日"></el-date-picker></el-form-item></el-col></el-row><el-form-item label="email" label-width="180px"><el-input v-model="modifyTeacherForm.email" autocomplete="off"></el-input></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button @click="modifyTeacherDialogVisible = false">取 消</el-button><el-button type="primary">修改</el-button></div></el-dialog></div></template><script>export default {name:'About',data(){return {page:{total:0,current:1,size:10},searchForm:{teacherName:'',state:''},formLabelWidth:"80px",modifyTeacherDialogVisible:false,addTeacherForm: {teacherName: '',email:'',birthday:''},modifyTeacherForm: {teacherId:'',teacherName: '',email:'',birthday:''},addTeacherDialogVisible:false,tableData:[]}},mounted(){this.search(1);},methods:{modifyTeacher(row){this.modifyTeacherForm=row;this.modifyTeacherDialogVisible=true;},addTeacher(){console.log(this.addTeacherForm)this.$http.post('/addNewTeacher',this.addTeacherForm).then(resp=>{this.$message({message:"新增成功",type:"success"});this.search(1);this.addTeacherDialogVisible=false;}).catch(resp=>{this.$message({message:"操作失败",type:"warning"});this.addTeacherDialogVisible=false;})},stateFormatter(row, column, cellValue, index){switch(cellValue){case 'wait': return '待审核';case 'normal': return '审核通过';case 'fail': return '审核失败';default : console.error("错误的状态"+cellValue+",无法格式化");}},audit(row,pass){console.log(row,pass);this.$http.post('/audit',{"teacherId":row.teacherId,"pass":pass}).then(resp=>{this.$message({message:"审核操作完成",type:"success"});this.search(1);}).catch(resp=>{this.$message({message:"操作失败",type:"warning"});})},fire(row){},handleClick(row){console.log(row);this.dialogFormVisible=true;// this.$message({message:'你查看成功了',type:'warning'});},search(current){//发请求到后端,搜索数据let param = this.searchForm;param.pageIndex=current;param.pageSize=this.page.size;this.$http.get('/queryTeacher',{params:param}).then(resp=>{if(resp.status=200&&resp.data.success){let data = resp.data.data;this.tableData=data.records;//将后端返回的数据绑定到分页条上this.page.total=data.total;this.page.current=data.current;this.page.size=data.size;}else{this.$message({message:'查询失败,'+resp.data.message,type:'warning'})}}).catch(error=>{this.$message({message:'查询失败,'+error.message,type:'error'})})}}}</script>
特别说明:
在el-menu上添加router属性,将激活vue-router模式,使用index作为path导航
<el-menu router default-active="1" class="el-menu-demo" mode="horizontal"><el-menu-item index="/">主页</el-menu-item><el-menu-item index="/about">关于</el-menu-item><el-menu-item index="/center">个人中心</el-menu-item>
作业
- 在脚手架项目中编写一个课程搜索功能;用户注册功能; element-ui
