什么叫库? 代表是jQuery
库本质是就是一些函数的集合,就是将一些函数放到一个独立的js文件中
在使用库的时候,是由开发人员说的算,也就是开发人员起到了主导作用,而jQuery是辅助完成相应的功能
什么是框架?
代表:vue
是一套完整的解决方案,项目中的用到的一些功能在框架的内部都已经提供好了,在
使用框架的时候,只要将我们自己写的代码,放到框架合适的地方,框架会在合适的时机
主动调用我们写好的代码。
框架制定了一套规则,我们开发人员,就按照这套规则写代码,也就是说:在使用
vue的时候,是由就框架说的算,就是框架起到了主导作用
库和框架的区别?
本质区别:控制翻转,也就是起到了主导作用
在使用库 的时候,由开发人员到主导作用
在时用 框架 的时候,由框架起到了主导作用
mvc设计模式
m:数据模型,操作数据,CRUD
常见处理事务:根据用户输入的用户名和密码来和数据库的用户名和密码进行匹配,来判断登录是否成功
v:视图模型,数据的渲染用户在页面中看到的页面内容
c:控制模型,是处理业务逻辑,数据模型和视图模型
常见的处理业务:
1.格式校验
2.将用户名和密码交给数据模型,由数据模型判断用户名和密码是否正确
mvc的优点:将应用程序划分为三大部分,实现了职责的分离
MVVM
mvvm=====> m / v /vm
M:数据模型
V:视图模型
VM:ViewModel视图模型
mvvm的特点: 数据的双向绑定
数据驱动视图的思想,数据是核心
v(修改视图)---->数据也会改变
M(修改数据)---->视图也会发生改变
注意点:
不推荐直接手动操作DOM!!!
学习Vue要转换的思想:数据驱动视图:不要想着怎么去操作DOM,而是想着如何去操作数据
Vue可以看做一个MVVM模式的框架,内部实现了数据的双向绑定
双向绑定的两个方向
1 视图- >数据 内容发生改变了,那么对应的数据也会自动跟着改变
2 数据- >视图 数据发生改变了,那么对应的数据也会自动跟着改变
说明:vue中不推荐直接操作DOM的,但是Vue的底层还是Dom操作,只是不需要我
们手动操作DOM,在框架的底层封装好了DOM操作
保持视图和数据的同步
MVVM的应用
MVVM适合带有视图的应用,比如前端(页面),桌面daunt的应用
这个模式最早出现在微软的 WPF技术中
vue的使用步骤
1.安装 :npm i vue
2.引入vue.js(未压缩版本)
3.使用vue
4.创建vue的实例
构造函数的内部是vue的配置项
const vm = new Vue({
//element
//作用:指定视图中的哪块内容作为Vue的视图
el:"#app",
//数据
data:{
msg:'Hello Vue'
}
});
{{}} 插值表达式:将data中的值插入到{{}}的位置
注意点:
1.构造函数的首字母大写
2.vm是一般约定使用的Vue的实例名称
3.只有el操作的范围内,才能被vue解析,超出范围无效
4.el 不能指定到body或者html中,否则会报错
5.内部的关键字属性名不能自定义,只能使用定义好的属性和方法
插值表达式
作用:将msg数据插入到当前的位置
插值表达式中,能够使用任意的js的表达式(不能出现语句)
表达式都是有值的,能作为方法参数都是表达式,
{{1}} {{"1111"}}
input 中的 v-model 是一个指令
<input type="text" v-model="name">
指令:就是Vue给HTML元素添加的一些特殊的标记,这些标记就是Vue提供的
作用:让HTML元素具备了原来没有的功能
数据的双向绑定实现
数据的双向绑定的原理:数据劫持
Vue中通过Object.defineProperty()方法实现了数据劫持的功能
通过这个方法,可以在 访问属性或给属性赋值时,添加一些额外的操作进来
Object.defineProperty()的使用
const obj = {};
let temp;
第一个参数:表示给哪个对象添加属性
第二个参数:表示要填加的属性名称
第三个参数:是一个对象,对象有两个方法,get和set
Object.defineProperty(obj,'name',{
在Object.defineProperty中,get和set名称固定
get的作用:当读取对象的属性的时候,会调用get方法
get 方法的返回值,就是当前的属性的值
get:function(){
return temp;
}
//set的作用:当设置对象的属性的时候,会调用set方法
//参数 value表示给属性的设置的值
set:function(value){
console.log(value)
temp = value;
}
})
shim指的是,可以通过代码的方式,去实现无法兼容的方法的功能
为什么vue不兼容ie8,及其以下?
Object.defineProperty是ES5中无法shim的特性
如何实现数据的双向绑定
M->V 修改数据,视图发生改变
1.1通过defineProperty定义一个数据obj.name
1.2在set方法中,直接修改对应的DOM内容即可
V->M 修改视图,数据发生改变
2.1给文本框绑定input事件
2.2在事件通过事件对象e 获取到当前的文本框的值 e.target.value
2.3因为要让数据改变,所以,直接给数据obj.name赋值
vue会遍历data配置中的所有属性,内部调用Object.defineProperty()方法,将所有的属性都转化为getter/setter的形式
并且,要添加vm实例中,所以可以直接通过vm.name来访问data:{name:'true'}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<div id="app">
<input type="text" id="txt" />
<h1 id="title"></h1>
</div>
<script>
/*
模拟实现双向数据绑定:
1 数据 -> 视图:(先实现)
1.1 通过 defineProperty 定义一个数据 obj.name
1.2 在 set 方法中,直接修改对应DOM的内容即可
2 视图 -> 数据:(再实现)
2.1 给文本框绑定input事件
2.2 在事件中通过事件对象 e 获取到当前文本框的值 e.target.value
2.3 因为要让数据改变,所以,直接给 数据obj.name 赋值
*/
//1.获取元素
let txt = document.querySelector('#txt');
let title = document.querySelector('#title');
//2.创建一个空对象和中间变量保存
let obj = {};
let temp = '';
//3.调用 Object.defineProperty 方法
Object.defineProperty(obj,'name',{
get(){
// //给h1设置值
// title.innerText = temp;
// //给input设置值
// txt.value = temp;
return temp;
},
set(value){
//给h1设置值
title.innerText = value;
//给input设置值
txt.value = value;
//使用中间变量将值保存下来
temp = value;
}
});
//4.给input注册input事件
txt.oninput=function(e){
//通过事件对象将当前input的值取出 e.target.value
//将值同步到obj.name中
//由于给obj.name赋值,就会触发set事件,那么h1的值也会同步
obj.name = e.target.value;
}
</script>
</body>
</html>
指令操作
指令的作用:实现数据的双向绑定,也就是说让文本框的值 和数据的name双向绑定到一起。只要任意一个改变,另一个都会发生改变
M->V 修改数据,视图发生改变
V->M 修改视图,数据发生改变
如果想要获取文本框的值,只要获取对应的数据即可
1.在文本框 中 添加一个指令: v-model="name"
2.name 数据就是文本框的值了
3.所以,想要获取文本框的值,直接获取name数据的值即可
问题一:
设置指令的时候,什么时候添加单花括号?
当设置类名的添加和移除操作,需要添加{}
当设置直接样式操作,需要添加{}
v-bind:class = "{completed : item.status}"
v.bind:style = "{'background-color':bgc}"
当属性只需要一个参数时,不需要添加单花括号{}
v-model = "item.status"
v-model
作用:用于实现数据的双向绑定功能
特点:
1.只能用于表单元素中
2.在不同的表单元素中功能不同
在<input type="text">中,表示的是value的值
在<input type="checkbox">中,表示的是checkbox
//html设置
<input type="text" v-model="isCheck">
<input type="checkbox" v-model="isCheck">
//js
const vm = new Vue({
el:'#app',
data:{
name:'快带你呀',
isCheck:'true'
}
});
v-text
作用:相当于innerText的功能,如果元素中有默认的内容,那么默认内容会被覆盖
v-html
作用:相当于innerHTML的功能。
应用场景:如果字符串内容中,包含了HTML字符串,此时应该使用v-html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<div id="app">
<!-- v-text 用来设置文本内容 -->
<!-- <p v-text="msg"></p>
<p>内容为: {{ msg }} !!!</p> -->
<div v-text="html">
</div>
<div v-html="txt">
</div>
</div>
<script src="./vue.js"></script>
<script>
/*
v-text:作用相当于 innerText 的功能
注意:如果 元素中有默认内容,那么,默认内容,就会被覆盖掉
v-html:作用相当于 innerHTML 的功能
如果字符串内容中,包含了 HTML字符串, 此时,应该使用 v-html
*/
const vm = new Vue({
el:'#app',
data:{
txt:'<h1>春春走啦,不开心呢</h1>',
html:"<h2>不得不说,玺哥唱歌挺好听的</h2>"
}
});
</script>
</body>
</html>
v-bind
作用:如果要给HTML的属性动态设置内容要使用v-bind命令
说明:
v-bind:href表示要给当前的元素添加href属性,v-bind属性的前缀表示要使用data中的数据,来实现动态绑定
简写的方式:
:href
//HTML设置
<a :href="url"></a>
<img :src="src" :alt="alt">
//js设置
const vm = new Vue({
el:'#app',
data:{
url: 'www.baidu.com',
src:'./imgs/1.png',
alt:'涵涵'
}
});
应用:
样式操作的两种方式:
1 class (推荐!!!)
//html设置 xm是类名 fs是类名
<div v-bind:class="{xm:isTrue,fz:isTrue}">小马哥的专属</div>
//js设置
const vm = new Vue({
el:'#app',
data:{
isTrue:true
}
});
2 style 行内样式
注意点:
1.属性名如果带有-的字符,可采用驼峰命名法,或者加上单引号
2.设置直接样式,如果有多个
3.多个属性之间用逗号隔开
4.设置直接样式必须加上单花括号{}
//HTML
<div v-bind:style="{color:isColor,'font-size': fz + 'px'}">
你是我的小星星
</div>
//JS设置
const vm = new Vue({
el:'#app',
data:{
isColor:'#f0f0f0',
fz: 50
}
});
v-for
作用:
能够遍历指定的数据(数组或对象),重复生成指令的标签
语法:
v-for = “item in arr”
item:表示数据中的每一项
arr:表示遍历的数组(对象)
获取数组中的每一项以及索引号
//html设置
<div v-for="(item,index) in list">{{index}}=========>{{item.name}}</div>
//js设置
const vm = new Vue({
el:'#app',
data:{
list:['red','green','yellow','blue']
}
});
遍历数组中的对象
//html设置
<div v-for="(item,index) in list">{{index}}=========>{{item.name}}</div>
//js设置
const vm = new Vue({
el:'#app',
data:{
list:[{name:'red'},{name:'green'},{name:'yellow'},{name:'blue'}]
}
});
v-on
作用:绑定事件
语法:
v-on:click="say"
orv-on:click="say('参数', $event)"
简写:
@click="say"
说明:绑定的事件从
methods
中获取-
事件中的this表示当前Vue实例
特点:
如何传递参数
添加小括号就表示要传递参数,此时,如果要在事件处理程序中获取到事件对象,就必须手动指定$event
@click = "fn(123)"
@click = "fn()"
如何获取事件处理参数
1.@click = "fn",这种获取事件处理函数,默认第一个参数就是事件处理函数
2.@click = "fn(123)"或者@click = "fn()"必须手动设置$event才能获取到事件处理函数,约定将事件处理函数作第一个参数
//html
@click = "fn($event,123)"
@click = "fn($event)"
//methods
fn(e){
//这里的e就是事件处理函数
console.log(e);
}
计算属性
只有计算属性的依赖项发生改变的时候,计算属性才会被重新计算,如果是不相关的数据改变,是不会引起计算属性重新计算
在加法计算器中,num1和num2是result的依赖项,当num1的值发生改变时,result会被触发
注意点
1.计算属性的在使用的时候,不要加小括号调用,否则会报错。
2.计算属性的值是由方法的返回值决定的
3.计算属性中的名称不要与data中的数据名称重名,否则会报错
使用的场景:
根据data中的现有的数据,得到一个新的数据,此时就应该使用计算属性
computed:{
result(){
//获取到的值是String类型的值
return this.num1-0 +(this.num2-0)
}
}
vue的更新特点:
data的中的数据发生改变时,页面中的所有的指令和表达式都会重新计算一次,事件处理函数除外。
产生的问题:所有的指令和表达式重新计算,会造成资源浪费?
key 属性
v-for中的key的属性
特点:只要使用v-for这个属性就要添加key属性,且key属性是唯一的
为什么要加key?
如果不加key的会出现临时状态错乱
什么叫就地复用?
在插入数据的过程中,标签没有改动,仅仅是标签的内容发生改变,就是所谓的就地复用,也就是复用了每个P标签,而在前面三个标签的后面添加了一个新的标签
同样的内容文本框中的内容也是一个临时状态,插入数据后,Vue采用了就地复用的策略
根本原因:不添加key属性采用了索引号作为key的值
解决就地复用的问题:
默认情况下不添加key实际上以每一项的索引号作为key的值,但是每项的索引值后动
态改变的,所以,插入数据,vue就地复用标签,就会发生数据错乱
但是有id作为key的属性后,以id作为唯一的标识,就地复用还会保持绑定的状态
最佳实现:
0.只要使用v-for就添加key属性
1.如果有id就会用id作为key的属性
2.如果没有id就是用能作为唯一标示的属性作为key值
3.如果不依赖于临时状态,index也可以作为key的值
//html
<ul id="app">
<li v-for="(item,index) in list" :key="item.id">
{{index}}=====>{{item.name}} <input type="text">
</li>
</ul>
//js
const vm = new Vue({
el:'#app',
data:{
list:[
{id:1,name:'常小杰'},
{id:2,name:'李大想'},
{id:3,name:'丁申阳'},
{id:4,name:'谢新旺'}
]
}
});
v-if 和 v-show
- 条件渲染
-
v-if
:根据表达式的值的真假条件,销毁或重建元素 -
v-show
:根据表达式之真假值,切换元素的 display CSS 属性
v-show
控制元素的展示和隐藏,如果值为true则显示该元素,如果为false则隐藏该元素
实现的原理:通过css中的dispaly:none实现的
v-if
控制元素的展示和隐藏,如果值为true表示显示该元素,如果值为false表示隐藏该元素
实现的原理:移除元素,也就是从HTML结构中将这个标签删除来隐藏
应用场景:
频繁操作元素的展示和隐藏,用v-show(性能高)
要么显示要么隐藏,用v-if
<p v-show="isShow">这个元素展示出来了吗???</p>
<p v-if="isShow">这个元素,在HTML结构中吗???</p>
提升性能:v-pre
- 说明:跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
<span v-pre>{{ this will not be compiled }}</span>
提升性能:v-once
- 说明:只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
<span v-once>This will never change: {{msg}}</span>
事件修饰符
.prevent
阻止默认行为,调用 event.preventDefault()-
.stop
阻止冒泡,调用 event.stopPropagation() -
.capture
添加事件侦听器时使用事件捕获
模式 -
.self
只当事件在该元素本身触发时,才会触发事件 -
.once
事件只触发一次
异步 DOM 更新
- 说明:Vue 异步执行 DOM 更新,监视所有数据改变,一次性更新 DOM
- 优势:可以去除重复数据,对于避免不必要的计算和避免重复 DOM 操作上,非常重要
-
Vue.nextTick(callback)
:在 DOM 更新后,执行某个操作(DOM 操作)vm.$nextTick(function () {})
-
$el
:表示 Vue 管理区域的根元素,是一个 DOM 对象
methods: {
fn () {
this.msg = 'change'
this.$nextTick(function () {
console.log('$nextTick中打印:', this.$el.children[0].innerText)
})
console.log('直接打印:', this.$el.children[0].innerText)
}
}
动态添加数据的注意点
- 注意:只有
data
中的数据才是响应式的,动态添加进来的数据默认为非响应式 - 可以通过以下方式实现动态添加数据的响应式
- 1
Vue.set(object, key, value)
- 适用于添加单个属性 - 2
Object.assign()
- 适用于添加多个属性
- 1
const vm = new Vue({
data: {
stu: {
name: 'jack',
age: 19
}
}
})
/* Vue.set */
Vue.set(vm.stu, 'gender', 'male')
vm.$set()
/* Object.assign */
vm.stu = Object.assign({}, vm.stu, { gender: 'female', height: 180 })
TodoMVC1.0
实现的思路:
1.首先引入vue.js,创建vue的实例对象vm
2.在实例vm的data属性中设置遍历的数组,数组的每一项都是一个对象
3.使用v-for(item in list)遍历li标签,生成多个标签
4.通过item中的status的属性值来控值当前标签的选中状态(v-model="item.status"),同时控制着选中样式的改变(是否添加completed 类)
html的操作
<li :class="{completed : item.flag}" v-for="item in list">
<div class="view">
<input class="toggle" type="checkbox" v-model="item.flag">
<label>{{item.name}}</label>
<button class="destroy"></button>
</div>
<input class="edit" value="Create a TodoMVC template">
</li>
js的操作
;(function(window) {
// Your starting point. Enjoy the ride!
// 1.首先引入vue.js,创建vue的实例对象vm
// 2.在实例vm的data属性中设置遍历的数组,数组的每一项都是一个对象
// 3.使用v-for(item in list)遍历li标签,生成多个标签
// 4.通过item中的status的属性值来控值当前标签的选中状态(v-model="item.status"),同时控制着选中样式的改变(是否添加completed 类)
const vm = new Vue({
el:'#app',
data:{
list:[{id:1,name:'羽毛球',flag:true},{id:2,name:'篮球',flag:false},{id:3,name:'排球',flag:true},{id:4,name:'乒乓球',flag:true},{id:5,name:'桌球',flag:false},]
}
});
})(window)