Vue
一、前端问题
- 学了HTML、CSS、JavaScript、jQuery、Bootstrap,发现并不能帮我们快速的构建成形的页面,而且操作DOM也比较麻烦
- 解决方案
-
- AngularJS【已被淘汰】
-
- Vue
-
- React
二、Vue介绍
1. 概述
- 官网:https://cn.vuejs.org/
- 渐进式
JavaScript
框架【想要用什么,就学什么】 - Vue是基于后台的MVC思想实现的。【MVVM】
2. MVVM
- M:Model:模型层【数据】,在这里表示 JavaScript 对象
- V:View:视图层,在这里表示 DOM(HTML 操作的元素)
- VM:ViewModel:连接视图和数据的中间件,Vue.js 就是 MVVM 中的 ViewModel 层的实现者
- More ActionsMVVM的原理图【双向数据绑定】
三、快速入门
1. 参考官网
https://cn.vuejs.org/v2/guide/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01-vue-quick.html</title>
<!-- 第一步:引入vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 第三步:使用vue语法或内容 -->
<div id="app">
<!-- 插值表达式 -->
{{ message }}
</div>
</body>
<!-- 第二步:创建vue对象 -->
<script>
//new Vue({}}) 创建一个vue对象
new Vue({
el: '#app', //el : element,通过选择器绑定html元素
data: { //data : 数据,可以定义普通变量,json对象等。这些数据可以通过vue的语法获取到
message: 'Hello Vue!'
}
})
</script>
</html>
2. 插值表达式
插值表达式是作为纯文本存在的,且需要放在被Vue绑定的HTML元素内部
2.1 语法
{{ vue的变量 }}
2.2 取值
- 变量
{{变量}}
- 对象
{{对象.属性}} 或者 {{对象.方法}}
- 数组
{{数组名[下标]}}
{{数组名[下标].属性}}
2.3 实例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02-vue-插值表达式.html</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- vue中的内容必须先定义,再使用 -->
<!-- 取普通变量的值 -->
{{ name }}
<br/>
<!-- 取对象的值 -->
{{product.name}} - {{product.price}} - {{product.marketTime}}
<br/>
<!-- 取数组中的元素 -->
{{employees[1].id}} - {{employees[1].empName}}
<br/>
<br/>
<br/>
<br/>
</div>
</body>
<script>
new Vue({
el: '#app',
data: {
name: '张三',
product : {
name : "电冰箱",
price : 5000,
marketTime : '2022-01-02'
},
employees : [
{id:1001, empName:"jack", deptId:1},
{id:1005, empName:"汉克", deptId:3}
]
}
})
</script>
</html>
四、vue指令
1. v-on
用来绑定事件的
- js的事件都是以on开头的,那么vue的事件就是js的事件把前面的on变成@
- οnclick=“test1()” @click=“test1()”
- 事件演示、传参、事件修饰符
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03-v-on.html</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- v-on : 代表绑定事件 -->
<!--
事件
js
- onclick
- onchange
...
vue
- v-on:click
- v-on:change
...
v-on: 可以简写成 @,推荐的
-->
<div id="app">
<button onclick="changeText(this)">原始js单击事件</button>
<br/>
<br/>
<button v-on:click="changeName()">Vue的单击事件1</button>
<br/>
{{name}}
<br/>
<button @click="changeName2('AA')">Vue的单击事件2</button>
<br/>
<br/>
<!--//在获取event时,方法就不要传参,也不要写括号-->
<div @mousemove="getXy" style="width: 300px; height: 200px; background-color:#AABBCC;"></div>
<br/>
{{x}}:{{y}}
<br/>
<br/>
<!-- 在方法中传入vue变量 -->
<button @click="changeName3(name)">Vue的单击事件3</button>
<br/>
<!-- 事件修饰符 : 阻止事件冒泡 -->
<div @mousemove="test4" style="width: 300px; height: 100px; background-color:#AABBAA;">
我是一个div[test4]
<!--<div @mousemove="test5" style="width: 200px; height: 50px; background-color:yellow;">js 我是一个div[test5] 停止事件传播</div>-->
<div @mousemove.stop style="width: 100px; height: 50px; background-color:yellow;">vue 我是一个div[test5]</div>
</div>
<br/>
</div>
</body>
<script>
new Vue({
el: '#app',
data: {
name : "张三",
x : 0,
y : 0
},
methods : {
changeName : function () {
//在vue的方法中可以使用js语法
if(this.name == '张三') {
//this : Vue对象
this.name = "李四";
}
},
changeName2 : function (value) {
alert(value);
this.name = value;
},
//获取事件对象 event,为了获取它原生事件属性及方法
getXy : function (event) {
//console.log(event.clientX);
//console.log(event.clientY);
this.x = event.clientX;
this.y = event.clientY;
},
changeName3 : function (value) {
alert(value);
},
test4 : function (event) {
this.x = event.clientX;
this.y = event.clientY;
},
/*test5 : function (event) {
//console.log("test5....")
event.stopPropagation(); //阻止事件传播
},*/
}
})
function changeText(obj) {
obj.innerText = "我改变内容";
}
</script>
</html>
2. v-bind
用来绑定属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04-v-bind.html</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<a href="http://www.baidu.com">baidu</a><br/>
<br/>
<a v-bind:href="linkUrl">baidu v-bind</a><br/>
<!-- v-bind:用于绑定属性,可以简写成 :,推荐使用简写方式 -->
<br/>
<a :href="linkUrl">baidu v-bind简写</a>
</div>
</body>
<script>
new Vue({
el: '#app',
data: {
linkUrl: 'http://www.baidu.com'
}
})
</script>
</html>
3. v-text、v-html
- v-text:innerText 获取纯文本
- v-html:innerHTML :能够解析HTML标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04-v-bind.html</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<span v-html="linkUrl"></span><br/>
<br/>
<span v-text="linkUrl"></span><br/>
</div>
</body>
<script>
new Vue({
el: '#app',
data: {
linkUrl: '<a href="http://www.baidu.com">百度</a>'
}
})
</script>
</html>
4. v-model
- 用来进行双向数据绑定
- 可以使用链式编程绑定实体
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>06-v-model.html</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<label for="message">消息:</label>
<!-- v-model = name + value -->
<input type="text" id="message" v-model="message"/><br/>
<br/>
{{message}}
<br/>
<br/>
<!--<form action="#" method="post">
用户名: <input type="text" name="username" value="${user.username}"/><br/>
性别: <input type="radio" value="1" name="gender" <c:if test="${user.gender == 1 ? 'checked' : ''}"></c:if>/>男
<input type="radio" value="0" name="gender"/>女
</form>-->
<form action="#" method="post">
用户名: <input type="text" v-model="user.username" /><br/>
性别: <input type="radio" value="1" v-model="user.gender" />男
<input type="radio" value="0" v-model="user.gender" />女
<button @click="update()">更新</button>
</form>
<!--
1.当vue中的数据发生变化时,会自动在视图回显
2.当视图中数据改变时,vue中的数据会实时同步
-->
</div>
</body>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue!',
user : {
username : "李四",
gender : 0
}
},
methods : {
update : function () {
alert(JSON.stringify(this.user));
}
}
})
</script>
</html>
5. v-if、v-else-if、v-else、v-show
- v-if、v-else-if、v-else:用来分支判断
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>07-v-if-else-if-else-show.html</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p v-if="age >= 18 && age <= 60">青壮年</p>
<p v-else-if="age < 18">未成年人要多吃饭</p>
<p v-else>该退休,不甘心啊</p>
<!-- v-show : 是通过css来渲染的 -->
<p v-show="!flag">我想显示</p>
<!-- v-if : 是直接通过元素是否存在 -->
<p v-if="age < 18">我能不能显示全靠age>18</p>
<!--
如果要效率,则选择 v-show
如果要安全,则选择 v-if
-->
</div>
</body>
<script>
new Vue({
el: '#app',
data: {
age : 117,
flag : true
}
})
</script>
</html>
6. v-for
- 遍历
对象、数组【简单数组、对象数组】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04-v-bind.html</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h2>遍历对象</h2>
<!-- 遍历对象 -->
<ul>
<li v-for="(value,key,index) in user">
{{index}} : {{key}} : {{value}}
</li>
</ul>
<!--
遍历
1.当in前面有多个参数时,需要使用()包起来
2.获取的值是什么,由参数的位置决定,跟名字没关系
3.遍历对象时,参数可以有3个,分别是值,属性名,索引
-->
<ul>
<li v-for="(v,k,i) in user">
{{i}} : {{k}} : {{v}}
</li>
</ul>
<br/>
<br/>
<ul>
<li v-for="(v,i) in nums">
{{i}} : {{v}}
</li>
</ul>
<br/>
<br/>
<ul>
<li v-for="(product,i) in products">
{{i}} : {{product.name}},{{product.price}},{{product.proDate}}
</li>
</ul>
</div>
</body>
<script>
new Vue({
el: '#app',
data: {
user : {
username : "jack",
age : 12
},
nums : [10,11,52,6,2,34],
products : [
{ name:"A4纸", price:10, proDate:'2000-12-12'},
{ name:"宝宝用品", price:50, proDate:'2020-12-12'},
{ name:"餐车", price:10000, proDate:'1999-12-13'}
]
}
})
</script>
</html>
五、监听属性、计算属性
1. 监听属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>09-监听属性.html</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p style = "font-size:25px;">计数器: {{ counter }}</p>
<button @click="counter++" style = "font-size:25px;">点我</button>
</div>
</body>
<script>
new Vue({
el: '#app',
data: {
counter : 0
},
//监听属性
watch : {
counter : function (newValue, oldValue) {
console.log("counter由" + oldValue + "变成了" + newValue);
}
}
})
</script>
</html>
2. 计算属性
- 不是一个普通的属性,而是一个方法,只不过在使用这个方法时只能把它当作一个变量来使用。
- 一旦是计算属性,那么它的值在不重新加载Vue对象时,会被浏览器缓存下来一直使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04-v-bind.html</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p style = "font-size:25px;">
time1: {{time1()}}
</p>
<p style = "font-size:25px;">
time2: {{time2}}
</p>
<button @click="addTime1()">add time1</button>
<button @click="addTime2()">add time2</button>
<br/>
<br/>
t1:{{t1}}
<br/>
t2:{{t2}}
</div>
</body>
<script>
new Vue({
el: '#app',
data: {
t1 : 0,
t2 : 0
},
methods : {
time1 : function () {
return Date.now();
},
addTime1 : function () {
console.log(this.time1());
this.t1 = this.time1() + 1;
},
addTime2 : function () {
console.log(this.time2);
this.t2 = this.time2 + 1;
}
},
//计算属性
computed : {
time2 : function () {
return Date.now();
}
}
})
</script>
</html>
六、ECMAScript6.0新语法
1. 局部变量定义
#es5
var a = 1; //全局变量
#es6
let a = 1; //局部变量
2. 函数声明
#es5
fun1 : function(参数列表){
//函数体
}
#es6
fun1(参数列表){
//函数体
}
3. 模板字符串
#es5
fun1 : function(id){
var url = "http://localhost/employee/findById?id=" + id;
}
#es6
fun1 : function(id){
var url = `http://localhost/employee/findById?id=${id}`;
}
4. 箭头函数
#es5
new Vue({
data : {
user : {}
},
methods: {
findById : function(id){
var _this = this;
var url = "http://localhost/employee/findById?id=" + id;
$.get(url, data, function(result){
console.log(result);
//this是谁? ajax
_this.user = result.data;
}, "json")
}
}
});
#es5
new Vue({
data : {
user : {}
},
methods: {
findById(id){
let url = `http://localhost/employee/findById?id=${id}`;
$.get(url, data, (result) => {
console.log(result);
//this是谁? vue
this.user = result.data;
}, "json")
}
}
});
5. 改造计算属性实例
七、组件化
-
在vue看来,万事万物皆组件。组件可以被复用
-
组件要使用,就必须先注册。
-
组件分为两类
- 局部组件【只能在当前vue中使用】
- 全局组件【可以在多个vue中使用】
1. 局部组件
只能在自己的Vue对象绑定的区域中使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>12-局部组件.html</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 使用组件 -->
<mytitle></mytitle>
<br/>
<br/>
<mytitle></mytitle>
<br/>
<br/>
<mytitle></mytitle>
</div>
<div id="app2">
<mytitle></mytitle> <!-- 这里不能用,要报错 -->
</div>
</body>
<script>
new Vue({
el: '#app',
data: {
},
components : {
//组件名 : 组件体【vue对象】
"mytitle" : {
//组件化后,data写法变了
data(){
return {
msg : "局部组件的消息"
}
},
methods: {
changeMessage() {
this.msg = "改改改";
}
},
//就是当前组件要渲染的dom
//template必须有且只有一个根标签
template : "<div><button @click='changeMessage()'>改变Message的值</button>{{msg}}</div>"
}
}
});
new Vue({
el : "#app2"
});
</script>
</html>
2. 全局组件
在不同的Vue组件中也可以使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>12-局部组件.html</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h1>App</h1>
<!-- 使用组件 -->
<mytitle></mytitle>
<br/>
<br/>
</div>
<hr/>
<div id="app2">
<h1>App2</h1>
<mytitle></mytitle>
</div>
</body>
<script>
Vue.component(
//组件名 : 组件体【vue对象】
"mytitle", {
//组件化后,data写法变了
data(){
return {
msg : "局部组件的消息"
}
},
methods: {
changeMessage() {
this.msg = "改改改";
}
},
//就是当前组件要渲染的dom
//template必须有且只有一个根标签
template : "<div><button @click='changeMessage()'>改变Message的值</button>{{msg}}</div>"
}
);
new Vue({
el: '#app'
});
new Vue({
el : "#app2"
});
</script>
</html>
八、生命周期
<html>
<head>
<meta charset="UTF-8">
<title>生命周期</title>
</head>
<body>
<div id="app1">
{{title}}
<button type="button" @click="changeTitle">change title</button>
<button type="button" @click="destroy">destroy</button>
</div>
</body>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script>
new Vue({
el:"#app1",
data:{
title:"this is title",
count : 0
},
methods:{
changeTitle:function(){
this.title= "new title " + this.count++;
},
destroy:function(){
//销毁vue实例
this.$destroy();
}
},
beforeCreate(){
console.log("beforeCreate")
},
created(){
console.log("created")
},
beforeMount(){
console.log("beforeMount")
},
mounted(){
console.log("mounted")
},
beforeUpdate(){
console.log("beforeUpdate")
},
updated(){
console.log("updated")
},
beforeDestroy(){
console.log("beforeDestory")
},
destroyed(){
console.log("destory")
}
})
</script>
</html>
九、前后端分离开发
前台 | 后台 |
---|---|
swagger | swagger |
Node.js【前台的一个tomcat】 | Tomcat |
mock假数据 | mysql |
postman | postman |
十、使用vue脚手架来开发vue项目
1. 安装node.js
-
简单理解:就是前台的一个tomcat
-
安装:闭着眼睛下一步【建议不要修改安装路径】
-
安装包:
node-v14.17.1-x64.msi
-
cmd:
node -v
-
2. 安装vue脚手架
- vue-cli
- 安装
- cmd:
npm install vue-cli -g
- cmd:
- 安装cnpm
- 安装
#打开cmd,输入命令
npm install -g cnpm --registry=https://registry.npm.taobao.org
#安装Vue需要npm的版本大于3,所以我们先升级一下npm,输入命令
cnpm install cnpm -g
#安装vue,输入命令
cnpm install vue
#安装vue-cli,输入命令
cnpm install --global vue-cli
3. 使用vue-cli创建vue项目
-
查看vue-cli提供的模板
-
创建一个项目
-
启动项目
在这里插入代码片#进入到项目目录
cd vue-demo01
#先安装
cnpm install
#启动项目
cnpm run dev
- More Actionshttp://localhost:8080
十一、vue项目
1. 目录结构及执行流程
-
项目的目录结构物
-
执行流程
2. 简单案例
项目结构
- App.vue
<template>
<div id="app">
<MyHeader></MyHeader>
<MyBody></MyBody>
<MyFooter></MyFooter>
</div>
</template>
<script>
import MyHeader from './components/MyHeader'
import MyBody from './components/MyBody'
import MyFooter from './components/MyFooter'
export default {
name: 'App',
components: {
//HelloWorld
MyHeader,
MyBody,
MyFooter
}
}
</script>
<style>
</style>
- MyHeader.vue
<template>
<div>
{{className}}
</div>
</template>
<script>
export default {
name: 'MyHeader',
data () {
return {
className: 'Java2107'
}
}
}
</script>
<style scoped>
div{
margin-left: 200px;
text-align: center;
width: 300px;
height: 100px;
background-color: red;
}
</style>
- MyBody.vue
<template>
<div>
{{message}}
</div>
</template>
<script>
export default {
name: 'MyBody',
data () {
return {
message: '每天好快乐!!'
}
}
}
</script>
<style scoped>
div{
margin-left: 200px;
text-align: center;
width: 300px;
height: 400px;
background-color: yellow;
}
</style>
- MyFooter
<template>
<div>
{{roleName}}:{{name}}
</div>
</template>
<script>
export default {
name: 'MyFooter',
data () {
return {
roleName: '班主任',
name: '小婷'
}
}
}
</script>
<style scoped>
div{
margin-left: 200px;
text-align: center;
width: 300px;
height: 50px;
background-color: blue;
}
</style>
效果:(红色:MyHeader;黄色:MyBody;蓝色:MyBody)
3. 组件传参
父组件:App
子组件:MyHeader、MyBody、MyFooter…
3.1 父传子
把App的变量传给MyBody
- 子组件【使用props属性来指定其他组件传递过来的参数】
<template>
<div>
{{message}}
<br/><br/>
这是父组件传递来的参数
<br/>
参数一:{{counter}}
<br/>
参数二:{{myproduct.id}},{{myproduct.proName}},{{myproduct.price}}
</div>
</template>
<script>
export default {
name : 'MyBody',
data () {
return {
message: '每天好快乐!!'
}
},
props : {
counter : {
type : Number,
required : false,
default : 0
},
myproduct: Object
}
}
</script>
<style scoped>
div{
margin-left: 200px;
text-align: center;
width: 300px;
height: 400px;
background-color: yellow;
}
</style>
- 父组件【使用v-bind:来绑定传递到子组件的变量名】
<template>
<div id="app">
<MyHeader></MyHeader>
<MyBody v-bind:counter="num" :myproduct="product"></MyBody>
<MyFooter></MyFooter>
</div>
</template>
<script>
import MyHeader from './components/MyHeader'
import MyBody from './components/MyBody'
import MyFooter from './components/MyFooter'
import MyAxiosTest from "./components/MyAxiosTest";
export default {
name: 'App',
components: {
MyHeader,
MyBody,
MyFooter
},
data(){
return{
num: 1000,
product: {
id: 1001,
proName: "小天鹅洗衣机",
price: 6599
}
}
}
}
</script>
<style>
</style>
3.2子传父
- 子组件向父组件发送数据
<template>
<div>
{{roleName}}:{{name}}
<br/><br/>
<button @click="sendData(name)">向父组件发送普通变量</button>
<button @click="sendObjectData(product)">向父组件发送对象数据</button>
</div>
</template>
<script>
export default {
name: 'MyFooter',
data () {
return {
roleName: '班主任',
name: '小婷',
product:{
id:111,
proName:"子组件传递来的数据",
price:1100
}
}
},
methods: {
sendData(value){
// 发送给父组件
this.$emit("funSendData",value);
},
sendObjectData(value){
// 发送给父组件
this.$emit("funSendObjectData",value);
}
}
}
</script>
<style scoped>
div{
margin-left: 200px;
text-align: center;
width: 300px;
height: 100px;
background-color: blue;
}
</style>
- 父组件监听子组件发送的名称
<template>
<div id="app">
<MyHeader></MyHeader>
<MyBody v-bind:counter="num" :myproduct="product"></MyBody>
<MyFooter @funSendData="testSendData" @funSendObjectData="testSendObjectData"></MyFooter>
<MyAxiosTest></MyAxiosTest>
</div>
</template>
<script>
import MyHeader from './components/MyHeader'
import MyBody from './components/MyBody'
import MyFooter from './components/MyFooter'
import MyAxiosTest from "./components/MyAxiosTest";
export default {
name: 'App',
components: {
MyAxiosTest,
//HelloWorld
MyHeader,
MyBody,
MyFooter
},
data(){
return{
num: 1000,
product: {
id: 1001,
proName: "小天鹅洗衣机",
price: 6599
}
}
},
methods: {
testSendData(value) {
console.log(value)
},
testSendObjectData(pro){
this.product = pro;
}
}
}
</script>
<style>
</style>