前端框架(Vue.js)
一、基本介绍
1.vue是什么
- Vue(读音/vju:/,类似于view)是一个前端框架,易于构建用户界面
- Vue的核心库只关注视图层,不仅易于上手,还便于与第三库或项目整合
- 支持和其他类库结合使用
- 开发复杂的单页应用非常方便
- Vue是Vue.js的简称
- 官网:https://cn.vuejs.org/
- git地址:https://github.com/vuejs/vue
2.MVVM{M(model)-V(view)-VM(ViewModel)}
2.1原理图
2.2MVVM解读
- M:即Model(模型),包括数据和一些基本操作
- V:即View,视图,页面渲染结果
- VM:即View-Model,模型与视图间的双向操作(无需开发人员干涉)
- 在MVVM之前,开发人员从后端获取需要的数据模型,然后要通过DOM操作Model渲染到View中。而后当用户操作视图,我们还需要通过DOM获取View中的数据,然后同步到Model中
- 而MVVM中的VM要做的事情就是把DOM操作完全封装起来,开发人员不用再关心Model和View之间是如何互相影响的
- 只要我们Model发生了改变,View上自然就会表现出来
3.快速入门
3.1代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue快速入门</title>
</head>
<body>
<script type="text/javascript" src="vue/vue.js"></script>
<!--
1.div元素不是必须得,也可以是其他元素,比如span,但是约定都是将vue实例挂载到div
因为div更适合做布局
2.id 不是必须为app,是程序员自己决定的,但是一般就是使用app
-->
<div id="app">
<!--
1.{{message}}:插值表达式
2.message 就是从Model的data数据池来获取或设置
3.当我们的代码执行时,会到data{} 数据池中区匹配数据,如果匹配上,
就进行替换,如果没有匹配上,就会输出空
4.这个插值表达式只能在标签中使用,不能在属性中使用
-->
<h1>你好-{{name}}-{{message}}</h1>
</div>
<script type="text/javascript">
/*
1.并不是只可以有一个Vue对象,而是可以有多个Vue对象,
但是如果不是特殊情况一个Vue对象就够了
2.注意一定要写在被挂载的元素之后,否则会挂载失败
*/
let vm = new Vue({
el:"#app",//创建的vue实例挂载到id=app的div(也可以理解为挂载到id=app的标签),名字一定要和要挂载的标签名的id一样
data:{//data{} 表示数据池(model有了数据),可以有很多数据,以k-v形式设置(根据业务需要来设置),名称由程序员制定,不是固定的
name:"学静思语",
message:"欢迎"
}
});
console.log(vm)
</script>
</body>
</html>
3.2注意事项和使用细节
- 注意代码顺序,要求被挂载的元素要放在最前面,否则无法绑定数据,也就是会挂载失败
- Vue.js采用简洁的模板语法,来声明的将数据渲染进DOM的系统,做到数据和显示分离
- Vue没有繁琐的DOM操作,如果使用JQuery,我们需要先找到div节点,获取到DOM对象,然后进行节点操作,显然Vue更加简洁
二、Vue简单的操作
1.数据单向渲染
1.1 基本说明
- v-bind: 指令可以基本完成基本数据渲染/绑定
- v-bind: 简写形式就是一个冒号(:)
- 其是由Vue解析的
1.2 注意事项和使用细节
- 插值表达式是用在标签体的
- 如果给标签属性绑定值,则使用 v-bind: 指令
1.3 代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>单向渲染</title>
</head>
<body>
<script type="text/javascript" src="vue/vue.js"></script>
<div id="app">
<!--
1.使用插值表达式引用data数据池数据是在标签体内
2.如果是在 标签/元素 的属性上去引用data数据池数据时,不能使用插值表达式,需要使用 v-bind:
3.v-bind: 是由Vue来解析
4.v-bind: 可以简写,简写就是一个(:)
-->
<h1>{{message}}</h1>
<img v-bind:src="img_src" v-bind:width="width">
<img :src="img_src" :width="width">
</div>
<script type="text/javascript">
/*
1.并不是只可以有一个Vue对象,而是可以有多个Vue对象,
但是如果不是特殊情况一个Vue对象就够了
2.注意一定要写在被挂载的元素之后,否则会挂载失败
*/
let vm = new Vue({
el:"#app",//创建的vue实例挂载到id=app的div(也可以理解为挂载到id=app的标签),名字一定要和要挂载的标签名的id一样
data:{//data{} 表示数据池(model有了数据),可以有很多数据,以k-v形式设置(根据业务需要来设置),名称由程序员制定,不是固定的
message:"hello!老鼠精",
img_src:"img/1.jpg",
width:"150px"
}
});
console.log(vm)
</script>
</body>
</html>
2.数据双向渲染
2.1基本说明
- v-bind: 是数据单向渲染:data数据池绑定的数据变化,会影响View,View的变化是不会影响data数据池的数据变化
- v-model: 是数据的双向渲染
- data数据池的数据变化会影响View的变化【底层的机制是Data Bindings】
- View的变化会影响data数据池的数据变化【底层机制是 DOM Listeners】
- v-model:value=““,可以进行数据双向渲染,v-model也可以进行数据双向渲染
2.2代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>数据双向渲染</title>
</head>
<body>
<script type="text/javascript" src="vue/vue.js"></script>
<div id="app">
<!--
1.v-bind: 是数据单向渲染:data数据池绑定的数据变化,会影响View,View的变化是不会影响data数据池的数据变化
2.v-model: 是数据的双向渲染,data数据池的数据变化会影响View的变化,View的变化会影响data数据池的数据变化
3.v-model:value="",可以进行数据双向渲染,v-model也可以进行数据双向渲染
-->
<h1>{{message}}</h1>
<input type="text" v-model="hobby.val"><br>
<input type="text" v-bind:value="hobby.val">
<h2>你的爱好是: {{hobby.val}}</h2>
</div>
<script type="text/javascript">
/*
1.并不是只可以有一个Vue对象,而是可以有多个Vue对象,
但是如果不是特殊情况一个Vue对象就够了
2.注意一定要写在被挂载的元素之后,否则会挂载失败
*/
let vm = new Vue({
el:"#app",//创建的vue实例挂载到id=app的div(也可以理解为挂载到id=app的标签),名字一定要和要挂载的标签名的id一样
data:{//data{} 表示数据池(model有了数据),可以有很多数据,以k-v形式设置(根据业务需要来设置),名称由程序员制定,不是固定的
message:"hello!请输入你的爱好",
// 这里这样做是为了以后的拓展
hobby:{
val:"购物"
}
}
});
console.log(vm)
</script>
</body>
</html>
3.事件绑定
3.1基本说明
- 使用 v-on 进行事件处理,比如: v-on:click 表示处理鼠标点击事件
- 事件调用的方法定义在 vue 对象声明的 methods 节点中
- v-on: 事件名 可以绑定指定事件
3.2注意事项和使用细节
- 如果方法没有参数,可以直接省略()【需要浏览器支持】
- v-on 指令的简写形式 @ 【需要浏览器支持】
- 如果要知道可以绑定哪些事件,可以在浏览器控制台中查看$el–>childNodes可以绑定哪些事件
3.3 代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件绑定</title>
</head>
<body>
<script type="text/javascript" src="vue/vue.js"></script>
<div id="app">
<h1>{{message}}</h1>
<!--
1.v-on:click 表示我们要给button元素绑定一个click的事件
2.sayHi() 表示绑定的方法,在方法池 methods{} 定义的
3.底层仍是DOM编程
-->
<button v-on:click="sayHi()">点击这里输出</button>
<button v-on:click="sayOk()">点击这里输出</button>
<button v-on:click="sayHi">点击这里输出</button>
<button @click="sayOk">点击这里输出</button>
</div>
<script type="text/javascript">
let vm = new Vue({
el:"#app",
data:{
message:"Vue事件绑定",
},
// 1. methods 对应的值是一个对象
// 2. 在{} 中,可以写很多的方法,可以理解为一个方法池
methods:{
sayHi(){
console.log("hi,金角大王")
},
sayOk(){
console.log("ok,银角大王")
}
}
});
</script>
</body>
</html>
4.修饰符
4.1修饰符基本介绍
- 修饰符(Modifiers)是以(.)指明的后缀,指出某个指令以特殊方式绑定
- 是为特殊情况做出的一种行为,来完成特定的业务逻辑
- 学习网址:https://v2.cn.vuejs.org/v2/guide/events.html
4.2代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>修饰符</title>
</head>
<body>
<!--导入Vue -->
<script type="text/javascript" src="vue/vue.js"></script>
<!--创建容器-->
<div id="app">
<!--创建一个from表单-->
<!--
1.修饰符用于指出一个指令应该以特殊方式绑定
2.v-on:submit.prevent中的.prevent 修饰符表示阻止表单提交的默认行为,然后执行指定的方法
-->
<form action="http://baidu.com" v-on:submit.prevent="submit">
<input type="text" v-model="monster.name"><br>
<input type="submit" value="注册">
</form>
<!--扩展部分-->
<h1>修饰符扩展部分</h1>
<!--被绑定的按钮只能被单击一次,如果刷新界面的话还是可以再单击的,如果想实现只单击需要前后端一起实现-->
<button v-on:click.once="click">点击一次</button>
<!--监听enter,特殊绑定-->
<input type="text" v-on:keyup.enter="onsubmit">
<input type="text" v-on:keyup.down="onsubmit">
<!--.trim就是把你输入框左右边的空格去除-->
<input type="text" v-model.trim="monster.name">
</div>
<!--创建Vue对象-->
<script type="text/javascript">
//定义Vue对象
let vm = new Vue({
el:"#app",
data:{
monster:{
// 这里可以不定义属性,可以动态生成
}
},
methods:{
submit(){
console.log("请输入名称",this.monster.name)
},
click(){
console.log("被单击了")
},
onsubmit(){
console.log("单击了enter键")
}
}
});
</script>
</body>
</html>
5.条件渲染/控制:v-if/v-show
5.1 基本说明
- v-if和v-show条件指令完成条件渲染/控制
- v-if介绍
- v-if 指令用于条件性的渲染一块内容,这块内容只会在指令的表达式返回true值的时候被渲染
- 还有v-else和v-else-if指令,和java中的if-else-if差不多
- v-show介绍
- v-show 用于根据条件展示元素,用法大致与v-if一样
5.2 代码
v-if代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>修饰符</title> </head> <body> <!--导入Vue --> <script type="text/javascript" src="vue/vue.js"></script> <!--创建容器--> <div id="app"> <input type="checkbox" v-model="check">是否同一条款【v-if实现】 <!-- 1.这里v-if指令是从data数据池中取数据 2.v-if/v-else 会根据 返回值来决定是否动态创建对应的子组件 --> <h1 v-if="check">你同意了条款</h1> <h1 v-else>你不同意条款</h1> </div> <!--创建Vue对象--> <script type="text/javascript"> //定义Vue对象 let vm = new Vue({ el:"#app", data:{ check:false } }); </script> </body> </html>
v-show代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>修饰符</title> </head> <body> <!--导入Vue --> <script type="text/javascript" src="vue/vue.js"></script> <!--创建容器--> <div id="app"> <input type="checkbox" v-model="check">是否同一条款【v-show实现】 <!-- 1.这里v-show指令是从data数据池中取数据 --> <h1 v-show="check">你同意了条款</h1> <h1 v-show="!check">你不同意条款</h1> </div> <!--创建Vue对象--> <script type="text/javascript"> //定义Vue对象 let vm = new Vue({ el:"#app", data:{ check:false } }); </script> </body> </html>
5.3 v-if和v-show的比对
- v-if会确保在切换过程中,条件块内的事件监听和子组件销毁和重建
- v-show机制相对简单,不管初始条件是什么,元素总是会被渲染,并且只是对CSS进行切换
- 建议:如果要频繁的切换,建议使用v-show;如果运行时条件很少改变,使用v-if较好
6.列表渲染:v-for
6.1基本介绍
6.2代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-for遍历数据</title>
</head>
<body>
<script type="text/javascript" src="vue/vue.js"></script>
<div id="app">
<h1>{{messages.test1}}</h1>
<ul>
<li v-for="num in nums">
{{num}}
</li>
</ul>
<h1>{{messages.test2}}</h1>
<ul>
<li v-for="(num,index) in nums">{{index}}-{{num}}</li>
</ul>
<h1>{{messages.test3}}</h1>
<table border="2" width="400px">
<tr v-for="(monster,index) in monsters">
<td>{{index + 1}}</td>
<td>{{monster.name}}</td>
<td>{{monster.age}}</td>
</tr>
</table>
</div>
<script type="text/javascript">
let vm = new Vue({
el:"#app",
data:{
messages:{
test1:"简单列表渲染",
test2:"简单列表渲染-带下标",
test3:"遍历数据列表"
},
nums:[1,2,3],
monsters:[{name:"牛魔王",age:100},{name:"孙悟空",age:100},{name:"哪吒",age:50}]
}
});
</script>
</body>
</html>
7.组件化编程
7.1 基本介绍
- 组件(Component)是Vue.js最强大的功能之一
- 组件也是一个Vue实例,也包括:data、methods、生命周期函数等
- 组件渲染需要Html模板,所以增加了template属性,值就是HTML模板
- 对于全局组件,任何Vue实例都可以直接在HTML中通过组件名称来使用组件
- data是一个函数,不再是一个对象,这样每次引用组件都是独立的对象
7.2注意事项和使用细节
- 如果方法体,只有简单的语句,比如count++,那么可以简写成v-on:click=“count++”
- 组件定义需要放置在new Vue()前面,否则组件注册会失败
7.3代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件化编程-传统方式</title>
</head>
<body>
<!--引入Vue-->
<script type="text/javascript" src="vue/vue.js"></script>
<!--创建容器-->
<!--
1.这种编程方式添加可很多属性,造成了业务数据的重复,没有体现复用性
2.这种方式需要大量的方法,所以引入Vue的模块编程,也是Vue最强大的功能之一
-->
<div id="app">
<button v-on:click="add">点击次数{{count}}次【非模块化编程】 </button><br>
<button v-on:click="count2++">点击次数{{count2}}次【非模块化编程】 </button><br>
<button v-on:click="count3++">点击次数{{count3}}次【非模块化编程】 </button><br>
<counter></counter>
</div>
<!--创建Vue对象-->
<script type="text/javascript">
let vm = new Vue({
//进行挂载
el:"#app",
data:{
count:10,
count2:10,
count3:10
},
methods:{
add(){
this.count++;
},
}
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模块化编程-全局组件</title>
</head>
<body>
<!-- 引入vue-->
<script type="text/javascript" src="vue/vue.js"></script>
<!--创建容器-->
<div id="app">
<counter></counter><br>
<counter></counter><br>
<counter></counter><br>
</div>
<!--创建Vue实例-->
<script type="text/javascript">
// 创建全局组件
//1.创建全局模块为counter的全局模块
//2.{} 表示就是我们的组件相关的内容
//3.temple 指定该组件的界面,也可以理解为HTML界面,因为会引用到数据池的数据,所以需要模板字符串
//4.要把Vue组件视为一个Vue实例,也有自己的数据池和methods
//5.对于组件,我们的数据池的数据,是使用函数/方法返回【目的是为了保证每个组件的数据是独立的】,因而不能使用原来的方式
//6.这时就达到目的了,界面通过template实现共享,业务处理也复用了,但是记住这个不能再另一个界面使用
Vue.component("counter",{
template:`<button v-on:click="add">点击次数{{count}}次-非模块化编程</button>`,
data(){//这里和原来的方式不同,为了保证每次的数据都是独立的,所以把这个data数据池改成了一个方法
return {
count:10
}
},
methods:{
add(){
this.count++ ;
}
}
});
new Vue({
el:"#app"
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模块化编程-局部组件</title>
</head>
<body>
<!-- 引入vue-->
<script type="text/javascript" src="vue/vue.js"></script>
<!--创建容器-->
<div id="app">
<counter></counter><br>
<counter></counter><br>
<counter></counter><br>
</div>
<!--创建Vue实例-->
<script type="text/javascript">
// 创建局部组件
//1.创建局部组件为counter的局部组件
//2.该组件只能在引入的Vue中挂载的容器中使用,如果出了组件注册的容器,则不能使用
//3.
const counter = {
template:`<button v-on:click="add">点击次数{{count}}次-非模块化编程</button>`,
data(){//这里和原来的方式不同,为了保证每次的数据都是独立的,所以把这个data数据池改成了一个方法
return {
count:10
}
},
methods:{
add(){
this.count++ ;
}
}
};
let vm = new Vue({
el:"#app",
// 要进引入某个组件
// 这个时候"counter"就是一个组件,是一个局部组件,它的使用范围只在当前的Vue可以使用
components:{
'counter':counter
}
});
</script>
</body>
</html>
三、vue的生命周期
1.vue的基本介绍
- vue实例有一个完整的生命周期,也就是说从开始创建、初始化数据、编译模板、挂载DOM、渲染-更新、卸载等一系列过程,称为Vue实例的生命周期
- 钩子函数(监听函数):Vue实例在完整的生命周期过程中(比如设置数据监听、编译模板、将实例挂载到DOM、在数据变化时更新DOM等),也会运行叫做生命周期钩子函数
- 钩子函数的作用就是在某个阶段,给程序员一个做某些处理的机会
2.生命周期图
2.1图片解读
- new Vue()
- new 了一个Vue的实例对象,此时就会进入组件的创建过程
- Init Events & Lifecycle
- 初始化组件的事件和生命周期函数
- beforeCreate
- 组件创建之后遇到的第一个生命周期函数,这个阶段data和methods以及DOM结构都未被初始化,也就是获取不到data的值,不能调用methods中的函数
- Init injections & reactivity
- 这个阶段中,正在初始化data和methods中的方法
- created
- 这个阶段组件的data和methods中的方法已初始化结束,可以访问,但是DOM结构为初始化,页面未被渲染
- 在这个阶段经常会发起Ajax请求,因为这个时候页面未被渲染,获取的数据可以及时的进行更新,然后渲染,保证页面所显示的是最新的数据
- 编译模板结构(在内存中进行)
- beforeMount
- 当模板在内存中编译完成,此时内存中的模板结构还未渲染至页面上,看不到真实的数据
- Create vm.$el and replace 'el' with it
- 这一步,正在把内存中渲染好的模板结构替换至真实的DOM结构也就是页面上
- mounted
- 此时,页面渲染好,用户看到的是真实的页面数据,生命周期创建阶段完毕,进入到了运行中的阶段
- 生命周期运行中
- beforeUpdate
- 当执行此函数,数据池的数据是新的,但是页面是之前的数据
- Virtual DOM re-render and patch
- 根据最新的data数据,重新渲染内存中的模板结构,并把渲染好的模板结构,替换至页面上
- updated
- 页面已经完成了更新,此时,data数据和页面的数据都是最新的
- beforeDestroy
- 当执行此函数时,组件即将被销毁,但还是没有真正开始销毁,此时组件的data、methods数据或方法还可以被调用
- Teardown
- 注销组件和事件监听
- destroyed
- 组件已经完成了销毁
3.代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>生命周期演示</title>
</head>
<body>
<!--引入Vue-->
<script type="text/javascript" src="vue/vue.js"></script>
<!--创建容器-->
<div id="app">
<h2 id="num">{{num}}</h2>
<button v-on:click="add">点赞</button>
<h1>{{name}}有{{num}}次点赞</h1>
</div>
<!--创建Vue对象-->
<script type="text/javascript">
let vm = new Vue({
el:"#app",
data:{
num:0,
name:"Kristina"
},
methods:{
add(){
this.num++;
},
show(){
return this.num;
}
},
beforeCreate(){//生命周期函数-创建Vue实例前
console.log("====================beforeCreate====================");
console.log("数据模型/数据池数据是否加载/能否使用[no]",this.num," ",this.name);
// console.log("数据模型/方法池数据是否加载/能否使用[no]",this.show());
console.log("页面DOM是否加载[yes]",document.getElementById("num"));
console.log("页面DOM是否被渲染[no]",document.getElementById("num").innerText);
},
created(){//生命周期函数-创建Vue实例后
console.log("====================created====================");
console.log("数据模型/数据池数据是否加载/能否使用[yes]",this.num," ",this.name);
console.log("数据模型/方法池数据是否加载/能否使用[yes]",this.show());
console.log("页面DOM是否加载[yes]",document.getElementById("num"));
console.log("页面DOM是否被渲染[no]",document.getElementById("num").innerText);
},
beforeMount(){//生命周期函数-挂载Vue实例前
console.log("====================beforeMount====================");
console.log("数据模型/数据池数据是否加载/能否使用[yes]",this.num," ",this.name);
console.log("数据模型/方法池数据是否加载/能否使用[yes]",this.show());
console.log("页面DOM是否加载[yes]",document.getElementById("num"));
console.log("页面DOM是否被渲染[no]",document.getElementById("num").innerText);
},
mounted(){//生命周期函数-挂载Vue实例后
console.log("====================mounted====================");
console.log("数据模型/数据池数据是否加载/能否使用[yes]",this.num," ",this.name);
console.log("数据模型/方法池数据是否加载/能否使用[yes]",this.show());
console.log("页面DOM是否加载[yes]",document.getElementById("num"));
console.log("页面DOM是否被渲染[yes]",document.getElementById("num").innerText);
},
beforeUpdate(){//生命周期函数-生命周期运行时数据被修改前
console.log("====================beforeUpdate====================");
console.log("数据模型/数据池数据是否加载/能否使用[yes]",this.num," ",this.name);
console.log("数据模型/方法池数据是否加载/能否使用[yes]",this.show());
console.log("页面DOM是否加载[yes]",document.getElementById("num"));
console.log("页面DOM是否被渲染[no]",document.getElementById("num").innerText);
},
updated(){//生命周期函数-生命周期运行时数据被修改后
console.log("====================updated====================");
console.log("数据模型/数据池数据是否加载/能否使用[yes]",this.num," ",this.name);
console.log("数据模型/方法池数据是否加载/能否使用[yes]",this.show());
console.log("页面DOM是否加载[yes]",document.getElementById("num"));
console.log("页面DOM是否被渲染[yes]",document.getElementById("num").innerText);
}
});
</script>
</body>
</html>