https://element.eleme.cn/

基本案例

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <!-- 引入样式 -->
  8. <link
  9. rel="stylesheet"
  10. href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"
  11. />
  12. <title>Document</title>
  13. </head>
  14. <body>
  15. <div id="app">
  16. <el-button @click="visible = true">Button</el-button>
  17. <el-dialog :visible.sync="visible" title="Hello world">
  18. <p>Try Element</p>
  19. </el-dialog>
  20. </div>
  21. <script src="https://unpkg.com/vue/dist/vue.js"></script>
  22. <!-- 引入组件库 -->
  23. <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  24. <script>
  25. let app = new Vue({
  26. el:'#app',
  27. data:{
  28. visible:false
  29. }
  30. });
  31. </script>
  32. </body>
  33. </html>

布局

通过基础的 24 分栏,迅速简便地创建布局。通过el-row和el-col布局,总共24分栏,span表示占用的栏数,offset表示偏移量

  1. <el-row>
  2. <el-col :span="24"><div class="grid-content bg-purple-dark"></div></el-col>
  3. </el-row>
  4. <el-row>
  5. <el-col :span="12"><div class="grid-content bg-purple"></div></el-col>
  6. <el-col :span="12"><div class="grid-content bg-purple-light"></div></el-col>
  7. </el-row>
  8. <el-row>
  9. <el-col :span="8"><div class="grid-content bg-purple"></div></el-col>
  10. <el-col :span="8"><div class="grid-content bg-purple-light"></div></el-col>
  11. <el-col :span="8"><div class="grid-content bg-purple"></div></el-col>
  12. </el-row>

Form

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <!-- 引入样式 -->
  8. <link
  9. rel="stylesheet"
  10. href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"
  11. />
  12. <title>Document</title>
  13. </head>
  14. <body>
  15. <div id="app">
  16. <el-container>
  17. <el-header>
  18. <el-menu default-active="1" class="el-menu-demo" mode="horizontal">
  19. <el-menu-item index="1">处理中心</el-menu-item>
  20. <el-submenu index="2">
  21. <template slot="title">我的工作台</template>
  22. <el-menu-item index="2-1">选项1</el-menu-item>
  23. <el-menu-item index="2-2">选项2</el-menu-item>
  24. <el-menu-item index="2-3">选项3</el-menu-item>
  25. <el-submenu index="2-4">
  26. <template slot="title">选项4</template>
  27. <el-menu-item index="2-4-1">选项1</el-menu-item>
  28. <el-menu-item index="2-4-2">选项2</el-menu-item>
  29. <el-menu-item index="2-4-3">选项3</el-menu-item>
  30. </el-submenu>
  31. </el-submenu>
  32. <el-menu-item index="3" disabled>消息中心</el-menu-item>
  33. <el-menu-item index="4"><a href="https://www.ele.me" target="_blank">订单管理</a></el-menu-item>
  34. </el-menu>
  35. </el-header>
  36. <el-main>
  37. <el-row>
  38. <el-col :span='12' :offset="6">
  39. <el-form ref="form" :model="form" label-width="80px">
  40. <el-form-item label="活动名称">
  41. <el-input v-model="form.name"></el-input>
  42. </el-form-item>
  43. <el-form-item label="活动区域">
  44. <el-select v-model="form.region" placeholder="请选择活动区域">
  45. <el-option label="区域一" value="shanghai"></el-option>
  46. <el-option label="区域二" value="beijing"></el-option>
  47. </el-select>
  48. </el-form-item>
  49. <el-form-item label="活动时间">
  50. <el-col :span="11">
  51. <el-date-picker type="date" format='yyyy-MM-dd' value-format="yyyy-MM-dd" placeholder="选择日期" v-model="form.date1" style="width: 100%;"></el-date-picker>
  52. </el-col>
  53. <el-col class="line" :span="2">-</el-col>
  54. <el-col :span="11">
  55. <el-time-picker format='HH:mm:ss' value-format='HH:mm:ss' placeholder="选择时间" v-model="form.date2" style="width: 100%;"></el-time-picker>
  56. </el-col>
  57. </el-form-item>
  58. <el-form-item label="即时配送">
  59. <el-switch v-model="form.delivery"></el-switch>
  60. </el-form-item>
  61. <el-form-item label="活动性质">
  62. <el-checkbox-group v-model="form.type">
  63. <el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
  64. <el-checkbox label="地推活动" name="type"></el-checkbox>
  65. <el-checkbox label="线下主题活动" name="type"></el-checkbox>
  66. <el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
  67. </el-checkbox-group>
  68. </el-form-item>
  69. <el-form-item label="特殊资源">
  70. <el-radio-group v-model="form.resource">
  71. <el-radio label="线上品牌商赞助"></el-radio>
  72. <el-radio label="线下场地免费"></el-radio>
  73. </el-radio-group>
  74. </el-form-item>
  75. <el-form-item>
  76. <el-upload
  77. class="upload-demo"
  78. action="http://localhost:8080/upload"
  79. name='file'
  80. :on-preview="handlePreview"
  81. :on-remove="handleRemove"
  82. :before-remove="beforeRemove"
  83. multiple
  84. :limit="3"
  85. :on-success="handleSuccess"
  86. :on-exceed="handleExceed"
  87. :file-list="form.fileList">
  88. <el-button size="small" type="primary">点击上传</el-button>
  89. <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
  90. </el-upload>
  91. </el-form-item>
  92. <el-form-item label="活动形式">
  93. <el-input type="textarea" v-model="form.desc"></el-input>
  94. </el-form-item>
  95. <el-form-item>
  96. <el-button type="primary" @click="onSubmit">立即创建</el-button>
  97. <el-button>取消</el-button>
  98. </el-form-item>
  99. </el-form>
  100. </el-col>
  101. </el-row>
  102. </el-main>
  103. <el-container>
  104. </div>
  105. <script src="https://unpkg.com/vue/dist/vue.js"></script>
  106. <!-- 引入组件库 -->
  107. <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  108. <script>
  109. let app = new Vue({
  110. el:'#app',
  111. data:{
  112. form:{
  113. name: 'defaultName',
  114. region: '大中国',
  115. date1: '',
  116. date2: '',
  117. delivery: false,
  118. type: [],
  119. resource: '',
  120. desc: '',
  121. fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}]
  122. },
  123. },
  124. methods:{
  125. onSubmit(){
  126. console.log(this.form);
  127. },
  128. handleRemove(file, fileList) {
  129. console.log(file, fileList);
  130. },
  131. handlePreview(file) {
  132. console.log(file);
  133. },
  134. handleExceed(files, fileList) {
  135. this.$message.warning(`当前限制选择 3 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
  136. },
  137. beforeRemove(file, fileList) {
  138. return this.$confirm(`确定移除 ${ file.name }?`);
  139. },
  140. handleSuccess(response, file, fileList){
  141. console.log(file);
  142. let fileObj = {name:file.name,url:file.response.data};
  143. this.form.fileList.push(fileObj)
  144. }
  145. }
  146. });
  147. </script>
  148. </body>
  149. </html>

upload使用注意事项:

  1. name指定上传时的文件名
  2. action指定提交的目标地址
  3. 需要在成功回调on-success时手工添加到fileList中

    分页

    1. <el-pagination
    2. background
    3. layout="prev, pager, next,sizes"
    4. :total="page.total" 总条数
    5. :current-page='page.current' 当前页
    6. :page-size='page.size' 页容量
    7. @current-change='search' 当前页码改变时间,回传改变后的页码
    8. >
    9. </el-pagination>
    10. search(current){
    11. //发请求到后端,搜索数据
    12. let param = this.searchForm;
    13. param.pageIndex=current;
    14. param.pageSize=this.page.size;
    15. axios.get('http://localhost:8000/queryTeacher',{
    16. params:param
    17. })
    18. .then(resp=>{
    19. if(resp.status=200&&resp.data.success){
    20. let data = resp.data.data;
    21. this.tableData=data.records;
    22. //将后端返回的数据绑定到分页条上
    23. this.page.total=data.total;
    24. this.page.current=data.current;
    25. this.page.size=data.size;
    26. }else{
    27. this.$message({
    28. message:'查询失败,'+resp.data.message,
    29. type:'warning'
    30. })
    31. }
    32. })
    33. .catch(error=>{
    34. this.$message({
    35. message:'查询失败,'+error.message,
    36. type:'error'
    37. })
    38. })
    39. }
    40. }

JS发展

nodejs js运行时环境 让js脱离浏览器,在电脑上运行

  • 后端代码,创建httpserver,接受http请求,并且响应;可以访问数据库;可以创建文件读取文件
    • 框架 express / sequelize
  • 桌面端应用程序
    • 框架 electron
  • 移动端应用程序
    • react-native
    • vue -> uniapp / weex

npm nodejs 自带的包管理器,功能类似于maven的依赖管理
webpack 打包工具,类似于Maven的构建流程

html => pug模板,简化html的编写
css => sass / less css拓展语言
js => typescript / coffeescript 升级

安装Node环境

  1. nodejs 自带npm

https://nodejs.org/zh-cn/
安装,下一步,下一步

  1. 测试 node -v npm -v
  2. 编写一个例子
    1. # 编写一个helloworld.js,内容如下
    2. console.log("hello world");
    3. # 通过node命令运行
    4. node helloworld.js
    1. npm init
    2. npm install mysql
    3. # 编写index.js,内容如下
    4. # 运行
    5. node index.js
    6. # 访问 localhost:8888 即可在控制台看到数据
    ```javascript var mysql = require(‘mysql’); var http = require(‘http’);

http.createServer(function (request, response) {

  1. // 发送 HTTP 头部
  2. // HTTP 状态值: 200 : OK
  3. // 内容类型: text/plain
  4. response.writeHead(200, {'Content-Type': 'text/plain'});
  5. var connection = mysql.createConnection({
  6. host: 'localhost',
  7. port:3306,
  8. user: 'root',
  9. password: 'root123',
  10. database: 'edu_56'
  11. });
  12. connection.connect();
  13. connection.query('SELECT * from edu_teacher', function (error, results, fields) {
  14. if (error) throw error;
  15. console.log('The solution is: ', results);
  16. // 发送响应数据 "Hello World"
  17. response.end(results);
  18. });

}).listen(8888);

// 终端打印如下信息 console.log(‘Server running at http://127.0.0.1:8888/‘);

  1. 4. 安装taobaonpm
  2. ```bash
  3. npm i -g cnpm --registry=https://registry.npm.taobao.org

vue-cli

  1. 安装

    1. cnpm install -g @vue/cli
    2. vue -V
  2. 创建项目

    1. # cmd
    2. vue create my-project
    3. # 界面
    4. vue ui

    image.png

image.png
image.png
image.png
image.png

  1. cd vue56
  2. npm run serve
  3. # 访问 IP:8080 看到界面

解析脚手架项目

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的元素上

  1. package.json 项目管理文件
  2. 约定:<br />在文件夹下的index.js, 当引入文件夹时,默认读取index.js
  3. <a name="pAMB6"></a>
  4. ## 包
  5. js内部,封装多个方法或者类的一个工具,类似于java包<br />在包内部,导出数据和方法
  6. ```javascript
  7. function helloPlus(){
  8. hello();
  9. }
  10. function hello(){
  11. alert('123');
  12. }
  13. //导出的内容
  14. export default {
  15. delta : 1.99,
  16. sayHello: helloPlus
  17. }

需要使用时,引入

  1. import a from './a.js'
  2. a.sayHello();

单文件组件 .vue文件

before :

  1. Vue.component('todo-item',{
  2. template:`<li style="list-style:none">
  3. <input type="checkbox" name="" v-model="todo.state" id="">
  4. <span contenteditable @keydown.esc='handleCancel' @focus="save" @blur='handleChange' >{{todo.text}}</span>
  5. <span style='color:red;cursor:pointer' @click='del(todo)'>x</span>
  6. </li>`,//html的内容
  7. props:['todo'],//属性,
  8. data:function(){
  9. return {
  10. prev:this.todo.text
  11. }
  12. },
  13. methods:{
  14. del(todo){
  15. this.$emit("del",todo);//(1)在组件内触发一个自定义的事件,名为del,事件对象(事件内容)todo
  16. },
  17. handleChange(e){
  18. console.log("changing:"+this.prev +" canceled:"+this.canceled)
  19. this.todo.text=e.target.innerText;
  20. },
  21. handleCancel(e){
  22. console.log("cancel:"+this.prev)
  23. this.todo.text=this.prev;
  24. e.target.innerText=this.prev;
  25. e.target.blur();
  26. },
  27. save(){
  28. console.log("saving:"+this.todo.text)
  29. this.prev=this.todo.text
  30. }
  31. },
  32. mounted(){
  33. }
  34. });

after:
VUE脚手架与ElementUI的使用 - 图6
现在我们获得:

一个 .vue 文件,就是一个组件

vue-router 路由器

单页面应用 Single Page Application SPA
不切换页面的情况下更新内容,极佳的用户体验,类似于App的使用体验,成为潮流
map.baidu.com
juejin.im
image.png
实例

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <div id="app">
  11. <!-- 使用 router-link 组件来导航. -->
  12. <!-- 通过传入 `to` 属性指定链接. -->
  13. <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
  14. <router-link to='/idx'>首页</router-link>
  15. <router-link to='/ctr'>个人中心</router-link>
  16. <!-- 路由出口 -->
  17. <!-- 路由匹配到的组件将渲染在这里 -->
  18. <router-view></router-view>
  19. </div>
  20. <script src="https://unpkg.com/vue/dist/vue.js"></script>
  21. <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  22. <script>
  23. //1. 定义两个组件
  24. let index = Vue.component('index',{
  25. template:'<div><h1>首页</h1></div>'
  26. });
  27. let center = Vue.component('center',{
  28. template:'<div><h1>个人中心</h1></div>'
  29. });
  30. //2. 定义路径与组件之间的映射关系
  31. const routes=[
  32. {path:'/idx',component:index},
  33. {path:'/ctr',component:center}
  34. ]
  35. //3. 创建路由对象
  36. const router = new VueRouter({routes});
  37. //4.将路由对象设置到Vue实例中,使之生效
  38. new Vue({
  39. router
  40. }).$mount('#app');
  41. </script>
  42. </body>
  43. </html>

动态路由

根据路径动态匹配组件

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <div id="app">
  11. <!-- 使用 router-link 组件来导航. -->
  12. <!-- 通过传入 `to` 属性指定链接. -->
  13. <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
  14. <router-link to='/idx'>首页</router-link>
  15. <router-link to='/ctr'>个人中心</router-link>
  16. <router-link to='/product/bottle'>产品介绍</router-link>
  17. <!-- 路由出口 -->
  18. <!-- 路由匹配到的组件将渲染在这里 -->
  19. <router-view></router-view>
  20. </div>
  21. <script src="https://unpkg.com/vue/dist/vue.js"></script>
  22. <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  23. <script>
  24. //1. 定义两个组件
  25. let index = Vue.component('index',{
  26. template:'<div><h1>首页</h1></div>'
  27. });
  28. let center = Vue.component('center',{
  29. template:'<div><h1>个人中心</h1></div>'
  30. });
  31. let product = Vue.component('product',{
  32. template:'<div><h1>产品介绍:{{$route.params.productName}}</h1></div>'
  33. });
  34. //2. 定义路径与组件之间的映射关系
  35. const routes=[
  36. {path:'/idx',component:index},
  37. {path:'/ctr',component:center},
  38. {path:'/product/:productName',component:product}
  39. ]
  40. //3. 创建路由对象
  41. const router = new VueRouter({routes});
  42. //4.将路由对象设置到Vue实例中,使之生效
  43. new Vue({
  44. router
  45. }).$mount('#app');
  46. </script>
  47. </body>
  48. </html>

嵌套路由

在组件内部存在路由链接及路由视图
在routes路由表中使用children表示嵌套的路由关系

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <div id="app">
  11. <!-- 使用 router-link 组件来导航. -->
  12. <!-- 通过传入 `to` 属性指定链接. -->
  13. <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
  14. <router-link to='/idx'>首页</router-link>
  15. <router-link to='/ctr'>个人中心</router-link>
  16. <!-- 路由出口 -->
  17. <!-- 路由匹配到的组件将渲染在这里 -->
  18. <router-view></router-view>
  19. </div>
  20. <script src="https://unpkg.com/vue/dist/vue.js"></script>
  21. <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  22. <script>
  23. //1. 定义两个组件
  24. let index = Vue.component('index',{
  25. template:'<div><h1>首页</h1></div>'
  26. });
  27. let center = Vue.component('center',{
  28. template:`<div>
  29. <h1>个人中心</h1>
  30. <!-- 嵌套路由的链接 -->
  31. <router-link to='/center/intro'>intro</router-link>
  32. <router-link to='/center/modify'>modify</router-link>
  33. <!-- 嵌套路由的出口 -->
  34. <router-view></router-view>
  35. </div>`
  36. });
  37. //嵌套路由的组件
  38. let intro = Vue.component('intro',{
  39. template:`<h2>个人介绍:大帅哥一个</h2>`
  40. })
  41. let modify = Vue.component('modify',{
  42. template:`<h2>修改个人信息</h2>`
  43. })
  44. //2. 定义路径与组件之间的映射关系
  45. const routes=[
  46. {path:'/idx',component:index},
  47. {
  48. path:'/ctr',
  49. component:center,
  50. children:[
  51. {path:'/center/intro', component: intro},
  52. {path:'/center/modify', component: modify}
  53. ]
  54. },
  55. ]
  56. //3. 创建路由对象
  57. const router = new VueRouter({routes});
  58. //4.将路由对象设置到Vue实例中,使之生效
  59. new Vue({
  60. router
  61. }).$mount('#app');
  62. </script>
  63. </body>
  64. </html>

编程式路由导航

调用this.$router.push方法进行跳转

  • 直接传链接
  • 传对象 ```html <!DOCTYPE html>

    1. <!-- 使用 router-link 组件来导航. -->
    2. <!-- 通过传入 `to` 属性指定链接. -->
    3. <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
    4. <router-link to='/login'>登录</router-link>
    5. <router-link to='/reg'>注册</router-link>
    6. <!-- 路由出口 -->
    7. <!-- 路由匹配到的组件将渲染在这里 -->
    8. <router-view></router-view>
  1. </div>
  2. <script src="https://unpkg.com/vue/dist/vue.js"></script>
  3. <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  4. <script>
  5. //1. 定义两个组件
  6. let reg = Vue.component('reg',{
  7. template:`
  8. <div>
  9. <h1>注册</h1>
  10. <input type="text" v-model='regForm.username' id="">
  11. <input type="password" v-model='regForm.password' id="">
  12. <button @click='doReg'>注册</button>
  13. </div>`,
  14. data(){
  15. return{
  16. regForm:{
  17. username:'',
  18. password:''
  19. }
  20. }
  21. },
  22. methods:{
  23. doReg(){
  24. console.log(this.regForm);
  25. alert('注册成功');
  26. console.log(this.$router);
  27. // this.$router.push('/login'); //直接传链接
  28. this.$router.push({path:'/login',query:{username:'zhangsan'}});//传对象
  29. }
  30. }
  31. });
  32. let login = Vue.component('login',{
  33. template:'<div><h1>登录 {{$route.query.username}}</h1></div>'
  34. });
  35. //2. 定义路径与组件之间的映射关系
  36. const routes=[
  37. {path:'/login',component:login},
  38. {path:'/reg',component:reg}
  39. ]
  40. //3. 创建路由对象
  41. const router = new VueRouter({routes});
  42. //4.将路由对象设置到Vue实例中,使之生效
  43. new Vue({
  44. router
  45. }).$mount('#app');
  46. </script>

  1. <a name="AvJBr"></a>
  2. ### 路由守卫
  3. 在跳转过程中检查是否有权限跳转到目标链接<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)
  4. ```javascript
  5. //添加全局的前置守卫
  6. router.beforeEach((to,from,next)=>{
  7. if(to.path=='/reg'){
  8. alert("目前尚未开放注册!")
  9. return;
  10. }
  11. //放行
  12. next();
  13. });

路由的参数:
每个守卫方法接收三个参数:

  • **to: Route**: 即将要进入的目标 路由对象
  • **from: Route**: 当前导航正要离开的路由
  • **next: Function**: 一定要调用该方法来resolve这个钩子。执行效果依赖next方法的调用参数。
    • **next()**: 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
    • **next(false)**: 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
    • **next('/')** 或者 **next({ path: '/' })**: 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: truename: '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注册)

image.png

开发一个页面

  1. 编写页面 ```vue
  1. 2. App.vue增加链接
  2. ```vue
  3. <router-link to="/">Home</router-link> |
  4. <router-link to="/about">About</router-link> |
  5. >>>>> <router-link to="/center">个人中心</router-link>
  1. 在router/index.js中配置路径映

image.png

使用axios

  1. 在项目根目录(package.json所在目录)下 npm add axios (本质是在package.json中添加axios依赖,并执行install拉取)
  2. 在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;

  1. 3. 在其他组件即可使用
  2. ```json
  3. this.$http.get("/getPersonInfo",{
  4. params:{
  5. id:1
  6. }
  7. }).then(resp=>{
  8. if(resp.status==200&&resp.data.success){
  9. this.person=resp.data.data;
  10. }
  11. }).catch(error=>{
  12. console.error("加载出错",error);
  13. })

如果报依赖缺失,执行 cnpm install

  1. These dependencies were not found:
  2. * core-js/modules/es.object.to-string.js in ./src/router/index.js
  3. * core-js/modules/es.string.iterator.js in ./src/router/index.js
  4. * core-js/modules/web.dom-collections.iterator.js in ./src/router/index.js

使用elementUI

  1. 添加依赖 cnpm i element-ui -S
  2. 在main.js中启用element ```javascript //引入element import ElementUI from ‘element-ui’; import ‘element-ui/lib/theme-chalk/index.css’;

Vue.use(ElementUI);

  1. 3. 使用elementUI
  2. ```vue
  3. <template>
  4. <div class="about">
  5. <el-container>
  6. <el-header>
  7. <el-menu default-active="1" class="el-menu-demo" mode="horizontal">
  8. <el-menu-item index="1">处理中心</el-menu-item>
  9. <el-submenu index="2">
  10. <template slot="title">我的工作台</template>
  11. <el-menu-item index="2-1">选项1</el-menu-item>
  12. <el-menu-item index="2-2">选项2</el-menu-item>
  13. <el-menu-item index="2-3">选项3</el-menu-item>
  14. <el-submenu index="2-4">
  15. <template slot="title">选项4</template>
  16. <el-menu-item index="2-4-1">选项1</el-menu-item>
  17. <el-menu-item index="2-4-2">选项2</el-menu-item>
  18. <el-menu-item index="2-4-3">选项3</el-menu-item>
  19. </el-submenu>
  20. </el-submenu>
  21. <el-menu-item index="3" disabled>消息中心</el-menu-item>
  22. <el-menu-item index="4"><a href="https://www.ele.me" target="_blank">订单管理</a></el-menu-item>
  23. </el-menu>
  24. </el-header>
  25. <el-main>
  26. <el-form :inline="true" :model="searchForm" class="demo-form-inline">
  27. <el-form-item label="教师姓名">
  28. <el-input v-model="searchForm.teacherName" placeholder="教师姓名"></el-input>
  29. </el-form-item>
  30. <el-form-item label="审核状态">
  31. <el-select clearable v-model="searchForm.state" placeholder="审核状态">
  32. <el-option label="待审核" value="wait"></el-option>
  33. <el-option label="审核通过" value="normal"></el-option>
  34. <el-option label="审核失败" value="fail"></el-option>
  35. </el-select>
  36. </el-form-item>
  37. <el-form-item>
  38. <el-button type="primary" @click="search">查询</el-button>
  39. <el-button type="success" @click="addTeacherDialogVisible=true" icon="el-icon-plus" circle></el-button>
  40. </el-form-item>
  41. </el-form>
  42. <el-row>
  43. <el-col >
  44. <el-table
  45. :data="tableData"
  46. style="width: 100%">
  47. <el-table-column
  48. prop="teacherId"
  49. label="教师ID"
  50. width="180">
  51. </el-table-column>
  52. <el-table-column
  53. prop="teacherName"
  54. label="教师姓名"
  55. width="180">
  56. </el-table-column>
  57. <!-- 格式化器 -->
  58. <el-table-column
  59. prop="state"
  60. :formatter="stateFormatter"
  61. label="状态">
  62. </el-table-column>
  63. <el-table-column
  64. prop="email"
  65. label="邮箱">
  66. </el-table-column>
  67. <el-table-column
  68. label="操作">
  69. <template slot-scope='scope'>
  70. <el-button v-if='scope.row.state=="wait"' @click="audit(scope.row,true)" type="text" size="small">审核通过</el-button>
  71. <el-button v-if='scope.row.state=="wait"' @click="audit(scope.row,false)" type="text" size="small">审核失败</el-button>
  72. <el-button v-if='scope.row.state=="normal"' @click="fire(scope.row)" type="text" size="small">开除</el-button>
  73. <el-button v-if='scope.row.state=="normal"' @click="modifyTeacher(scope.row)" type="text" size="small">修改</el-button>
  74. </template>
  75. </el-table-column>
  76. </el-table>
  77. <el-pagination
  78. background
  79. layout="prev, pager, next,sizes"
  80. :total="page.total"
  81. :current-page='page.current'
  82. :page-size='page.size'
  83. @current-change='search'
  84. >
  85. </el-pagination>
  86. </el-col>
  87. </el-row>
  88. </el-main>
  89. </el-container>
  90. <el-dialog title="新增讲师" :visible.sync="addTeacherDialogVisible">
  91. <el-form :model="addTeacherForm">
  92. <el-row>
  93. <el-col :span='15'>
  94. <el-form-item label="讲师姓名" label-width="180px">
  95. <el-input v-model="addTeacherForm.teacherName" autocomplete="off"></el-input>
  96. </el-form-item>
  97. </el-col>
  98. </el-row>
  99. <el-row>
  100. <el-col :span='15'>
  101. <el-form-item label="生日" label-width="180px">
  102. <el-date-picker
  103. v-model="addTeacherForm.birthday"
  104. type="date"
  105. format="yyyy-MM-dd"
  106. value-format="yyyy-MM-dd HH:mm:ss"
  107. placeholder="选择生日">
  108. </el-date-picker>
  109. </el-form-item>
  110. </el-col>
  111. </el-row>
  112. <el-form-item label="email" label-width="180px">
  113. <el-input v-model="addTeacherForm.email" autocomplete="off"></el-input>
  114. </el-form-item>
  115. </el-form>
  116. <div slot="footer" class="dialog-footer">
  117. <el-button @click="addTeacherDialogVisible = false">取 消</el-button>
  118. <el-button type="primary" @click="addTeacher">新增</el-button>
  119. </div>
  120. </el-dialog>
  121. <el-dialog title="修改讲师" :visible.sync="modifyTeacherDialogVisible">
  122. <el-form :model="modifyTeacherForm">
  123. <el-row>
  124. <el-col :span='15'>
  125. <el-form-item label="讲师姓名" label-width="180px">
  126. <el-input v-model="modifyTeacherForm.teacherName" autocomplete="off"></el-input>
  127. </el-form-item>
  128. </el-col>
  129. </el-row>
  130. <el-row>
  131. <el-col :span='15'>
  132. <el-form-item label="生日" label-width="180px">
  133. <el-date-picker
  134. v-model="modifyTeacherForm.birthday"
  135. type="date"
  136. format="yyyy-MM-dd"
  137. value-format="yyyy-MM-dd HH:mm:ss"
  138. placeholder="选择生日">
  139. </el-date-picker>
  140. </el-form-item>
  141. </el-col>
  142. </el-row>
  143. <el-form-item label="email" label-width="180px">
  144. <el-input v-model="modifyTeacherForm.email" autocomplete="off"></el-input>
  145. </el-form-item>
  146. </el-form>
  147. <div slot="footer" class="dialog-footer">
  148. <el-button @click="modifyTeacherDialogVisible = false">取 消</el-button>
  149. <el-button type="primary">修改</el-button>
  150. </div>
  151. </el-dialog>
  152. </div>
  153. </template>
  154. <script>
  155. export default {
  156. name:'About',
  157. data(){return {
  158. page:{
  159. total:0,
  160. current:1,
  161. size:10
  162. },
  163. searchForm:{
  164. teacherName:'',
  165. state:''
  166. },
  167. formLabelWidth:"80px",
  168. modifyTeacherDialogVisible:false,
  169. addTeacherForm: {
  170. teacherName: '',
  171. email:'',
  172. birthday:''
  173. },
  174. modifyTeacherForm: {
  175. teacherId:'',
  176. teacherName: '',
  177. email:'',
  178. birthday:''
  179. },
  180. addTeacherDialogVisible:false,
  181. tableData:[]
  182. }
  183. },
  184. mounted(){
  185. this.search(1);
  186. },
  187. methods:{
  188. modifyTeacher(row){
  189. this.modifyTeacherForm=row;
  190. this.modifyTeacherDialogVisible=true;
  191. },
  192. addTeacher(){
  193. console.log(this.addTeacherForm)
  194. this.$http.post('/addNewTeacher',this.addTeacherForm)
  195. .then(resp=>{
  196. this.$message({message:"新增成功",type:"success"});
  197. this.search(1);
  198. this.addTeacherDialogVisible=false;
  199. }).catch(resp=>{
  200. this.$message({message:"操作失败",type:"warning"});
  201. this.addTeacherDialogVisible=false;
  202. })
  203. },
  204. stateFormatter(row, column, cellValue, index){
  205. switch(cellValue){
  206. case 'wait': return '待审核';
  207. case 'normal': return '审核通过';
  208. case 'fail': return '审核失败';
  209. default : console.error("错误的状态"+cellValue+",无法格式化");
  210. }
  211. },
  212. audit(row,pass){
  213. console.log(row,pass);
  214. this.$http.post('/audit',{"teacherId":row.teacherId,"pass":pass})
  215. .then(resp=>{
  216. this.$message({message:"审核操作完成",type:"success"});
  217. this.search(1);
  218. }).catch(resp=>{
  219. this.$message({message:"操作失败",type:"warning"});
  220. })
  221. },
  222. fire(row){
  223. },
  224. handleClick(row){
  225. console.log(row);
  226. this.dialogFormVisible=true;
  227. // this.$message({message:'你查看成功了',type:'warning'});
  228. },
  229. search(current){
  230. //发请求到后端,搜索数据
  231. let param = this.searchForm;
  232. param.pageIndex=current;
  233. param.pageSize=this.page.size;
  234. this.$http.get('/queryTeacher',{
  235. params:param
  236. })
  237. .then(resp=>{
  238. if(resp.status=200&&resp.data.success){
  239. let data = resp.data.data;
  240. this.tableData=data.records;
  241. //将后端返回的数据绑定到分页条上
  242. this.page.total=data.total;
  243. this.page.current=data.current;
  244. this.page.size=data.size;
  245. }else{
  246. this.$message({
  247. message:'查询失败,'+resp.data.message,
  248. type:'warning'
  249. })
  250. }
  251. })
  252. .catch(error=>{
  253. this.$message({
  254. message:'查询失败,'+error.message,
  255. type:'error'
  256. })
  257. })
  258. }
  259. }
  260. }
  261. </script>

特别说明:
在el-menu上添加router属性,将激活vue-router模式,使用index作为path导航

  1. <el-menu router default-active="1" class="el-menu-demo" mode="horizontal">
  2. <el-menu-item index="/">主页</el-menu-item>
  3. <el-menu-item index="/about">关于</el-menu-item>
  4. <el-menu-item index="/center">个人中心</el-menu-item>

Vuex

问题: 前端需要存储类似是否登录这样的数据,用于判断页面能否显示?
image.png

两种方式:

简单处理方式(丐版),在浏览器中存储数据: localStorage / sessionStorage (html5)

为何不用Cookie?
页面切换时,可能不发请求;数据量比较大
localStorage和sessionStorage的API是一致的,如下:

  • 保存数据:localStorage.setItem(key,value);
  • 读取数据:localStorage.getItem(key);
  • 删除单个数据:localStorage.removeItem(key);
  • 删除所有数据:localStorage.clear();
  • 得到某个索引的key:localStorage.key(index);

localStorage和sessionStorage的区别在于作用域范围,localStroge针对一个网站,持久存储;sessionStorage只对一个标签,关闭则消失;一般使用localStorage;

拦截登录实例

  1. 路由守卫,拦截所有请求,基于router实现守卫,代码写在/router/index.js ```javascript import {Message} from ‘element-ui’

router.beforeEach((to,from,next)=>{ let isLogined = localStorage.getItem(“isLogined”); console.log(“是否登录”+isLogined);

if(to.path==’/login’){ console.log(“登陆请求,放行”); next(); return; } if(isLogined){ console.log(“已登录,放行”); next(); return; }

Message({ type:”error”, message:”请您先登录” }); //this.$router 是在vue实例中使用 //跳转 router.push(“/login”);

});

  1. 2. 登录完成后,存入登录标记
  2. ```vue
  3. <template>
  4. <el-form
  5. :model="ruleForm"
  6. status-icon
  7. ref="ruleForm"
  8. label-width="100px"
  9. class="demo-ruleForm"
  10. >
  11. <el-form-item label="用户名" prop="pass">
  12. <el-input
  13. type="text"
  14. v-model="ruleForm.username"
  15. autocomplete="off"
  16. ></el-input>
  17. </el-form-item>
  18. <el-form-item label="密码" prop="checkPass">
  19. <el-input
  20. type="password"
  21. v-model="ruleForm.password"
  22. autocomplete="off"
  23. ></el-input>
  24. </el-form-item>
  25. <el-form-item>
  26. <el-button type="primary" @click="submitForm">登录</el-button>
  27. </el-form-item>
  28. </el-form>
  29. </template>
  30. <script>
  31. export default {
  32. name: "Login",
  33. data() {
  34. return {
  35. ruleForm: {
  36. username: "",
  37. password: "",
  38. }
  39. };
  40. },
  41. methods: {
  42. submitForm() {
  43. alert("登录成功");
  44. localStorage.setItem("isLogined","true");
  45. }
  46. },
  47. };
  48. </script>

可以通过开发者控制台查看localStorage所存的数据
image.png

Vuex

https://vuex.vuejs.org/zh/
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
image.png
处理中大型的vue应用程序的数据状态管理

  • state,数据存储,驱动应用的数据源;
  • view,以声明方式将 state 映射到视图;
  • actions,用来修改state的一些操作,响应在 view 上的用户输入导致的状态变化。

如果state里有一个属性叫余额,那么actions就可能存在充值或者提现这样方法

以下是一个表示“单向数据流”理念的简单示意:
VUE脚手架与ElementUI的使用 - 图14
image.png
image.png

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <div id="app">
  11. <div>{{count}}</div>
  12. <div>
  13. <button @click='add'>+</button>
  14. <button @click='minus'>-</button>
  15. </div>
  16. </div>
  17. <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  18. <script src="https://unpkg.com/vuex@3.6.2/dist/vuex.js"></script>
  19. <script>
  20. // public class A{
  21. // private int count=0;
  22. // public void incr(){
  23. // count++;
  24. // }
  25. // public void decr(){
  26. // count--;
  27. // }
  28. // }
  29. //创建了一个Vuex的store对象
  30. const store = new Vuex.Store({
  31. state:{//数据
  32. count:0
  33. },
  34. mutations:{//action,对数据的操作
  35. incr(state){//参数为state对象
  36. state.count++;
  37. },
  38. decr(state){
  39. state.count--;
  40. }
  41. }
  42. });
  43. let app = new Vue({
  44. el:"#app",
  45. data:{
  46. // count:0
  47. },
  48. computed:{//通过计算属性将store内部的值放进到vue实例中
  49. count(){
  50. return store.state.count;
  51. }
  52. },
  53. methods:{
  54. add(){
  55. //触发store的相应的mutation更改器
  56. store.commit('incr');
  57. },
  58. minus(){
  59. store.commit('decr');
  60. }
  61. }
  62. })
  63. </script>
  64. </body>
  65. </html>