Vue Cli学习笔记
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 搭建开发环境
-
node.js安装: 详见node.js安装笔记
-
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结构
[]为文件夹
- [node_modules]工程中使用到的模块,也可以理解为工程的依赖项, 例如Babel、Vue等框架的文件,不手动管理。
需要注意
:如果是从Git或其它位置复制得到的工程,没有此文件夹,需要运行npm install
或者npm i
,否则将无此文件夹及其下的各依赖项,工程将无法正常启动。
-
[public]:工程被编译打包后仍会保留的内容(文件内容可能会在编译打 包过程中修改)
你可以自行在此文件夹下创建子级文件夹,用于存放公共静态资源,例如图片等。 -
public/index.html:默认的主页,通常不修改其内容。
-
[src]:页面源代码,除工程配置以外的所有开发都在此文件夹下
-
[src/assets]:资源文件夹,通常存放图片等, 放置需要经由 Webpack 处理的静态文件。
注意
:仅不需要被程序动态控制的图片放在此处
-
[src/components]:视图组件,通常是可以被其它各页面复用的,是各 个.vue文件。
-
[src/router]:路由控制。
-
src/router/index.js:路由配置文件,除非工程中页面数量较大,或路 由关系复杂,否则使用这1个文件进行路由管理即可。
-
[src/store]:全局数据存储
-
[src/views]:视图组件 ,通常,每个页面在此文件夹都应该有1个对应 的文件,可引用[src/components]下的组件。
-
src/App.vue:默认的主页视图组件。
-
src/main.js:工程的主js文件,通常用于导入工程中将使用的其它库 – 此文件中所有import语句必须在最上方位置,各import语句不区分先后顺序。
-
.gitigore:用于配置使用Git提交工程时将忽略的文件和文件夹 。
-
bable.config.js:Babel的配置文件。
-
package.json:工程的管理配置文件,相当于Maven项目的pom.xml, 在不熟悉的情况下不要手动修改此文件的配置,可能需要关注的主要有:
- scripts:支持的2个npm命令参数,例如npm run serve、npc run build
- dependencies:运行时依赖项
- devDependencies:开发依赖项,将不参与打包
-
package-lock.json:工程的管理配置文件 。
-
README.md:工程的说明文档,用于开发人员编写如何使用、注意事 项、更新日志等内容,使用IntelliJ IDEA首次打开工程时,会自动打开此 文件,此文件的默认内容中提示了工程的运行命令 。
-
vue.config.js:Vue的配置文件。
4.2 视图组件
- 所有以 .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>
- 可以看到此文件中主要有2个节点:
<template>节点:用于设计页面元素,其内部代码可以是标准HTML代码,也可以 是Vue或其它库(例如Element UI)支持的代码
< style> 节点:用于定义样式,语法规则与传统前端技术中完全相同
需要注意
:在<template>必须有且仅有1个直接子节点(通常是<div>节 点),否则将无法通过编译!
- 而默认的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>
- 在以上views/HomeView.vue文件中,第4行代码为:
<HelloWorld msg="欢迎来到你的 Vue CLI"/>
以上代码是基于其在<script>标签内通过以下代码引用了 components/HellowWorld.vue视图组件:
import HelloWorld from '@/components/HelloWorld.vue'
-
在
<HelloWorld>
节点中配置了名为msg值为"Welcome to Your Vue.js App"的属性,而components/HelloWorld.vue中则使用 {{ msg }}应用了传入的值,这是在Vue CLI工程中封装视图组件并引用时 传参的典型方式 -
在components和views下的.vue文件的设计方式是基本相同的,区别在 于components下的视图组件应该是可以被引用的
-
所有视图组件的源代码被修改后,都不需要重启服务,在浏览器可以看到 最新的内容,这是Vue CLI的热部署(热更新)实现的
4.3 路由
-
Vue CLI应用是单页面的,也就是说,在Vue CLI工程的设计思想中,页 面只有1个,只不过页面中的内容是可以动态调整的,所以,无论是使用 不同的URL进行访问,还是页面中触发某个事件后,虽然用户看到了不同 的页面效果,但是,用户看到的其实永远只是1个页面,只是页同中的内 容不同而已,这也就是视图组件源文件中使用
<template>
节点设计页面 元素的原因(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 登录页面案例
-
首先通过ElementUI官方文档:https://element.eleme.cn/#/zh-CN/component/installation找到相似的演示
-
将对应的代码复制到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>
- 删除不必要的无关文件
删除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
项目结构如下:
- 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>