VUE
Vue 的核心库只关注视图层,方便与第三方库或既有项目整合。
HTML + CSS + JS : 视图 : 给用户看,刷新后台给的数据
网络通信 : axios
页面跳转 : vue-router
状态管理:vuex
Vue-UI : ICE , Element UI
前端三要素
HTML (结构) :超文本标记语言(Hyper Text Markup Language) ,决定网页的结构和内容
CSS (表现) :层叠样式表(Cascading Style sheets) ,设定网页的表现样式
JavaScript (行为) :是一种弱类型脚本语言,其源代码不需经过编译,而是由浏览器解释运行,用于控制网页的行为
JavaScript框架
jQuery: 大家熟知的JavaScript框架,优点是简化了DOM操作,缺点是DOM操作太频繁,影响前端性能;在前端眼里使用它仅仅是为了兼容IE6、7、8;
Angular: Google收购的前端框架,由一群Java程序员开发,其特点是将后台的MVC模式搬到了前端并增加了模块化开发的理念,与微软合作,采用TypeScript语法开发;对后台程序员友好,对前端程序员不太友好;最大的缺点是版本迭代不合理(如: 1代-> 2代,除了名字,基本就是两个东西;截止发表博客时已推出了Angular6)
React: Facebook出品,一款高性能的JS前端框架;特点是提出了新概念[虚拟DOM]用于减少真实DOM操作,在内存中模拟DOM操作,有效的提升了前端渲染效率;缺点是使用复杂,因为需要额外学习一门[JSX] 语言;
Vue:一款渐进式JavaScript框架,所谓渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等新特性。其特点是综合了Angular (模块化)和React (虚拟DOM)的优点;
Axios :前端通信框架;因为Vue 的边界很明确,就是为了处理DOM,所以并不具备通信能力,此时就需要额外使用一个通信框架与服务器交互;当然也可以直接选择使用jQuery提供的AJAX通信功能;
前端三大框架:Angular、React、Vue
Vue 是 MVVM 模式的实现者
Model : 模型层,在这里表示JavaScript对象
View : 视图层,在这里表示DOM (HTML操作的元素)
ViewModel : 连接视图和数据的中间件,Vue.js就是MVVM中的ViewModel层的实现者在MVVM架构中,是不允许数据和视图直接通信的,只能通过ViewModel来通信,而ViewModel就是定义了一个Observer观察者
ViewModel 能够观察到数据的变化,并对视图对应的内容进行更新
ViewModel 能够监听到视图的变化,并能够通知数据发生改变
至此,我们就明白了,Vue.js 就是一个MVVM的实现者,他的核心就是实现了DOM监听与数据绑定
第一个VUE程序
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
{{message}}
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script>
var vue = new Vue({
el:"#app",
data:{
message:"hello vue"
}
});
</script>
</body>
</html>
vue基本语法
v-bind
现在数据和DOM已经被建立了关联,所有的东西都是响应式的。我们在控制台操作对象的属性,界面可以实时更新。
我们可以使用v-bind
来绑定元素属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>狂神说Java</p>
<!--view层 模板-->
<div id="app">
<span v-bind:title="message">鼠标悬停几秒钟查看此处动态绑定的提示信息!</span>
</div>
</body>
<!--导入js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
message: "hello,vue"
}
})
</script>
</html>
v-bind等别称为指令,指令带有前缀v-,以表示它们是Vue提供的特殊特性。它们会在渲染的DOM上应用特殊的响应式行为,在这里,这个指令的意思是:将这个元素节点的title
特性和Vue实例的message
属性保持一致
判断-循环
if
v-if,v-else
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层 模板-->
<div id="app">
<h1 v-if="type==='A'">A</h1>
<h1 v-else-if="type==='B'">B</h1>
<h1 v-else>C</h1>
</div>
</body>
<!--导入js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
type: "A"
}
})
</script>
</html>
for
v-for
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>狂神说Java</p>
<!--view层 模板-->
<div id="app">
<li v-for="item in items">
<li v-for="item : items">
姓名:{{item.name}},年龄:{{item.age}}
</li>
</div>
</body>
<!--导入js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
items: [
{name: "zhangsan", age: 12},
{name: "lisi", age: 10},
{name: "wangwu", age: 16}
]
}
})
</script>
</html>
vue绑定事件
v-on:后面跟事件,如v-on:οnclick=“方法名” @οnclick=“方法名”
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>狂神说Java</p>
<!--view层 模板-->
<div id="app">
<button v-on:click="sayHi">Click Me</button>
</div>
</body>
<!--导入js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
message: "你点我干嘛?"
},
methods: {
//方法必须绑定在Vue的Methods对象中,v-on:事件
//sayHi 方法名
//两种书写方法
sayHi: function (event){
}
sayHi: (function (event) {
alert(this.message)
})
}
})
</script>
</html>
Vue双向绑定
什么是双向绑定
Vue.js是一个MVVM框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是Vue.js的精髓之处了。
值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的,非UI控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用vuex,那么数据流也是单项的,这时就会和双向数据绑定有冲突。
在表单中使用双向数据绑定
你可以用v-model指令在表单 <input>
、<textarea>
及<select>
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但v-model本质上不过是语法糖。它负责监听户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
注意:v-model会忽略所有元素的value、checked、selected特性的初始值而总是将Vue实例的数据作为数据来源,你应该通过JavaScript在组件的data选项中声明。
输入框的双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!--view层 模板-->
<div id="app">
<input type="text" value="" v-model="message">{{message}}
</div>
</body>
<!--导入js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
message: "hello,vue"
}
})
</script>
</html>
单选框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!--view层 模板-->
<div id="app">
性别是:
<input type="radio" name="sex" value="男" v-model="sex">男
<input type="radio" name="sex" value="女" v-model="sex">女
<p>选中了谁:{{sex}}</p>
</div>
</body>
<!--导入js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
sex:''
}
})
</script>
</html>
下拉框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层 模板-->
<div id="app">
下拉框:
<select v-model="selected">
<option value="" disabled>-请选择-</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<p>value:{{selected}}</p>
</div>
</body>
<!--导入js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
selected: ""
}
})
</script>
</html>
Vue组件
组件是可复用的Vue
实例,说白了就是一组可以重复使用的模板,跟JSTL的自定义标签、Thymeleaf的th:fragment
等框架有着异曲同工之妙。通常一个应用会以一棵嵌套的组件树的形式来组织:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层 模板-->
<div id="app">
// v-bind缩写 :qing="item"
<qinjiang v-for="item in items" v-bind:qin="item"></qinjiang>
</div>
</body>
<!--导入js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
Vue.component("qinjiang",{
props: ['qin'],
template: '<li>{{qin}}</li>'
})
var vm = new Vue({
el: "#app",
data: {
items: ['Java','Python','Php']
}
})
</script>
</html>
Axios异步通信
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js"></script>
Axios是一个开源的可以用在浏览器端和NodeJS
的异步通信框架,她的主要作用就是实现AJAX异步通信,其功能特点如下:
- 从浏览器中创建
XMLHttpRequests
- 从node.js创建http请求
- 支持Promise API [JS中链式编程]
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防御XSRF (跨站请求伪造)
GitHub: https://github.com/
axios/axios 中文文档: http://www.axios-js.com/
模拟Json数据:
{
"name": "weg",
"age": "18",
"sex": "男",
"url":"https://www.baidu.com",
"address": {
"street": "文苑路",
"city": "南京",
"country": "中国"
},
"links": [
{
"name": "bilibili",
"url": "https://www.bilibili.com"
},
{
"name": "baidu",
"url": "https://www.baidu.com"
},
{
"name": "cqh video",
"url": "https://www.4399.com"
}
]
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层 模板-->
<div id="vue">
<div>{{info.name}}</div>
<a v-bind:href="info.url">点我进入</a>
</div>
</body>
<!--1.导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<!--导入axios-->
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js"></script>
<script>
var vm = new Vue({
el: "#vue",
data: {
items: ['Java','Python','Php']
},
//data:vm的属性
//data():vm方法
data(){
return{
//请求的返回参数,必须和json字符串一样
info:{
name: null,
age: null,
sex: null,
url: null,
address: {
street: null,
city: null,
country: null
}
}
}
},
//钩子函数,链式编程,ES6新特性
mounted(){
//$.axaj()
axios.get("../data.json").then(res => (this.info=res.data))
}
})
</script>
</html>
计算属性
计算出来的结果,保存在属性中
计算属性的重点突出在属性
两个字上(属性是名词),首先它是个属性
其次这个属性有计算
的能力(计算是动词),这里的计算就是个函数;简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;可以想象为缓存!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层 模板-->
<div id="app">
<div>currentTime1: {{currentTime1()}}</div>
<div>currentTime2: {{currentTime2}}</div>
</div>
</body>
<!--导入js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
message: "hello,world!"
},
methods: {
currentTime1: function () {
return Date.now(); // 返回一个时间戳
//每次调用都会刷新数据
}
},
computed: {
//计算属性:methods,computed 方法名不能重名,重名字后,只会调用methods的方法
//在控制台中调用不会刷新数据,在加入this.message;后重新赋值后会刷新数据
currentTime2: function () {
this.message;
// 返回一个时间戳
return Date.now();
}
}
})
</script>
</html>
内容分发:<slot>
Vue.js中我们使用 元素作为承载分发内容的出口,作者称其为插槽,可以应用在组合组件的场景中;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="app">
<todo>
<todo-title slot="todo-title" v-bind:name="title"></todo-title>
<todo-items slot="todo-items" v-for="item in todoItems" v-bind:item="item"></todo-items>
</todo>
</div>
<!--1.导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
//slot 插槽 这个组件要定义在前面不然出不来数据
Vue.component("todo", {
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
<div>'
});
Vue.component("todo-title", {
//属性
props: ['name'],
template: '<div>{{name}}</div>'
});
Vue.component("todo-items", {
props: ['item'],
template: '<li>{{item}}</li>'
});
let vm = new Vue({
el: "#app",
data: {
//标题
title: "图书馆系列图书",
//列表
todoItems: ['三国演义', '红楼梦', '西游记', '水浒传']
}
});
</script>
</body>
</html>
自定义事件分发
通过以上代码不难发现,数据项在Vue的实例中,但删除操作要在组件中完成,那么组件如何才能删除Vue实例中的数据呢?此时就涉及到参数传递与事件分发了,Vue为我们提供了自定义事件的功能很好的帮助我们解决了这个问题;
使用this.$emit (‘自定义事件名’,参数)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="app">
<todo>
<todo-title slot="todo-title" v-bind:name="title"></todo-title>
<todo-items slot="todo-items" v-for="(item,index) in todoItems" v-bind:item="item"
v-bind:index="index" v-on:remove="removeItems(index)"></todo-items>
</todo>
</div>
<!--1.导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
//slot 插槽 这个组件要定义在前面不然出不来数据
Vue.component("todo", {
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
<div>'
});
Vue.component("todo-title", {
//属性
props: ['name'],
template: '<div>{{name}}</div>'
});
Vue.component("todo-items", {
props: ['item','index'],
template: '<li>{{index}}---{{item}} <button @click="remove">删除</button></li>',
methods: {
remove: function (index) {
// this.$emit 自定义事件分发
this.$emit('remove',index)
}
}
});
let vm = new Vue({
el: "#app",
data: {
//标题
title: "图书馆系列图书",
//列表
todoItems: ['三国演义', '红楼梦', '西游记', '水浒传']
},
methods: {
removeItems: function (index) {
console.log("删除了"+this.todoItems[index]+"OK");
this.todoItems.splice(index,1);
}
}
});
</script>
</body>
</html>
vue-cli项目
什么是vue-cli
vue-cli官方提供的一个脚手架,用于快速生成一个vue的项目模板;
预先定义好的目录结构及基础代码,就好比咱们在创建Maven项目时可以选择创建一个骨架项目,这个估计项目就是脚手架,我们的开发更加的快速;
项目的功能:
- 统一的目录结构
- 本地调试
- 热部署
- 单元测试
- 集成打包上线
需要的环境:
Node.js下载安装
Node.js:http://nodejs.cn/download/
安装就是无脑的下一步就好,安装在自己的环境目录下
Git:https://git-scm.com/downloads
镜像:https://npm.taobao.org/mirrors/git-for-windows/
确认nodejs安装成功:
cmd下输入node -v,查看是否能够正确打印出版本号即可!
cmd下输入npm -v,查看是否能够正确打印出版本号即可!
这个npm,就是一个软件包管理工具,就和linux下的apt软件安装差不多!
更改依赖路径的方法:
1、使用npm root -g可查看npm的全局安装路径 :
C:\WINDOWS\system32>npm root -g
E:\nodejs\node_lib\node_prefix\node_modules
2、使用npm config list可查看所有配置:
3、使用npm config set prefix修改npm安装的全局路径;使用npm config set cache命令修改缓存目录;
npm config set cache D:\nodejs\node_cache
npm config set prefix D:\nodejs\node_prefix
更换node.js淘宝镜像
# -g 就是全局安装
npm install cnpm -g
# 或使用如下语句解决npm速度慢的问题
npm install --registry=https://registry.npm.taobao.org
默认安装的位置:C:\Users\administrator\AppData\Roaming\npm
更换全局安装后会安装到 指定路径中
安装vue-cli:
如果更改依赖包环境,需要在环境变量中添加cnpm的路径 cnpm.cmd
添加该路径
(69条消息) ‘cnpm’ 不是内部或外部命令,真正有效解决方法_King-Long的博客-CSDN博客_cnpm不是
cnpm instal1 vue-cli-g
#测试是否安装成功
#查看可以基于哪些模板创建vue应用程序,通常我们选择webpack
vue list
创建vue-cli程序
新建一个空的文件夹如 vue-first
在cmd中进入该目录下
#这里的myvue是顶日名称,可以根据自己的需求起名
vue init webpack myvue
一路都选择no即可;
说明:
- Project name:项目名称,默认回车即可
- Project description:项目描述,默认回车即可
- Author:项目作者,默认回车即可
- Install vue-router:是否安装vue-router,选择n不安装(后期需要再手动添加)
- Use ESLint to lint your code:是否使用ESLint做代码检查,选择n不安装(后期需要再手动添加)
- Set up unit tests:单元测试相关,选择n不安装(后期需要再手动添加)
- Setupe2etests with Nightwatch:单元测试相关,选择n不安装(后期需要再手动添加)
- Should we run npm install for you after the,project has been created:创建完成后直接初始化,选择n,我们手动执行;运行结果! 选择最后一个
初始化并运行
cd myvue 进入创建的项目中
npm install 安装所有的依赖环境 cnpm install
打开idea 将项目在命令中执行运行或者 在该文件下执行命令运行
npm run dev 运行dev
结果
E:\VueCode\vue-first\myvue>npm run dev
> myvue@1.0.0 dev
> webpack-dev-server --inline --progress --config build/webpack.dev.conf.js
(node:9416) [DEP0111] DeprecationWarning: Access to process.binding('http_parser') is deprecated.
(Use `node --trace-deprecation ...` to show where the warning was created)
13% building modules 31/34 modules 3 active ...:\VueCode\vue-first\myvue\src\App.vue{ parser: "babylon" } is deprecated; we now treat it as { parser: "babel" }.
95% emitting
DONE Compiled successfully in 3954ms 11:38:19
I Your application is running here: http://localhost:8080
ctrl+c 停止运行
vue-cli文件说明
- config/index.js
- 端口配置 默认8080
- 配置静态环境文件 默认static
Webpack模块化开发
什么是Webpack
本质上, webpack是一个现代JavaScript应用程序的静态模块打包器(module bundler) 。当webpack处理应用程序时, 它会递归地构建一个依赖关系图(dependency graph) , 其中包含应用程序需要的每个模块, 然后将所有这些模块打包成一个或多个bundle
Webpack是当下最热门的前端资源模块化管理和打包工具, 它可以将许多松散耦合的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分离,等到实际需要时再异步加载。通过loader转换, 任何形式的资源都可以当做模块, 比如Commons JS、AMD、ES 6、CSS、JSON、Coffee Script、LESS等;
伴随着移动互联网的大潮, 当今越来越多的网站已经从网页模式进化到了WebApp模式。它们运行在现代浏览器里, 使用HTML 5、CSS 3、ES 6等新的技术来开发丰富的功能, 网页已经不仅仅是完成浏览器的基本需求; WebApp通常是一个SPA(单页面应用) , 每一个视图通过异步的方式加载,这导致页面初始化和使用过程中会加载越来越多的JS代码,这给前端的开发流程和资源组织带来了巨大挑战。
前端开发和其他开发工作的主要区别,首先是前端基于多语言、多层次的编码和组织工作,其次前端产品的交付是基于浏览器的,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统,这个理想中的模块化系统是前端工程师多年来一直探索的难题。
模块化的演进
原始的Scrip标签
<script src = "module1.js"></script>
<script src = "module2.js"></script>
<script src = "module3.js"></script>
这是最原始的JavaScript文件加载方式,如果把每一个文件看做是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在window对象中,不同模块的调用都是一个作用域。
这种原始的加载方式暴露了一些显而易见的弊端:
全局作用域下容易造成变量冲突
文件只能按照
CommonsJS
服务器端的NodeJS遵循CommonsJS规范,该规范核心思想是允许模块通过require方法来同步加载所需依赖的其它模块,然后通过exports或module.exports来导出需要暴露的接口。
require("module");
require("../module.js");
export.doStuff = function(){};
module.exports = someValue;
优点:
- 服务器端模块便于重用
- NPM中已经有超过45万个可以使用的模块包
- 简单易用
缺点:
- 同步的模块加载方式不适合在浏览器环境中,同步意味着阻塞加载,浏览器资源是异步加载的
- 不能非阻塞的并行加载多个模块
实现:
- 服务端的NodeJS
- Browserify,浏览器端的CommonsJS实现,可以使用NPM的模块,但是编译打包后的文件体积较大
- modules-webmake,类似Browserify,但不如Browserify灵活
- wreq,Browserify的前身
ES6模块
EcmaScript 6标准增加了JavaScript语言层面的模块体系定义。ES 6模块的设计思想, 是尽量静态化, 使编译时就能确定模块的依赖关系, 以及输入和输出的变量。Commons JS和AMD模块,都只能在运行时确定这些东西。
import "jquery"
export function doStuff(){}
module "localModule"{}
优点
容易进行静态分析
面向未来的Ecma Script标准
缺点
原生浏览器端还没有实现该标准
全新的命令,新版的Node JS才支持
实现
Babel
安装Webpack
WebPack是一款模块加载器兼打包工具, 它能把各种资源, 如JS、JSX、ES 6、SASS、LESS、图片等都作为模块来处理和使用。
全局安装webpack插件
npm install webpack -g
npm install webpack-cli -g
测试安装是否成功,若出现版本号说明安装成功
webpack -v
webpack-cli -v
配置
创建 webpack.config.js配置文件
- :入口文件, 指定Web Pack用哪个文件作为项目的入口
- output:输出, 指定WebPack把处理完成的文件放置到指定路径
- module:模块, 用于处理各种类型的文件
- plugins:插件, 如:热更新、代码重用等
- resolve:设置路径指向
- watch:监听, 用于设置文件改动后直接打包
module.exports = {
entry:"",
output:{
path:"",
filename:""
},
module:{
loaders:[
{test:/\.js$/,;\loade:""}
]
},
plugins:{},
resolve:{},
watch:true
}
直接运行webpcka命令打包
使用webpack
步骤:
1、创建空文件项目webpack-study
,用IDEA打开
2、创建一个名为modules的目录,用于放置JS模块等资源文件
3、在modules下创建模块文件,如hello.js
,用于编写JS模块相关代码
hello.js
//暴露一个方法:sayHi
exports.sayHi = function(){
document.write("<div>Hello Webpack</div>");
}
4、在modules下创建一个名为main.js
的入口文件,用于打包时设置entry属性
//require 导入一个模块,就可以调用这个模块中的方法了
var hello = require("./hello"); //类似于new一个对象 然后调用对象
hello.sayHi();
5、在项目目录下创建webpack.config.js
配置文件,使用webpack命令打包 在该项目文件下进行打包
module.exports = {
entry:"./modules/main.js", //程序的入口
output:{
filename:"./js/bundle.js" //打包的文件路径/文件名
}
}
6、在项目目录下创建HTML页面,如index.html
,导入webpack打包后的JS文件
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>狂神说Java</title>
</head>
<body>
<!--前端的模块化开发-->
<script src="dist/js/bundle.js"></script>
</body>
</html>
7、在IDEA控制台中直接执行webpack;如果失败的话,就使用管理员权限运行即可!
8、运行HTML看效果
# 参数--watch 用于监听变化
webpack --watch //当代码发生改变就会重新进行打包
vue-router路由
Vue Router是Vue.js官方的路由管理器。它和Vue.js的核心深度集成, 让构建单页面应用变得易如反掌。包含的功能有:
- 嵌套的路由/视图表
- 模块化的、基于组件的路由配置
- 路由参数、查询、通配符
- 基于Vue js过渡系统的视图过渡效果
- 细粒度的导航控制
- 带有自动激活的CSS class的链接
- HTML5 历史模式或hash模式, 在IE 9中自动降级
- 自定义的滚动行为
一个干净的项目
src/assets/logo.png 图片文件删除
src/components/HelloWorld.vue 删除
APP.vue 多余文件删除后该文件的样式
<template>
<div id="app">
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
安装vue-router 路由 在该项目文件中进行下载
npm install vue-router --save-dev
或
cnpm install vue-router --save-dev
在安装完后在main.js中进行引入 和使用
import VueRouter from 'vue-router' //引入
Vue.use(VueRouter) //显示声明使用
main.js 是所有程序的主路口的样式
App.vue是主界面
测试使用
在该项目下运行
npm run dev
问题:
如果出现"export 'default' (imported as 'VueRouter') was not found in 'vue-router'
这种情况
查看vue-router版本是否过高 降级到3.1.3 然后重新安装
"vue-router": "^3.1.3"
运行 npm或cnpm install 重新安装插件
测试使用
在App.vue页面中添加
<template>
<div id="app">
<h1>一个vue页面</h1>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
如果环境还在运行,则会自动打包进行编译,展示出页面信息说明程序无误。
自定义页面组件
在compontens文件下进行创建:
Content.vue
<template>
</template>
<script>
export default { //export 导出
name: "xxx"
}
</script>
<style scoped> <!-- scoped 作用域 只在当前文件中生效-->
</style>
在App.vue处进行导入
App.vue
<template>
<div id="app">
<h1>一个vue页面</h1>
</div>
</template>
<script>
import Content from './components/Content.vue'
export default {
name: 'App',
comments:{
Content
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
案例:
App.vue 主程序路口
<template>
<div id="app">
<h1>Vue-Router</h1>
<router-link to="/main">首页</router-link> <!--类似于 a 标签-->
<router-link to="/content">内容页</router-link>
<router-view></router-view><!--这个得写 展示视图-->
</div>
</template>
<script>
import Content from './components/Content.vue'
export default {
name: 'App',
comments:{
Content
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
main.js 主程序的样式
import Vue from 'vue'
import App from './App'
import VueRouter from 'vue-router'
//导入创建的路由配置 目录
import router from './router' //自动扫描里面的路由配置
Vue.config.productionTip = false
Vue.use(VueRouter)
/* eslint-disable no-new */
new Vue({
el: '#app',
//配置路由
router,
components: { App },
template: '<App/>'
})
componets/Content.vue 页面的组件
<template>
<h1>内容页</h1>
</template>
<script>
export default {
name: "xxx"
}
</script>
<style scoped>
</style>
componets/Main.vue 页面的组件
<template>
<h1>首页</h1>
</template>
<script>
export default {
name: "Main"
}
</script>
<style>
</style>
创建文件夹router 下,专门存放路由,新建文件 index.js 作为路由配置
import Vue from 'vue'
import VueRouter from 'vue-router'
//导入上面的组件路径
import Content from '../components/Content'
import Main from '../components/Main'
//安装路由
Vue.use(VueRouter);
//配置导出路由
export default new VueRouter({
routes: [
{
//路由的路径 类似java中的 @RequestMapping
path: '/content', // 网址路径
name :'content', //name可以省略
//跳转的组件
component: Content
},
{
//路由的路径
path: '/main', // 网址路径
name :'main',
//跳转的组件
component: Main
}
]
});
项目结构:
- Src
- components:用于存放Vue功能组件
- Content.vue
- Main.vue
- views:用于存放Vue视图组件
- router:用于存放vue-router配置
- index.js
- App.vue
- main.js
- components:用于存放Vue功能组件
Vue+Element
组件地址:组件 | Element
新创建一个项目 vue-element
安装依赖 安装vue-router、element-ui、sass-loader和node-sass四个插件
#进入工程目录
cd hello-vue
#安装vue-routern
npm install vue-router --save-dev
#安装element-ui
npm i element-ui -S
#安装依赖
npm install
# 安装SASS加载器
cnpm install sass-loader node-sass --save-dev
#启功测试
npm run dev
Npm命令解释:
- npm install moduleName:安装模块到项目目录下
- npm install -g moduleName:-g的意思是将模块安装到全局,具体安装到磁盘哪个位置要看npm config prefix的位置
- npm install -save moduleName:–save的意思是将模块安装到项目目录下, 并在package文件的dependencies节点写入依赖,-S为该命令的缩写
- npm install -save-dev moduleName:–save-dev的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖,-D为该命令的缩写
创建登录页面
把没有用的初始化东西删掉!
在源码目录中创建如下结构:
- assets:用于存放资源文件
- components:用于存放Vue功能组件
- views:用于存放Vue视图组件
- router:用于存放vue-router配置
在views下创建 Main.vue
<template>
<div>首页</div>
</template>
<script>
export default {
name:"Main"
}
</script>
<style scoped>
</style>
在views目录下创建Login.vue
<template>
<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>
</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>
<style scoped>
</style>
配置路由样式 index.js
import Vue from "vue";
import Router from 'vue-router';
import Main from '../views/Main'
import Login from '../views/Login'
Vue.use(Router);
export default new Router({
routes:[
{
path: '/main',
component:Main
},
{
path: '/login',
component:Login
}
]
})
编写主程序页面 App.vue
<template>
<div id="app">
<!-- <router-link></router-link> -->
<router-view></router-view><!--会自动展示页面-->
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
</style>
主程序演示 main.js
import Vue from 'vue'
import App from './App'
//扫描路由的包
import router from './router'
//ElementUI的导入
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(router) //路由的声明使用
Vue.use(ElementUI) //ElementUI的声明使用
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router, // 配置路由
render:h=>h(App) //配置ElementUI
})
注意:依赖的版本问题
"sass-loader": "^10.0.2",
"vue-router": "^3.1.3", 可以使用该版本
启动项目
npm run dev
在网址上输入[vue-element](http://localhost:8080/#/login)
(http://localhost:8080/#/login) 展示登录页面
路由嵌套
嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成。
案例:
1、 创建用户信息组件,在 views目录下创建一个名为Profile.vue
的视图组件;
<template>
<h1>个人信息</h1>
</template>
<script>
export default {
name: "Profile"
}
</script>
<style>
</style>
2、创建用户列表,在 views目录下创建一个名为List.vue
的视图组件;
<template>
<h1>用户列表</h1>
</template>
<script>
export default {
name: "List"
}
</script>
<style>
</style>
3、在路由中对页面进行绑定 index.js
import Vue from "vue";
import Router from 'vue-router';
import Main from '../views/Main'
import Login from '../views/Login'
import List from '../views/List'
import Profile from '../views/Profile'
Vue.use(Router);
export default new Router({
routes:[
{
path: '/main',
component:Main,
//嵌套路由
children:[
{path:'/user/profile',component:Profile},
{path:'/user/list',component:List}
]
},
{
path: '/login',
component:Login
}
]
})
4、在Views/Main.vue 中修改
<template>
<el-row class="tac">
<el-col :span="12">
<h5>首页</h5>
<el-menu
default-active="2"
class="el-menu-vertical-demo"
@open="handleOpen"
@close="handleClose">
<el-submenu index="1">
<template slot="title">
<i class="el-icon-location"></i>
<span>导航一</span>
</template>
<el-menu-item-group>
<template slot="title">分组一</template>
<el-menu-item index="1-1"><router-link to="/user/profile">选项1</router-link></el-menu-item> <!--路由链接-->
<el-menu-item index="1-2"><router-link to="/user/list">选项2</router-link></el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="分组2">
<el-menu-item index="1-3">选项3</el-menu-item>
</el-menu-item-group>
<el-submenu index="1-4">
<template slot="title">选项4</template>
<el-menu-item index="1-4-1">选项1</el-menu-item>
</el-submenu>
</el-submenu>
<el-menu-item index="2">
<i class="el-icon-menu"></i>
<span slot="title">导航二</span>
</el-menu-item>
<el-menu-item index="3" disabled>
<i class="el-icon-document"></i>
<span slot="title">导航三</span>
</el-menu-item>
<el-menu-item index="4">
<i class="el-icon-setting"></i>
<span slot="title">导航四</span>
</el-menu-item>
</el-menu>
</el-col>
<router-view></router-view>
</el-row>
</template>
<script>
export default {
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
}
}
}
</script>
<style scoped>
</style>
参数传递及重定向
参数传递
Main.vue
<!--name地址,params:传递参数 v-bind: 绑定数据 简写为 :-->
<el-menu-item index="1-1"><router-link :to="{name:'profile',params:{id:1}}">选项1</router-link></el-menu-item>
<!--<el-menu-item index="1-1"><router-link to="/user/profile">选项1</router-link></el-menu-item>-->
路由 index.js
//:id 接收数据,如/user/profile/:id/:name 接收id和name属性 只写地址也可以接收到
{path:'/user/profile/:id',name:'profile',component:Profile},
注意: 要写name ,不然会识别不到
接收数据
profile.vue
方法一:
<template>
<div>
<h1>个人信息</h1>
{{$route.params.id }}
</div>
</template>
<script>
export default {
name: "Profile"
}
</script>
<style>
</style>
方法二:
路由上.index.js 加入props:true
{path:'/user/profile/:id',name:'profile',component:Profile,props:true}
接收界面中 Profile.vue
<template>
<div>
<h1>个人信息</h1>
<!--{{$route.params.id }}-->
{{id}} <!--显示数据-->
</div>
</template>
<script>
export default {
props:['id'], //使用组件接收数据
name: "Profile"
}
</script>
<style>
</style>
重定向
案例:
路由 index.js 再定义一个路径 重定向到首页
export default new Router({
routes:[
{
path: '/main',
component:Main,
//嵌套路由
children:[
//:id 接收数据,如/user/profile/:id/:name 接收id和name属性
{path:'/user/profile/:id',name:'profile',component:Profile,props:true},
{path:'/user/list',component:List}
]
},
{
path: '/login',
component:Login
},{
path:'/goHome', //再定义一个路径 重定向到首页
redirect:'/main'
}
]
})
Main.vue 添加跳转事件
<el-menu-item index="1-3"><router-link to="/goHome">回到首页</router-link></el-menu-item>
404和路由钩子
路由模式有两种:
- hash:路径带 # 符号,如 http://localhost/#/login
- history:路径不带 # 符号,如 http://localhost/login
修改路由配置,代码如下:
路由index.js
export default new Router({
mode: 'history',
routes: [
]
});
404 页面
1、创建一个NotFound.vue
视图组件,处理404
<template>
<div>
<h1>404,你访问的页面不存在</h1>
</div>
</template>
<script>
export default {
name: "NotFound"
}
</script>
<style scoped>
</style>
2、修改路由配置index.js
import NotFound from '../views/NotFound'
routes: [
{
path: '*',
component: NotFound
}]
路由钩子与异步请求
beforeRouteEnter
:在进入路由前执行
beforeRouteLeave
:在离开路由前执行
在Profile.vue中写
export default {
props:['id'],
name: "UserProfile",
//过滤器
beforeRouteEnter: (to, from, next) => {
console.log("进入路由之前");
next();
},
beforeRouteLeave:(to, from, next) => {
console.log("进入路由之后");
next();
}
}
参数说明:
- to:路由将要跳转的路径信息
- from:路径跳转前的路径信息
- next:路由的控制参数
- next() 跳入下一个页面
- next(‘/path’) 改变路由的跳转方向,使其跳到另一个路由
- next(false) 返回原来的页面
- next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例
在钩子函数中使用异步请求
1、安装 Axios 或官网:vue-axios|axios中文网 | axios (axios-js.com)
cnpm install --save vue-axios
2、main.js
引用 Axios
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
3、准备数据:只有我们的 static 目录下的文件是可以被访问到的,所以我们就把静态文件放入该目录下。
数据和之前用的json数据一样 需要的去上述axios例子里
静态数据存放的位置
static/mock/data.json
{
"name": "狂神说Java",
"url": "https://blog.kuangstudy.com",
"page": 1,
"isNonProfit": true,
"address": {
"street": "含光门",
"city": "陕西西安",
"country": "中国"
},
"links": [
{
"name": "bilibili",
"url": "https://space.bilibili.com/95256449"
},
{
"name": "狂神说Java",
"url": "https://blog.kuangstudy.com"
},
{
"name": "百度",
"url": "https://www.baidu.com/"
}
]
}
4.在 beforeRouteEnter 中进行异步请求 Profile.vue
export default {
props:['id'],
name: "UserProfile",
//过滤器
beforeRouteEnter: (to, from, next) => {
console.log("进入路由之前");
next(vm => {
vm.getData();//进入路由之前执行getData方法
});
},
beforeRouteLeave:(to, from, next) => {
console.log("进入路由之后");
next();
},
methods:{
getData: function () {
this.axios({
method:'get',
url:"http://localhost:8080/static/mock/data.json"
}).then(function (response) {
console.log(response);
})
}
}
}