1、环境准备
# 1. 官网下载node.js
http://nodejs.cn/download/
# 2. 配置node.js环境变量
windows系统:环境变量添加以下配置
NODE_HOME = nodejs安装目录
PATH = %NODE_HOME%/bin
# 3. 验证nodejs是否安装成功
node -v
# 4. npm简单介绍
node package manager nodejs包管理工具
maven 管理java后端依赖 远程仓库(中心仓库) 阿里云镜像
npm 管理前端系统依赖远程仓库(中心仓库) 配置淘宝镜像
# 5.配置淘宝镜像
配置淘宝镜像
npm config set registry https://registry.npm.taobao.org
验证是否设置成功
npm config get registry
# 6.配置全局修改npm下载依赖配置
npm config set cache "D:java
odeJS
ode_modules
pm-repo
pm-cache"
npm config set prefix "D:java
odeJS
ode_modules
pm-repo
pm_global"
修改完成之后,再次npm config ls 就会看到变化。而且.npmrd文件也会有变化,这个文件在C盘的用户目录下,比如C:UsersAdministrator。
# 7.检测node.js环境配置
查看npm当前配置 npm config ls -l
2、安装nodejs脚手架
# 0、卸载@vue/cli脚手架命令
npm uninstall -g @vue/cli
# 1、vue cli 官网
https://cn.vuejs.org/
# 2、安装 vue-cli 版本2
npm install -g vue-cli
# 3、安装 @vue/cli 版本3
npm install -g @vue/cli
3、创建第一个vue脚手架项目
初始化
# 1、创建第一个脚手架项目
vue init webpack 项目名
# 2、理解开发方式,一切皆组件
js、css、html
开发一个一个xxx.vue(组件),将多个组件组合成前端框架系统
D:java odeJS ode_modules pm-repo pm_globalvue.cmd
在intellij中开发vue
- intellij插件商店下载Vue.js插件
- 配置node服务器启动命令
vue项目初始结构目录及作用
4、如何开发vue脚手架
vue-cli项目中一切皆组件
- 组件中的MVVM
main.js主入口
- 一个常规组件
<template>
<div>
<h1>用户模块</h1>
<h1>内容</h1>
<table border="1">
<tr>
<td>id</td>
<td>name</td>
<td>age</td>
<td>操作</td>
<td></td>
</tr>
<!--循环-->
<tr v-for="user in users">
<!--第一种方式取值-->
<td v-text="user.id"></td>
<!--第二种方式取值-->
<td>{{user.name}}</td>
<td>{{user.age}}</td>
<td><a href="">删除</a> <a href="">修改</a></td>
</tr>
</table>
<!--使用导入的组件-->
<Footer></Footer>
</div>
</template>
<script>
import Footer from "./Footer"; // 导入Footer公共页脚组件
export default { // 导出默认组件
name: "User", // 组件名称
data() { // 当前组件拥有数据
return {
users: [
{id: 1, name: '李小龙', age: 18}, // 伪造的数据
{id: 2, name: '卡特玲娜', age: 0} // 伪造的数据
]
}
},
methods: {}, // 当前组件拥有的方法
components: { // 在当前组件中祖册其它组件
Footer
},
created() { // created生命周期,通过执行axios的API与后端springboot接口通信获得数据到data上
}
}
</script>
<style scoped>
/*scoped:表示样式只在当前组件中起作用*/
</style>
- 路由文件:router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from "../components/Home";
import User from "../components/User";
import Student from "../components/Student";
Vue.use(Router) // 全局Vue实例注册Router路由
export default new Router({
mode:'history', // 去掉路径前的#
routes: [// 为组件配置路由映射路径
{path: '/',redirect:"/home"}, // 重定向
{path: '/home', name: 'Home', component: Home},
{path: '/user', name: 'User', component: User},
{path: '/student', name: 'Student', component: Student}
]
})
- 在脚手架中使用axios异步通信库
# 1.安装axios
npm install axios --save -dev
# 2.配置main.js,引入axios
import axios from "axios";
Vue.prototype.$http=axios; // 修改vue内部的$http(异步)为axios(异步)
# 3.使用axios
在需要发送异步请求的位置使用:
this.$http.get("url").then((res)=>{}),
this.$http.post("url").then((res)=>{})发送异步请求
# 4.接口模拟平台
提供自定义访问接口,返回预期数据
http://rap2.taobao.org/account/login
- VUE-CLI 脚手架项目打包和部署
# 1.在package.json的同级目录下,执行
npm run build
vue脚手架打包的项目必须在服务器上运行,不能双击运行
# 2.打包之后项目中的变化
dist目录就是vue脚手架的生产目录,将其复制到服务器直接部署
# 3.注意
如果vue前端系统路径采用的是model:history模式,不带#的路径模式,可能出现找不到路径的情况
Vue项目build后,图片加载不出来解决方案
vue项目,build之后会对图片进行处理,具体处理的方式是在文件webpack.base.conf.js中,有如下代码:
module: {
rules: [
{
test: /.(png|jpe?g|gif|svg)(?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000, // 1k-----限制文件的大小
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
}
]
}
以上代码中,使用url-loader对图片的大小进行限制,在limit之内,webpack会将图片转化为base64,超出limit限制,交给file-loader处理。如果在limit范围之内,不会出现图片加载不出来的情况;
超出limit,webpack会将处理后的图片放在dist/static/img/中,此时加载图片将会显示不出来。
具体做法如下:
1、在config/index.js文件内,修改代码: (列出index.js的部分代码)
assetsPublicPath字段值由之前的'/'改为'./';
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: './',
}
2、在webpack.prod.conf.js文件内,output字段,添加代码(publicPath: './'):
output: {
publicPath: './', // 添加的代码
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
3、在utils.js文件里添加 publicPath:'../../',代码如下:
// (which is the case during production build)
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader',
publicPath: '../../' // 添加的代码
})
} else {
return ['vue-style-loader'].concat(loaders)
}
以上步骤操作完后,执行命令:npm run build
在build后,dist中的index.html页面的link、script标签的引入路径变为相对路径;同时,相关的图片路径,也变变为相对路径,此时部署项目,不再出现图片路径404。
Element UI 起步
-
掌握vue,vue脚手架的基本知识
-
初始化一个前端vue脚手架项目
-
项目安装Element UI
# 1、下载element-UI依赖到当前项目中
npm i element-ui -S
# 2、指定当前项目使用element-ui依赖
main.js配置导入。
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 声明(注册)在当前vue脚手架项目使用element-ui
Vue.use(ElementUI)
src源码
- main.js
import Vue from 'vue' // 导入vue
import App from './App' // 导入根组件
import router from './router' // 导入路由
import ElementUI from 'element-ui'; // 导入elementUI
import 'element-ui/lib/theme-chalk/index.css'; // 导入样式
import axios from "axios"; // 导入axios通信模块
Vue.prototype.$http = axios; // 修改vue内部的$http(异步)为axios(异步)通信机制
Vue.config.productionTip = false // 浏览器console控制台提示
Vue.use(ElementUI) // 注册elementUI
new Vue({
el: '#app', // vue接管根挂载点
router, // 路由组件
components: {App},
template: '<App/>'
})
- index.js
import Vue from 'vue' // 导入全局vue
import Router from 'vue-router'
import Index from "../components/Index"; // 导入首页
import List from "../components/user/List"; // 导入用户列表页
// 注册路由
Vue.use(Router)
export default new Router({
routes: [ // 路由规则列表
{path: "/", redirect: "/index"},
{path: "/index", name: "Index", component: Index},
{path: "/users", name: "users", component: List},
]
})
- App.vue
<template>
<div id="app"><!--根挂载点-->
<el-container><!--el容器-->
<el-header><!--容器头部-->
<!--导航栏菜单-->
<el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect">
<el-menu-item index="/index">主页</el-menu-item>
<el-menu-item index="/users">用户管理</el-menu-item>
<el-menu-item index="/msgs">消息中心</el-menu-item>
<el-menu-item index="/orders">订单管理</el-menu-item>
</el-menu>
</el-header>
<el-main><!--容器主体部分-->
<router-view/><!--路由控制视图变化的区域-->
</el-main>
</el-container>
</div>
</template>
<script>
export default { // 配置导出
name: 'App', // 组件命名
data() { // 数据
return {
activeIndex: this.$route.path, // 激活连接下划蓝线标识
};
},
methods: { // 方法
handleSelect(key, keyPath) { // 绑定事件:点击菜单
console.log(key, keyPath);
this.$router.push(key) // 跳转视图
}
}
}
</script>
<style>
</style>
- Index.vue
<template>
<el-carousel indicator-position="outside"><!--跑马灯-->
<el-carousel-item v-for="item in imgs" :key="item"><!--遍历图片-->
<el-image :src="item" style="height: 100%; 100%" fit="fill"><!--设置样式-->
</el-image>
</el-carousel-item>
</el-carousel>
</template>
<script>
// 导入组件
import homeImg1 from '../assets/indeximages/1.jpg';
import homeImg2 from '../assets/indeximages/2.jpg';
import homeImg3 from '../assets/indeximages/3.jpg';
import homeImg4 from '../assets/indeximages/4.jpg';
import homeImg5 from '../assets/indeximages/5.jpg';
import homeImg6 from '../assets/indeximages/6.jpg';
import homeImg7 from '../assets/indeximages/7.jpg';
import homeImg8 from '../assets/indeximages/8.jpg';
import homeImg9 from '../assets/indeximages/9.jpg';
export default {
name: "Index",
data() {
return {imgs: [homeImg1,homeImg2,homeImg3,homeImg4,homeImg5,homeImg6,homeImg7,homeImg8,homeImg9,]}
}
}
</script>
<style scoped>
</style>
- /user/List.vue
<template>
<div>
<!--遍历展示数据-->
<el-table
:data="tableData.filter(data => !search || data.name.toLowerCase().includes(search.toLowerCase()))"
style=" 100%">
<!--编号列-->
<el-table-column
label="编号"
width="180">
<template slot-scope="scope">
<p>{{ scope.row.id }}</p>
</template>
</el-table-column>
<!--姓名列-->
<el-table-column
label="姓名"
width="180">
<template slot-scope="scope">
<el-tag size="medium">{{ scope.row.name }}</el-tag>
</template>
</el-table-column>
<!--生日-->
<el-table-column
label="生日"
width="180">
<template slot-scope="scope">
<i class="el-icon-potato-strips"></i>
<span style="margin-left: 10px">{{ scope.row.bir }}</span>
</template>
</el-table-column>
<!--性别-->
<el-table-column
label="性别"
width="180">
<template slot-scope="scope">
<p>{{ scope.row.sex }}</p>
</template>
</el-table-column>
<!--搜索查找-->
<el-table-column
align="right">
<template slot="header" slot-scope="scope">
<el-input
v-model="search"
size="mini"
placeholder="输入姓名关键字搜索"/>
</template>
</el-table-column>
<!--修改、删除操作-->
<el-table-column>
<template slot-scope="scope">
<el-button
size="mini"
@click="handleEdit(scope.$index, scope.row)">编辑
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<!--分页条-->
<div class="block" style="text-align: center">
<el-pagination
layout="prev, pager, next,jumper,total,sizes"
:total="total"
:page-sizes="[1,2, 4, 6, 8]"
:page-size="2"
prev-text="上一页"
next-text="下一页"
background
@size-change="changeSize"
@current-change="changePage"
@prev-click="preClick"
@next-click="nextClick"
>
</el-pagination>
</div>
<!--添加按钮-->
<el-button type="success" size="mini" style="margin-top: 20px" @click="add">添加</el-button>
<!--添加保存用户表单-->
<transition name="el-zoom-in-center">
<div v-show="show" class="transition-box">
<el-form required :rules="rules" ref="userForm" :model="form" label-suffix=":" label-width="80px">
<!--表单id项-->
<el-form-item hidden>
<el-input v-model="form.id" class="inputSize"></el-input>
</el-form-item>
<!--表单name项-->
<el-form-item label="用户姓名" prop="name" label-width="100px">
<el-input v-model="form.name" class="inputSize"></el-input>
</el-form-item>
<!--表单bir项-->
<el-form-item label="生日" label-width="100px" prop="bir">
<el-date-picker type="date" placeholder="选择日期" v-model="form.bir" class="inputSize">
</el-date-picker>
</el-form-item>
<!--表单sex项-->
<el-form-item label="性别" label-width="100px" prop="sex">
<el-radio-group v-model="form.sex">
<el-radio label="男"></el-radio>
<el-radio label="女"></el-radio>
</el-radio-group>
</el-form-item>
<!--表单address项-->
<el-form-item label="用户地址" label-width="100px" prop="address">
<el-input v-model="form.address" class="inputSize"></el-input>
</el-form-item>
<!--表单操作项-->
<el-form-item label-width="350px">
<el-button type="primary" @click="onSubmit('userForm')">保存用户信息</el-button>
<el-button @click="resetForm('userForm')">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
</div>
</template>
<script>
export default {
name: "List",
data() {
return {
tableData: [], //展示用户信息数据表
search: '', // 搜索
total: 0,
pageNow: 1,
pageSize: 2,
show: false, // 控制添加,修改表单标志位
form: { // 添加、修改绑定数据
id: '',
name: '',
bir: '',
sex: '男',
address: ''
},
rules: { // 表单验证规则
name: [
{required: true, message: '请输入用户名称', trigger: 'blur'}, // 没输入数据时失去焦点提示信息
{min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: "blur"}],
bir: [{required: true, message: '请输入用户生日', trigger: 'blur'}],
sex: [{required: true, message: '请输入用户性别', trigger: 'blur'}],
address: [{required: true, message: '请输入用户地址', trigger: 'blur'}]
}
}
},
methods: {
handleEdit(index, row) {
console.log(index, row);
this.show = true
this.form = row;
this.$http.post("http://localhost:8989/user/del", row).then((resp => {
if (resp.data == "success") {
this.$message({message: "修改成功", type: "success"});
this.findAll();
} else {
this.$message.error('修改失败');
}
}))
},
handleDelete(index, row) {
console.log(index, row);
console.log(row.id)
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http.post("http://localhost:8989/user/del", new String(row.id)).then((res) => {
if (res.data == "success") {
this.$message({message: "删除成功", type: "success"});
this.findAll();
} else {
this.$message.error('删除失败');
}
});
})
},
changePage(page) {
this.pageNow = page
this.findAll()
console.log(page)
},
changeSize(pageSize) {
this.pageSize = pageSize
this.findAll()
console.log(pageSize)
},
preClick(pageChange) {
this.pageNow = pageChange
this.findAll()
console.log(pageChange)
},
nextClick(pageChange) {
this.pageNow = pageChange
this.findAll()
console.log(pageChange)
},
resetForm(userForm) {
this.$refs[userForm].resetFields();
this.show = true
this.form = {sex: '男'};
},
add() {
this.show = !this.show
this.form = {sex: '男'};
},
onSubmit(userForm) {
this.$refs[userForm].validate((valid) => {
if (valid) {
if (this.form.id) {
this.$confirm('是否确认要更新该用户信息', '提示', {
cancelButtonText: '取消',
confirmButtonText: '确定',
type: 'warning'
}).then(() => {
this.$http.post("http://localhost:8989/user/update", this.form).then((response) => {
console.log(response.data);
if (response.data == "success") {
this.$message({
message: '更新成功',
type: 'success'
});
// 清除表单信息
this.show = false;
this.findAll();
} else {
this.$message.error('更新失败');
}
});
})
} else {
this.$http.post("http://localhost:8989/user/save", this.form).then((response) => {
console.log(response.data);
if (response.data == "success") {
this.$message({
message: '添加成功',
type: 'success'
});
// 清除表单信息
this.form = {sex: '男'};
this.show = false;
this.findAll();
} else {
this.$message.error('添加失败');
}
});
}
} else {
this.$message.error('输入的表单信息不合法');
return false;
}
});
},
findAll() {
var url = "http://localhost:8989/user/findByPage"
if (this.pageNow && this.pageSize) {
url = url + "?pageNow=" + this.pageNow + "&pageSize=" + this.pageSize;
} else if (this.pageNow) {
url = url + "?pageNow=" + this.pageNow
} else if (this.pageSize) {
url = url + "?pageSize=" + this.pageSize
}
this.$http.get(url).then((response) => {
this.tableData = response.data.users
this.total = response.data.countUsers
});
}
},
created() {
this.findAll()
},
};
</script>
<style scoped>
/*添加、修改用户表单样式*/
.transition-box {
margin-bottom: 10px;
100%;
height: 300px;
border-radius: 4px;
padding: 40px 20px;
box-sizing: border-box;
margin-right: 20px;
}
/*表单输入框大小,还可以用栅格处理*/
.inputSize {
100%;
}
</style>
效果展示