vue笔记(二)
4.两种数据绑定
数据驱动:当数据发生变化的时候,用户的界面发生相应的变化,开发者不需要手动去修改dom,vue框架会自动的根据数据渲染页面。这也是声明式渲染的概念。
1.响应式数据
只能由代码改变UI或者只能由UI改变代码,其核心原理是数据劫持
对响应式的理解:核心原理是数据劫持,即通过object.defineProperty,vue在初始化数据时,会传入一个data对象,内部会默认对data对象进行遍历,使用object.defineProperty将这些属性全部转换为getter/setter。vue内部会对数据进行劫持操作,进而追踪依赖,在属性被访问和修改时通知变化。vue3.0版本用的是代理对象(new Proxy())来做响应式的,我们访问数据访问的是代理对象的数据。
//vue响应式数据实现的基本原理:
var data={}
var temp=""//临时存储空间
Object.defineProperty(data,"msg",{
set(v){
temp=v//设置data对象的msg属性时,将临时存储空间存储为msg的值v
h1.innerHTML=v//将页面显示的数据更改为设置的值v
},
get(){
return temp//获取data对象的msg属性时,返回临时存储空间temp的值,即是设置的msg属性值
}
})
data.msg=100;//改变data对象的msg属性值
2.双向数据绑定
如果数据源改变,页面就相应的改变,并且页面的数据改变(用户交互),数据源的数据也改变------- 双向数据绑定
实现方式:在响应式的基础上利用input事件,监听输入框,当用户与页面交互时,获取输入的值,并将值绑定到data容器中。
vue提供的系统指令:v-model ----- 其本质上是一个语法糖
vue实现双向数据绑定的原理:
采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
//利用object.defineProperty实现双向数据绑定
<body>
<div id="app">
<input type="text" id="txt">
<p id="show"></p>
</div>
</body>
<script type="text/javascript">
var obj = {}
Object.defineProperty(obj, 'txt', {
get: function () {
return obj
},
set: function (newValue) {
document.getElementById('txt').value = newValue
document.getElementById('show').innerHTML = newValue
}
})
document.addEventListener('keyup', function (e) {
obj.txt = e.target.value
})
</script>
==========================
//利用input事件实现
<div id='app'>
<input type="text" :value="msg" @input="input1"/>
<button @click="send">发送</button>
<button @click="change1">change1</button>
</div>
<script>
new Vue({
el: '#app',
data: {
msg:"1234"
},
methods:{
send(){
console.log(this.msg)
},
change1(){
this.msg="abcd"
}
input1(e){//input事件:当input输入框的value值改变时会被触发
this.msg=e.target.value
}
}
})
</script>
==================
//vue的v-model实现方式 -----本质是语法糖
<div id='app'>
<input type="text" v-model="msg"/>
<button @click="send">发送</button>
<button @click="change1">change1</button>
</div>
<script>
new Vue({
el: '#app',
data: {
msg:"1234"
},
methods:{
send(){
console.log(this.msg)
},
change1(){
this.msg="abcd"
}
}
})
</script>
5.vue简介
vue是由阿里的尤雨溪开发的渐进式前端框架。是目前最流行的框架之一。
vue是一套构建用户界面的渐进式框架。与其他重量级框架不同的是,vue采用自底向上增量开发的设计。vue的核心库只关注视图层,容易学习,容易与其他库或者已有的项目整合。另一方面,vue完全有能力驱动采用单文件组件和vue生态系统支持的库开发的复杂单页应用。vue的目标是通过尽可能简单的API实现响应的数据绑定和组合的视图组件。
前端三大框架:
Vue.js、React.js、Angular.js
- vue.js:数据驱动和组件化开发,轻量级,分层渐进式框架;
- React.js:数据驱动和组件化开发,灵活性很高;
- Angular.js 1.0版本数据驱动 ,2.0加上了组件化开发,重量级框架;大型企业OA办公
对vue渐进式的理解:
渐进式可以理解为主张最少。
Angular是主张较多的框架,使用angular必须使用它的模块机制,必须使用它的依赖注入- 必须使用它的特殊形式定义组件。它带有较强的排它性,很难在项目的某个部分单独使用angular开发。
React,它的主张主要是函数式编程的理念,是软性的侵入。
Vue是渐进的,没有强主张。项目的某个部分可以单独使用vue实现,它不会对整个项目产生干涉,具有很好的兼容适应性。也可以使用vue全家桶进行整个项目的开发。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mc3HcbGg-1634041049565)(E:\新建文件夹\OneDrive\桌面\图片\vue.jpg)]
vue全家桶的概念:
- vue.js:vue的核心库
- vue-cli vue官方脚手架,用于搭建vue开发环境
- vueRouter:vue官方的路由管理器
- vuex:vue应用程序开发的状态管理模式
- vue-resource:网络请求
- UI框架
6.MVC和MVVM
1.MVC:
在实际应用开发场景中,开发者常用的一种设计模式是MVC(比如egg.js中的MVC设计模式):
- M(Model):数据模型层。是应用程序中用于处理应用程序数据逻辑的部分,模型对象负责在数据库中存取数据。
- V(View):视图层。是应用程序中处理数据显示的部分,视图是依据模型数据创建的。
- C(Controller):控制层。是应用程序中处理用户交互的部分,控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。
2.MVVM:
- M(Model):模型层。就是业务逻辑相关的数据对象,通常从数据库映射而来,我们可以说是与数据库对应的model。
- V(View):视图层。就是展现出来的用户界面。
- VM(ViewModel):视图模型层。就是与界面(view)对应的Model。因为,数据库结构往往是不能直接跟界面控件一一对应上的,所以,需要再定义一个数据对象专门对应view上的控件。而ViewModel的职责就是把model对象封装成可以显示和接受输入的界面数据对象。
7.条件渲染
v-if和v-show
当指令绑定的变量为true时,该标签显示,为false时,标签不显示
区别:
- v-if是将元素从dom中删除
- v-show是通过操作元素的display属性实现隐藏和显示
visibility: hidden; 不脱离文档流的
display:none 脱离文档流
v-if 删除节点
v-show display:none
底层设计的区别导致v-if和v-show的使用场景有区别
v-if具有较高的切换消耗,会导致页面回流,所以常用于不常切换的业务中
v-show具有较高的性能消耗,节点不显示在页面上,但是依然存在于dom树中,所以常用于需要频繁被切换显示的场景。
<div id="app">
<div v-if="flag">666</div>
<div v-show="flag">777</div>
</div>
<script type="text/javascript">
new Vue({
el: "#app",
data: {
flag:false
}
})
v-if和v-else的使用:
<div v-if="flag==1">111</div>
<div v-else-if="flag==2">666</div>
<div v-else>222</div>
8.循环渲染
指令:v-for
语法:
<div id='app'>
<!-- <div>{{arr[0]}}</div>
<div>{{arr[1]}}</div>
<div>{{arr[2]}}</div>
<div>{{arr[3]}}</div> -->
<div v-for="el in arr">
<h1>{{el}}</h1>
<h2>666666</h2>
</div>
<div v-for="el in arr2">
<div v-if="el.id!=124">
<h1>{{el.text}}</h1>
<h2>时间:{{el.ctime}}</h2>
</div>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
arr:["hello","vue","js","css"],
arr2:[{id:"123",text:"内容1",ctime:"2021-10-12 14:28"},
{id:"124",text:"内容2",ctime:"2021-10-11 14:28"},
{id:"125",text:"内容3",ctime:"2021-10-10 14:28"}
]
}
})
</script>
//v-for会将绑定该指令的标签的子元素都克隆相应的次数
v-if和v-for同时使用会导致的问题:
在老版本的vue中,允许v-if和v-for放在同一个标签中,没有先后顺序的要求,但是v-for会先被执行。
在新版本的vue中,v-if和v-for写在同一个标签中可能会导致出现语法错误。
渲染过程:对arr每一项先做map循环判断v-if给出的条件,再做一遍for 循环渲染。
这样会导致:arr 数组新增一项数据时,会对每一项再做一遍v-if 循环,然后for 循环渲染。
解决方案:将v-for写在最外层的标签上
<div id='app'>
<div v-for="(el,index) in arr">
<h1 v-if="index!=1">{{el}}</h1>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
arr:["a","b","c"]
}
})
</script>
//如果if和for套在一层,数据容器发生变化时,if会重新判断一遍
嵌套的写法 数据容器变化时 if只判断新增的数据
这样当arr 数组某一项数据发生变化时,只对新增的数据进行v-if 判断,节约渲染效率
这样会引起新的问题:外层for的div会也创建一个挂载到DOM中
解决方案:微信小程序采用block元素,vue采用template标签。该标签会在渲染后被移除,其实就是dom操作中的fragment
<div id='app'>
<template v-for="(el,index) in arr">
<h1 v-if="index!=1">{{el}}</h1>
</template>
</div>
<script>
new Vue({
el: '#app',
data: {
arr:["a","b","c"]
}
})
</script>
==========
DOM:
var fnode=document.createDocumentFragment()//冰容器
for(let i=0;i<10000;i++){
var s=document.createElement("span")
s.innerHTML=new Date()
fnode.appendChild(s)
document.body.appendChild(s)
}
document.body.appendChild(fnode)
v-for中key的意义:
data中for循环的容器数据个数发生变化时,会跟for中的vm节点个数作比较
如果数据多了,会在vm节点后面增加对应数量的节点,并不会重新创建所有节点,然后vm去更新对应的DOM
然后就去刷新数据到界面: 按照for的数据容器中的数据顺序来渲染如果用户以前操作过旧节点,那么新数据顺序可能会出现跟旧节点顺序不匹配的效果(旧节点跟旧数据没有对应起来)
解决方案:for循环时把数据跟创建的节点利用给元素绑定唯一key值(key只能绑定唯一的值,一般来说是后端获取的id)
原理:因为vue在刷新页面组件时,会把旧节点跟新vm节点做比较,如果要增加节点,并不会删除旧节点,而是复用
这样会导致节点跟数据没有绑定关系而重新渲染,用key可以将数据与节点绑定起来。
<div id="app">
<h1>活动:1分钟内从1万件商品中选择你喜欢10件送给你</h1>
<button type="button" @click="add">加载新的商品</button>
<button>提交</button>
<div>
<div v-for=" (item,index) in arr" :key="item.id">
<input type="checkbox" name="goods"/>
{{item.name}}=={{item.info}}
</div>
</div>
</div>
<script type="text/javascript">
new Vue({
el:"#app",
data:{
arr:[
{id:10001,name:"鞋子1",info:"这个鞋子好1"},
{id:10002,name:"鞋子2",info:"这个鞋子好2"},
{id:10003,name:"鞋子3",info:"这个鞋子好3"},
{id:10004,name:"鞋子4",info:"这个鞋子好4"}
],
count:5
},
methods:{
add(){
//网络请求 然后把新商品添加到arr中
//假装网络请求了新数据
var result=this.count++
this.arr.unshift({id:result,name:"鞋子"+result,info:"这个鞋子好"+result})
}
}
})
</script>
",info:“这个鞋子好2”},
{id:10003,name:“鞋子3”,info:“这个鞋子好3”},
{id:10004,name:“鞋子4”,info:“这个鞋子好4”}
],
count:5
},
methods:{
add(){
//网络请求 然后把新商品添加到arr中
//假装网络请求了新数据
var result=this.count++
this.arr.unshift({id:result,name:“鞋子”+result,info:“这个鞋子好”+result})
}
}
})