4. Vue CLI脚手架学习笔记

本文详细介绍了VueCLI的用途、安装和创建第一个VueCLI工程的步骤,强调了VueCLI工程的单页面特性。此外,讲解了VueCLI工程的文件结构,重点解析了视图组件和路由的配置。还涵盖了ElementUI的安装和在登录页面中的应用,以及Axios的使用,包括POST、DELETE、PUT和GET请求。最后,讨论了VueCLI的嵌套路由和路由守卫的概念,提供了一个实际案例。
摘要由CSDN通过智能技术生成

1 Vue CLI介绍

1.1 Vue.js

  • Vue.js(读音:/vjuː/, 类似于:view) 是一套构建用户界面的渐进式框架

  • Vue.js的官方网址是:https://cn.vuejs.org/

  • 传统的前端开发框架大多是基于DOM(Document Object Model:文档 对象模型)的,在操作时,需要关心被操作的页面元素,甚至这些页面元 素的层级结构,核心思想是:先根据DOM找到对应的页面元素,然后再 进行相关操作,例如设计其样式,或配置某个事件

  • Vue则是将必要的页面元素的相关属性(例如页面元素的样式、控件的值、 页面元素的事件等)与数据进行绑定,当实现绑定后,就不再需要关心页 面元素本身了,只需要关心各个数据即可,从而避免了大量繁琐的DOM 操作,也实现了页面设计与数据处理的分离

1.2 Vue CLI

  • Vue CLI通常称为“VUE脚手架”,它是一个专门为单页面应用快速搭建 繁杂的脚手架,它可以轻松的创建新的应用程序而且可用于自动生成vue 和webpack的工程模板

  • Vue CLI相关文档的官方网址是:https://cli.vuejs.org/zh/guide/

  • Vue CLI是由VUE提供的一个官方客户端(client),专门为单页面应用 快速搭建繁杂的脚手架

需要注意:在使用传统模式开发的前端工程中,各个页面是相对独立的, 甚至你可以在本地硬盘上找到对应的html文件并双击直接打开它,而Vue CLI工程与一个Web应用程序一样,是需要启动服务才可以访问的,一定 程度上,它的上手难度会更大一些,但是在中大型应用程序的开发中,它 在开发效率、管理和维护成本上有更大的优势

1.3 单页面

  • 单页面,指的是在工程中,理论上只有1个HTML页面,只不过这 个页面的所有内容都是可以动态更新的,你随时可以使用新的页面内容替 换原有的内容,并且,你还可以使得URL一并更新,从用户体验上来说, 这种单页面应用与传统的前端应用并没有什么不同

  • 单页面应用的工程中需要一定的配置,对配置文件的位置也有一定的要求, 整体工程结果并不像传统的前端应用工程那么自由,所以,手动创建这种 应用的成本较大,而Vue CLI则可以自动生成vue.js + webpack的工程模 板,是为现代前端工作流提供了Batteries-included(自含全套工具集) 的构建设置,只需要几分钟的时间甚至更短的时间就可以运行起来。

2 搭建开发环境

  1. node.js安装: 详见node.js安装笔记

  2. Vue CLI安装:

npm install -g @vue/cli

检查是否安装成功:

vue -V

在这里插入图片描述

3 创建第1个VUE CLI工程

通常使用Vue的命令来创建Vue CLI工程,并且,此命令会将工程创建在 执行命令时的位置,所以,先在命令提示符窗口中进入Vue Workspace, 例如(以下示例中的#开头是注释,不要执行):

# 切换到D盘 d:
# 创建Vue的Workspace,文件夹名称为Vue-Workspace,是自定义名称 
# 如果Vue的Workspace已经存在,则不需要执行接下来这条命令 
# 如果使用IntelliJ IDEA开发VUE CLI工程,也可以直接使用IntelliJ IDEA的Workspace, 无强制要求 
mkdir Vue-Workspace 
# 进入D盘下的Vue-Workspace 
cd Vue-Workspace

使用vue create命令即可创建Vue CLI工程,命令格式是:

vue create 工程名称

例如执行:

vue create vue-project-01

创建过程中会有一些选项,最先提示的选项是Please pick a preset,表示“请选择一个预设项”,推荐选择Manually select features,表示 “手动选择功能”,通过键盘的上下箭头进行选择,选择到目标项后按下键盘的Enter键到下一步:

在这里插入图片描述
接下来的选项是Check the features needed for your project,表示 “选择你的工程中需要使用的功能”,推荐在列表中选择Babel、Router、 Vuex这3项,使用键盘的上下箭头移动,使用空格选中或取消选中,选择 完成后按下键盘的Enter键到下一步:

在这里插入图片描述

关于列表中主要的几个功能:

  • Babel:ES6高级语法向低版本语法兼容的工具
  • Router:路由管理器(管理请求路径与页面资源的映射关系,相关于Controller中 @RequestMapping)
  • Vuex:全局状态管理工具(管理全局共享的内存中的数据,例如各页面需要使用到 的用户信息)
  • Linter:初学者不建议勾选,是代码规范检验工具,其要求较严格

接下来的选项是Choose a version of Vue.js that you want to start the project with,表示“选择你的工程中希望使用的Vue.js的版本”, 推荐选择2.x这项,选择到目标项后按下键盘的Enter键到下一步:
在这里插入图片描述
接下来的选项是Use history mode for router,表示“是否在路由中选 择历史模式”,推荐选择“是”,我选择否,输入Y后按下键盘的Enter键到下一步 (提示信息中,Y是大写的,表示它是默认选项,不输入Y而直接按下 Enter键是等效的):

在这里插入图片描述
接下来的选项是Where do you prefer placing config for Babel, ESLint, etc.?,表示“你习惯把一些配置信息存放在哪里?”,推荐选择 In package.json,即存放在package.json文件中,选择到目标项后按 下键盘的Enter键到下一步:
在这里插入图片描述

如果前面的Use history mode for router中选择了则会出现Save this as a preset for future projects?,表示“是否 保存以上配置信息,作为后续将创建的新工程的预设?”,推荐选择 “否”,输入N后按下键盘的Enter键(提示信息中,N是大写的,表示它 是默认选项,不输入N而直接按下Enter键是等效的)

在这里插入图片描述

如果还安装了yarn将会让你选择使用yarn或使用npm, 这里使用npm

创建成功:
在这里插入图片描述
执行

cd vue-project-01
npm run serve

启动成功:
在这里插入图片描述
访问:

http://localhost:8080

在这里插入图片描述

4 了解VUE CLI工程

4.1 Vue CLI结构

在这里插入图片描述

[]为文件夹

  1. [node_modules]工程中使用到的模块,也可以理解为工程的依赖项, 例如Babel、Vue等框架的文件,不手动管理。

需要注意:如果是从Git或其它位置复制得到的工程,没有此文件夹,需要运行 npm install或者npm i,否则将无此文件夹及其下的各依赖项,工程将无法正常启动。

  1. [public]:工程被编译打包后仍会保留的内容(文件内容可能会在编译打 包过程中修改)
    你可以自行在此文件夹下创建子级文件夹,用于存放公共静态资源,例如图片等。

  2. public/index.html:默认的主页,通常不修改其内容。

  3. [src]:页面源代码,除工程配置以外的所有开发都在此文件夹下

  4. [src/assets]:资源文件夹,通常存放图片等, 放置需要经由 Webpack 处理的静态文件。

注意:仅不需要被程序动态控制的图片放在此处

  1. [src/components]:视图组件,通常是可以被其它各页面复用的,是各 个.vue文件。

  2. [src/router]:路由控制。

  3. src/router/index.js:路由配置文件,除非工程中页面数量较大,或路 由关系复杂,否则使用这1个文件进行路由管理即可。

  4. [src/store]:全局数据存储

  5. [src/views]:视图组件 ,通常,每个页面在此文件夹都应该有1个对应 的文件,可引用[src/components]下的组件。

  6. src/App.vue:默认的主页视图组件。

  7. src/main.js:工程的主js文件,通常用于导入工程中将使用的其它库 – 此文件中所有import语句必须在最上方位置,各import语句不区分先后顺序。

  8. .gitigore:用于配置使用Git提交工程时将忽略的文件和文件夹 。

  9. bable.config.js:Babel的配置文件。

  10. package.json:工程的管理配置文件,相当于Maven项目的pom.xml, 在不熟悉的情况下不要手动修改此文件的配置,可能需要关注的主要有:

  • scripts:支持的2个npm命令参数,例如npm run serve、npc run build
  • dependencies:运行时依赖项
  • devDependencies:开发依赖项,将不参与打包
  1. package-lock.json:工程的管理配置文件 。

  2. README.md:工程的说明文档,用于开发人员编写如何使用、注意事 项、更新日志等内容,使用IntelliJ IDEA首次打开工程时,会自动打开此 文件,此文件的默认内容中提示了工程的运行命令 。

  3. vue.config.js:Vue的配置文件。

4.2 视图组件

  1. 所有以 .vue 为后缀的都是视图组件,根目录下的App.vue默认代码为:
<template>
  <div id="app">
    <nav>
      <router-link to="/">欢迎</router-link> |
      <router-link to="/about">关于</router-link>|
      <router-link to="/other">其它</router-link>
    </nav>
    <router-view/>
  </div>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

nav {
  padding: 30px;
}

nav a {
  font-weight: bold;
  color: #2c3e50;
}

nav a.router-link-exact-active {
  color: #42b983;
}
</style>
  1. 可以看到此文件中主要有2个节点:
  • <template>节点:用于设计页面元素,其内部代码可以是标准HTML代码,也可以 是Vue或其它库(例如Element UI)支持的代码

  • < style> 节点:用于定义样式,语法规则与传统前端技术中完全相同

需要注意:在<template>必须有且仅有1个直接子节点(通常是<div>节 点),否则将无法通过编译!

  1. 而默认的views/HomeView.vue的源代码如下:
<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/EI9.png">
    <HelloWorld msg="欢迎来到你的 Vue CLI"/>
  </div>
</template>

<script>
//导入组件
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'HomeView',
  components: {
    HelloWorld
  }
}
</script>
  1. 在以上views/HomeView.vue文件中,第4行代码为:
<HelloWorld msg="欢迎来到你的 Vue CLI"/>

以上代码是基于其在<script>标签内通过以下代码引用了 components/HellowWorld.vue视图组件:

import HelloWorld from '@/components/HelloWorld.vue'
  1. &lt;HelloWorld&gt;节点中配置了名为msg值为"Welcome to Your Vue.js App"的属性,而components/HelloWorld.vue中则使用 {{ msg }}应用了传入的值,这是在Vue CLI工程中封装视图组件并引用时 传参的典型方式

  2. 在components和views下的.vue文件的设计方式是基本相同的,区别在 于components下的视图组件应该是可以被引用的

  3. 所有视图组件的源代码被修改后,都不需要重启服务,在浏览器可以看到 最新的内容,这是Vue CLI的热部署(热更新)实现的

4.3 路由

  • Vue CLI应用是单页面的,也就是说,在Vue CLI工程的设计思想中,页 面只有1个,只不过页面中的内容是可以动态调整的,所以,无论是使用 不同的URL进行访问,还是页面中触发某个事件后,虽然用户看到了不同 的页面效果,但是,用户看到的其实永远只是1个页面,只是页同中的内 容不同而已,这也就是视图组件源文件中使用&lt;template&gt;节点设计页面 元素的原因(template释义为:模板)

  • Vue CLI工程使用路由控制 单页面中显示的元素,默认 的router/index.js源代码所示:

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'

Vue.use(VueRouter)

//路由
const routes = [
  {
    path: '/',
    component: HomeView
  },
  {
    path: '/about',
    component: () => import('../views/AboutView.vue')
  },
  {
    path: '/other',
    component: () => import('../views/OtherView.vue')
  }
]

const router = new VueRouter({
  routes
})

export default router
  • 在此文件中,需要重点关注import语句和routes常量。

  • routes常量是一个数组,数组元素是JSON对象,此JSON对象中主要配 置的属性有:

    • path:路径,即URL路径,每个JSON对象的此属性值必须是唯一的,Vue将根据用 户访问的URL加载对应的视图组件
    • name:名称,可忽略,如果配置此属性,则每个JSON对象的此属性值必须是唯一 的
    • component:视图组件,当访问的URL匹配path时,此视图组件将被显示,在配置 此属性的值时,需分析此视图组件是否为动态导入(懒加载)的
      • 默认即导入:当客户端首次访问此服务时,就会导入此视图组件,需通过此文件顶部通 过import语句导入,且component属性的值就是import时指定的视图组件名,每个工 程中通过此方式导入的视图组件应该非常少
      • 动态导入:取值是使用ES6中的import()返回的Promise对象,相比之下,import语句 是默认即导入的,而import()函数是动态导入的,以避免客户端首次访问此服务时就加 载了大量的视图组件,每个工程中的绝大部分视图组件都应该是这种方法导入的

注意:以上语法格式需要Babel支持,否则将无法正常编译打包

5 使用ElementUI

5.1 Element UI

Element UI是一套采用 Vue 2.0 作为基础框架实现的组件库,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的组件库,提供了配套设计资源,帮助网站快速成型。

Element UI的官方网址是:https://element.eleme.cn/#/zh-CN

5.2 安装Element UI

npm i element-ui -S

npm install --save element-ui

安装完成后在,在工程的main.js中导入并使用Element UI

//导入Element UI
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI);

//使用Element UI
Vue.use(ElementUI);

main.js代码如下:

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
//导入ElementUI
import ElementUI from "element-ui"
import "element-ui/lib/theme-chalk/index.css"

//使用ElementUI
Vue.use(ElementUI)

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

实现居中显示的两种方式:

  • 传统html+css的方式
<div style="width: 500px; margin: 0 auto;">
	 <!-- 页面元素 --> 
</div>
  • 通过ElementUI的方式
<el-row type="flex" justify="center">
<el-col :span="8"><!-- 将24分成3等份,每份占8, 可以调整 -->
<!-- 页面元素 -->
</el-col>
</el-row>

5.3 登录页面案例

  1. 首先通过ElementUI官方文档:https://element.eleme.cn/#/zh-CN/component/installation找到相似的演示
    在这里插入图片描述

  2. 将对应的代码复制到App.vue的id为app的div标签中,将style标签删除,如下:

<template>
  <div id="app">
    <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
      <el-form-item label="密码" prop="pass">
        <el-input type="password" v-model="ruleForm.pass" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="确认密码" prop="checkPass">
        <el-input type="password" v-model="ruleForm.checkPass" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="年龄" prop="age">
        <el-input v-model.number="ruleForm.age"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
        <el-button @click="resetForm('ruleForm')">重置</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
  export default {
    data() {
      var checkAge = (rule, value, callback) => {
        if (!value) {
          return callback(new Error('年龄不能为空'));
        }
        setTimeout(() => {
          if (!Number.isInteger(value)) {
            callback(new Error('请输入数字值'));
          } else {
            if (value < 18) {
              callback(new Error('必须年满18岁'));
            } else {
              callback();
            }
          }
        }, 1000);
      };
      var validatePass = (rule, value, callback) => {
        if (value === '') {
          callback(new Error('请输入密码'));
        } else {
          if (this.ruleForm.checkPass !== '') {
            this.$refs.ruleForm.validateField('checkPass');
          }
          callback();
        }
      };
      var validatePass2 = (rule, value, callback) => {
        if (value === '') {
          callback(new Error('请再次输入密码'));
        } else if (value !== this.ruleForm.pass) {
          callback(new Error('两次输入密码不一致!'));
        } else {
          callback();
        }
      };
      return {
        ruleForm: {
          pass: '',
          checkPass: '',
          age: ''
        },
        rules: {
          pass: [
            { validator: validatePass, trigger: 'blur' }
          ],
          checkPass: [
            { validator: validatePass2, trigger: 'blur' }
          ],
          age: [
            { validator: checkAge, trigger: 'blur' }
          ]
        }
      };
    },
    methods: {
      submitForm(formName) {
        this.$refs[formName].validate((valid) => {
          if (valid) {
            alert('submit!');
          } else {
            console.log('error submit!!');
            return false;
          }
        });
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      }
    }
  }
</script>
  1. 删除不必要的无关文件
    删除router/index.js中不必要的配置,包括:
  • 删除import HomeView from ‘…/views/HomeView.vue’
  • 删除routes常量中各对象(值为空数组即可)
  • 删除src/components/HelloWorld.vue – 删除src/views/HomeView.vue
  • 删除src/views/AboutView.vue

router/index.js文件内容如下:

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

项目结构如下:
在这里插入图片描述

  1. App.vue删掉一些没有用的方法和标签并修改最终修改如下:

注意:自定义校验 callback 必须被调用。更多高级用法可参考 async-validator

<template>
  <div id="app">
    <el-row type="flex" justify="center">
     <el-col :span="8">
       <h1 style="text-align: center">用户登录</h1>
       <el-divider></el-divider>
       <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
         <el-form-item label="用户名" prop="username">
           <el-input v-model="ruleForm.username"></el-input>
         </el-form-item>
         <el-form-item label="密码" prop="password">
           <el-input type="password" v-model="ruleForm.password" autocomplete="off"></el-input>
         </el-form-item>
         <el-form-item>
           <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
           <el-button @click="resetForm('ruleForm')">重置</el-button>
         </el-form-item>
       </el-form>
     </el-col>
    </el-row>

  </div>
</template>

<style>
  * {
    font-family:"Nicrosoft YaHei","微软雅黑",Arial,sans-serif,
    "Helvetica Neue", Helvetica,
    "PingFang sc","Hiragino Sans GB";
  }
</style>
<script>
  export default {
    data() {
      var checkUsername = (rule, value, callback) => {
        if (!value) {
          return callback(new Error('用户名不能为空'));
        }
        callback();
      };
      var validatePass = (rule, value, callback) => {
        if (value === '') {
          callback(new Error('请输入密码'));
        }
      };
      return {
        ruleForm: {
          password: '',
          username: ''
        },
        rules: {
          password: [
            { validator: validatePass, trigger: 'blur' }
          ],
          username: [
            { validator: checkUsername, trigger: 'blur' }
          ]
        }
      };
    },
    methods: {
      submitForm(formName) {
        this.$refs[formName].validate((valid) => {
          if (valid) {
            alert('submit!');
          } else {
            console.log('error submit!!');
            return false;
          }
        });
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      }
    }
  }
</script>

效果:
在这里插入图片描述

6 使用Axios

6.1 Axios

  • axios是一个易用、简洁且高效的http库,主要用于发起HTTP请求,并 获取响应的结果, 底层原理是ajax。
  • axios的官方网址是:http://www.axios-js.com/
  • axios的主要特点有:
    • 从浏览器中创建 XMLHttpRequests
    • 从 node.js 创建 http 请求 – 支持 Promise API
    • 拦截请求和响应 – 转换请求数据和响应数据
    • 取消请求
    • 自动转换 JSON 数据
    • 客户端支持防御 XSRF

6.3 Axios的安装

npm i axios -S

npm install --save axios

安装完成后,也需要在main.js中添加配置,配置代码为:

 import axios from 'axios' 
 
 Vue.prototype.axios = axios

6.4 发起POST请求

//添加
axios.post("/books",this.formData).then((res)=>{
    //判断当前操作是否成功
    if(res.data.flag){
        //1.关闭弹层
        this.dialogFormVisible = false;
        this.$message.success(res.data.msg);
     }else{
        this.$message.error(res.data.msg);
     }
}).finally(()=>{
     //2.重新加载数据
     this.getAll();
});

6.5 发起DELETE请求

//删除
axios.delete("/books/"+row.id).then((res)=>{
     if(res.data.flag){
     	 this.$message.success("删除成功");
     }else{
         this.$message.error("数据同步失败,自动刷新");
     }
}).finally(()=>{
    //2.重新加载数据
    this.getAll();
});

6.6 发起PUT请求

//修改
axios.put("/books",this.formData).then((res)=>{
    //判断当前操作是否成功
    if(res.data.flag){
	    //1.关闭弹层
	    this.dialogFormVisible4Edit = false;
	    this.$message.success("修改成功");
    }else{
        this.$message.error("修改失败");
    }
}).finally(()=>{
    //2.重新加载数据
    this.getAll();
});

6.7 发起GET请求

//根据id获取数据
axios.get("/books/"+row.id).then((res)=>{
    if(res.data.flag && res.data.data != null ){
    this.dialogFormVisible4Edit = true;
    this.formData = res.data.data;
}else{
    this.$message.error("数据同步失败,自动刷新");
}
}).finally(()=>{
    //2.重新加载数据
    this.getAll();
});

5 Vue CLI的嵌套路由

5.1 <router-view>

将需要改变的部分使用<router-view/>代替,就会形成最外部(页面所有部分)是<router-view/> 的同时,内部还有一个<router-view/>(右侧的大区域),在配置路由 时,就需要使用到嵌套路由的做法了。
在这里插入图片描述
在在router/index.js中

const routes = [ 
	{ 
		path: '/', 
		component: HomeView 
	},
	{ 
		path: '/about', 
		component: () => import('../views/AboutView.vue') 
	} 
];

而嵌套路由则需要在原路由的某对象中添加children属性,此属性仍是一 个数组,其内部的配置方式与routes常量是相同的,例如:

const routes = [
	{
		path: '/admin',
		component: () => import('../views/AdminView.vue'),
		 children: [
			{
				path: 'user/list'
				component: () => import('../views/admin/UserListView.vue') },
			{
				path: 'user/add-new'
				component: () => import('../views/admin/UserAddNewView.vue')
			}
	]
	}
];

5.2 路由守卫

页面的标题栏一直没有设置,在实际开发时,各 页面的标题栏显示的文本可能是不同的,可通过Vue CLI的路由守卫及元数据实现,在router/index.js中,配置每个路由信息时,可以添加meta 元数据,在这里设置标题文字,路由守卫可在发生路由跳转时执行特定的 操作,例如全局前置守卫就可以在每次路由跳转之前执行,在此时设置标 题文本即可。

5.3 案例

项目结构
在这里插入图片描述

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
//导入ElementUI
import ElementUI from "element-ui"
import "element-ui/lib/theme-chalk/index.css"

//使用ElementUI
Vue.use(ElementUI)

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

route/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'

Vue.use(VueRouter)

const routes = [
    {
        path: '/',
        component: HomeView,
        meta: {
            title: '主页'
        }
    },
    {
        path: '/admin/',
        redirect: '/admin/list',//重定向,当访问admin时,重定向到/admin/list路径,就是下面的用户列表
        component: () => import('../views/AdminView.vue'),
        children: [
            {
                path: 'list',
                component: () => import('../views/admin/UserListView.vue'),
                meta: {
                    title: '用户列表'
                }

            },
            {
                path: 'add',
                component: () => import('../views/admin/UserAddView.vue'),
                meta: {
                    title: '新增用户'
                }
            },
            {
                path: 'image',
                component: () => import('../views/admin/ImageView.vue'),
                meta: {
                    title: '查看图片'
                }
            }
        ]
    },
    {
        path: '/login',
        component: () => import('../views/LoginView.vue'),
        meta: {
            title: '登录'
        }
    }
]

const router = new VueRouter({
    mode: 'history',
    base: process.env.BASE_URL,
    routes
})

//路由守卫
router.beforeEach((to, from, next) => {
    if (to.meta.title) {
        document.title = to.meta.title
    }
    next()
})

export default router

App.vue

<template>
  <div id="app">
    <nav v-show="path ==='/login' || path ==='/'">
      <router-link to="/">首页</router-link> |
      <router-link to="/login">登录</router-link>|
      <router-link to="/admin">后台管理</router-link>
    </nav>
    <router-view/>
  </div>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
}

nav {
  padding: 30px;
  text-align: center;
}

nav a {
  font-weight: bold;
  color: #2c3e50;
}

nav a.router-link-exact-active {
  color: #42b983;
}
</style>

<script>
  export default {
    name: 'App',
    data(){
      return{
        path:''
      }
    },
    components: {
    },
    // 判断路由
    mounted() {
      this.path = this.$route.path;
      // console.log(this.$route.path)
    },
    watch:{
      $route(to,from){
        this.path = to.path
      }
    }
  }
</script>

views/LoginView.vue

<!--这是自己再次单独写的登录-->
<template>
    <div id="app">
        <el-row type="flex" justify="center">
            <el-col :span="8">
                <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
                    <el-form-item label="用户头像">
                        <el-image preview-src-list style="width: 100px" :src="ruleForm.avatarUrl"></el-image>
                    </el-form-item>
                    <el-form-item label="用户名" prop="username">
                        <el-input v-model="ruleForm.username"></el-input>
                    </el-form-item>
                    <el-form-item label="密码" prop="password">
                        <el-input type="password" v-model="ruleForm.password" autocomplete="off"></el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
                        <el-button @click="resetForm('ruleForm')">重置</el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>

    </div>
</template>
<script>
    export default {
        data() {
            var checkUsername = (rule, value, callback) => {
                if (!value) {
                    return callback(new Error('年龄不能为空'));
                }
                callback();
            };
            var validatePassword = (rule, value, callback) => {
                if (value === '') {
                    callback(new Error('请输入密码'));
                }
                callback();
            };
            return {
                ruleForm: {
                    password: '888888',
                    username: 'admin',
                    avatarUrl: ''
                },
                rules: {
                    password: [
                        {validator: validatePassword, trigger: 'blur'}
                    ],
                    username: [
                        {validator: checkUsername, trigger: 'blur'}
                    ]
                }
            };
        },
        methods: {
            submitForm(formName) {
                this.$refs[formName].validate((valid) => {
                    // alert('submit!');
                    this.ruleForm.avatarUrl = 'https://portrait.gitee.com/uploads/avatars/user/3114/9344141_huang-ren-1_1649866911.png!avatar200';
                    if (valid) {
                        this.axios.post("http://localhost:18080/user/login", this.ruleForm).then((res) => {
                            console.log(res.data);
                            let json=res.data;
                            let status = json.state;
                            if (status == 200) {
                                console.log(this.ruleForm.avatarUrl);
                                this.$notify({
                                    title: '登录成功',
                                    message: '欢迎您, 尊贵的' + json.data.username + '用户',
                                    type: 'success'
                                });
                            } else {
                                let title=json.message.split(",")[0];
                                let message=json.message.split(",")[1];
                                this.$notify.error({
                                    title:title,
                                    message:message
                                })
                            }
                        });
                    } else {
                        console.log('error submit!!');
                        return false;
                    }
                });
            },
            resetForm(formName) {
                this.$refs[formName].resetFields();
            }
        }
    }
</script>
<style>
    * {
        font-family: "Nicrosoft YaHei", "微软雅黑", Arial, sans-serif,
        "Helvetica Neue", Helvetica,
        "PingFang sc", "Hiragino Sans GB";
    }
</style>

views/HomeView.vue

<template>
  <div class="home" style="text-align: center">
    <img alt="Vue logo" src="../assets/EI9.png">
  </div>
</template>

AdminView.vue

<template>
    <div class="admin">
        <!--整个后台管理页面的容器, 内部为上下结构-->
        <el-container>
            <!--头部-->
            <el-header class="layout-header">
                <span id="s1">后台管理系统</span>
                <router-link to="/">首页</router-link>
            </el-header>
            <el-container class="layout-body">
                <!--侧边栏-->
                <el-aside class="layout-aside">
                    <el-menu
                            router="true"
                            default-active="1-1"
                            class="el-menu-vertical-demo"
                            @open="handleOpen"
                            @close="handleClose"
                            background-color="#9ED3D7"
                            text-color="#fff"
                            active-text-color="#409EFF">
                        <el-submenu index="1">
                            <template slot="title">
                                <i class="el-icon-location"></i>
                                <span>用户管理</span>
                            </template>
                            <el-menu-item index="list">用户列表</el-menu-item>
                            <el-menu-item index="add">新增用户</el-menu-item>
                            <el-submenu index="1-3">
                                <template slot="title">图片</template>
                                <el-menu-item index="image">查看图片</el-menu-item>
                            </el-submenu>
                        </el-submenu>
                    </el-menu>
                </el-aside>
                <!--主体-->
                <el-main>
                    <router-view/>
                </el-main>
            </el-container>
        </el-container>
    </div>
</template>

<style>
    * {
        margin: 0;
    }

    .layout-header {
        background: #71BEC4;
        color: #fff;
    }

    #s1 {
        line-height: 60px;
    }

    .layout-header a {
        text-decoration: none;
        float: right;
        right: 20px;
        color: white;
        line-height: 60px;
    }

    .layout-body {
        position: absolute;
        top: 60px;
        bottom: 0;
        left: 0;
        right: 0;
    }

    .layout-aside {
        background-color: #9ED3D7;
        color: #fff;
    }
</style>

<script>
    export default {
        methods: {
            handleOpen(key, keyPath) {
                console.log(key, keyPath);
            },
            handleClose(key, keyPath) {
                console.log(key, keyPath);
            }
        }
    }
</script>

views/admin/UserListView.vue

<template>
    <div>
        <h1>这是用户列表</h1>
        <img width="690" alt="Vue logo" src="../../assets/img.jpg">
    </div>
</template>

views/admin/UserAddView.vue

<template>
    <div>
        <h1>这是新增用户</h1>
        <img width="690" alt="Vue logo" src="../../assets/image.jpeg">
    </div>
</template>

views/admin/ImageView.vue

<template>
  <div style="text-align: center">
    <h2>嘤嘤嘤</h2>
    <img width="690" alt="Vue logo" src="../../assets/image1.jpg">
  </div>
</template>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值