复习
- 熟悉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 />在包内部,导出数据和方法
```javascript
function 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. 在其他组件即可使用
```json
this.$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-column
prop="teacherId"
label="教师ID"
width="180">
</el-table-column>
<el-table-column
prop="teacherName"
label="教师姓名"
width="180">
</el-table-column>
<!-- 格式化器 -->
<el-table-column
prop="state"
:formatter="stateFormatter"
label="状态">
</el-table-column>
<el-table-column
prop="email"
label="邮箱">
</el-table-column>
<el-table-column
label="操作">
<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-pagination
background
layout="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-picker
v-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-picker
v-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