当前位置: 首页 > news >正文

网站设计的公司工作室网络营销教学网站

网站设计的公司工作室,网络营销教学网站,建设网站用苹果系统,网站及推广UI render(state) VUE的特点是数据驱动视图,在这里可以把数据理解为状态,而视图就是用户可以看到的页面,页面是动态变化的,而他的变化或是用户操作引起,或是后端数据变化引起,这些都可以说是数据的状态变…

UI = render(state)

VUE的特点是数据驱动视图,在这里可以把数据理解为状态,而视图就是用户可以看到的页面,页面是动态变化的,而他的变化或是用户操作引起,或是后端数据变化引起,这些都可以说是数据的状态变了,导致页面随之变化。

把顶部公式拆为三部分:UI、render、state。state和UI都是用户定的,不变的是render,所以VUE就担任了这个角色,当VUE发现state变化后,就通过一系列操作,把他反应在了UI上。

那么VUE是如何发现state变化的?引出了VUE的变化侦测:

JS为我们提供了object.defineProperty()方法,通过此方法我们可以知道数据什么时候发生了变化。

1.Object数据变得可观测

数据每次读写能够被我们看到,我们能知道数据什么时候发生了变化,将其称为数据的可观测。通过使用上述对象方法,可以实现。如下

let person = {}
let nameval = 'lwh'
Object.defineProperty(person,name,{get() {console.log('name被读取了')return nameval}set(newval) {console.log('name被修改了')nameval = newval
}
})

通过Object.defineProperty()方法定义了person的Name属性,并把这个属性的读写分别使用get和set方法进行拦截,每当该属性进行读或写操作时候就会触发这两个方法,意味着person的数据对象已经是可观测的了

但是为了将此对象的所有属性都变得可观测,可以编写以下代码: 

export class Observe {constructor(value) {this.value = value//给value新增一个__ob__属性,值为该value的observe实例//相当于给value打上标记,表示他已经转化为响应式了def(value,'__ob__',this)if (Array.isArray(value)) {//为数组的逻辑} else {this.walk(value)}}walk(obj: Object) {const keys = Object.keys(obj)for (let i = 0; i < keys.length; i++) {defineReactive(obj,key[i])}}
}
​
function defineReactive(obj, key, val) {if(typeof val === 'object') {new Observable(val)}object.defineProperty(obj, key, {enumerable: true,configurable: true,get() {console.log(`${key}属性被读取`)return val;},set(newval) {if(val === newval) {return}console.log(`${key}属性被修改了`)val = newval}})
}

上面的代码中,我们定义了observe类,用来将一个普通的Object转化为可观测的object。并且给value新增一个ob属性,表示这个已经被转化成响应式了。

然后判断数据类型,只有Object 类型才会调用walk方法将每一个属性都转换成getter/setter形式来侦测变化,最后在defineReactive中当传入的属性值还是一个object时使用new observe(val)来递归子属性,这样我们就可以把obj中所有属性都变为可观测型的,只要将object传入observe中,那么这个object就会变成可观测,响应式的Object.

observer类位于Vue2源码的src/core/observer/index.ts中。

2.依赖收集

当Object变得可观测后,我们就能知道数据什么时候发生了变化,发生了什么变化,这样就可以通知视图更新。但是问题来了,我们怎么知道哪些视图需要更新?总不能一个数据变化全部视图全部更新一次吧。所以,应该是视图里哪个使用到了这个数据的就更新。

视图里谁用到了这个数据谁更新,说官方一点就是谁依赖了这个数据谁更新。我们建立一个依赖数组(因为一个数据可能被多个地方使用,所以需要建立数组),谁依赖了这个数据就把谁放进这个数组。当数据变化时,就根据它的依赖数组去通知哪些视图需要更新。这个过程就是依赖收集。

那么我们该如何进行依赖收集,如何知道哪些依赖这个数据?

谁用了这个数据,那么当这个数据变化时就通知谁,所谓谁用了这个数据,就是谁获取了这个数据。根据上文可观测数据在被获取时会调用get方法,那么我们就可以在get中收集这个依赖。同样,数据变化会触发Set,所以,我们就在set中通知更新。

所以,我们应该给每个数据都配置一个依赖数组,谁依赖了它就放入谁。不过,单单使用数组的话,功能可能有点欠缺且代码有点耦合。所以拓展一下的话,我们给每一个数据建立一个类,用作依赖管理。所以在vue2源码中有了这个依赖管理器Dep类,代码如下:

// 源码位置:src/core/observer/dep.ts    
export default class Dep {constructor () {this.subs = []}addSub (sub) {this.subs.push(sub)}// 删除一个依赖removeSub (sub) {remove(this.subs, sub)}// 添加一个依赖depend () {if (window.target) {this.addDep(window.target)}}// 通知所有依赖更新notify () {const subs = this.subs.slice()for (let i = 0, l = subs.length; i < l; i++) {subs[i].update()}}
}
​
/*** Remove an item from an array*/
export function remove (arr, item) {if (arr.length) {const index = arr.indexOf(item)if (index > -1) {return arr.splice(index, 1)}}
}

在上面依赖管理器中,初始化了一个sub数组用来存放依赖,并且定义了几个附加方法。

有了依赖管理器后,我们就可以在getter中收集依赖,setter中通知更新了

function defineReactive (obj,key,val) {if(typeof val === 'object'){new Observable(val)}const dep = new Dep()  //实例化一个依赖管理器,生成一个依赖管理数组depObject.defineProperty(obj, key, {enumerable: true,configurable: true,get(){dep.depend()    // 在getter中收集依赖return val;},set(newVal){if(val === newVal){return}val = newVal;dep.notify()   // 在setter中通知依赖更新}})
}

接下来需要知道的是,我们收集的依赖到底是谁?

谁用到了这个数据谁就是依赖,那代码上该如何描述这个谁呢?

在Vue中还实现了一个叫做Watcher的类,这个类的实例就是我们上面说的那个谁。换句话说,谁用到了数据,我们就为谁创建一个Watcher实例。在之后数据变化时,我们不直接去通知依赖更新,而是去通知依赖对应的watch实例,由watcher实例去通知真正的视图

类的具体实现如下:

export default class Watcher {constructor (vm,expOrFn,cb) {this.vm = vm;this.cb = cb;this.getter = parsePath(expOrFn)this.value = this.get()}get () {window.target = this;const vm = this.vmlet value = this.getter.call(vm, vm)window.target = undefined;return value}update () {const oldValue = this.valuethis.value = this.get()this.cb.call(this.vm, value, oldValue)}
}
​
/*** Parse simple path.* 把一个形如'data.a.b.c'的字符串路径所表示的值,从真实的data对象中取出来* 例如:* data = {a:{b:{c:2}}}* parsePath('a.b.c')(data)  // 2*/
const bailRE = /[^\w.$]/
export function parsePath (path) {if (bailRE.test(path)) {return}const segments = path.split('.')return function (obj) {for (let i = 0; i < segments.length; i++) {if (!obj) returnobj = obj[segments[i]]}return obj}
}

分析代码:

1.实例化Watcher类时,会先执行其构造函数;

2.在构造函数中调用了this.get()实例方法;

3.在get()方法中,首先通过window.target = this 把实例自身赋给了全局的一个唯一对象window.target上,然后通过let value = this.getter.call(vm,vm)获取一下被依赖的数据,这里的目的是触发该数据的getter,在上文说过,调用getter会随之调用dep.depend()方法收集依赖,而在dep.depend()上取到挂载到window.target的值并将其存到依赖数组中,在get()方法最后需要将window.target释放掉

4.当数据变化时,会触发setter,在其中执行了dep.notify()方法,在这个方法中,遍历所有的依赖(即watcher实例),执行依赖的update()方法,在方法中调用数据变化的更新回调函数,从而更新视图。

3.不足之处

通过defineProperty方法实现了对Object数据的观测,但是这个方法仅仅只能观测到其中数据及设置值,如果向Object中添加或删除值时,他是无法观察到的,导致添加或者删除值时,无法通知依赖,无法驱动视图更新。vue也注意到了这一点,所以为了解决这个问题,vue添加了两个全局api:$set $delete,在后面学习全局API时会说到。

4.总结

通过Object.defineProperty方法实现了对object数据的可观测,并且封装了Observer类,让我们能够方便的把object数据中的所有属性(包括子属性)都转换成getter/seter的形式来侦测变化。

接着,知道了在getter中收集依赖,在setter中通知依赖更新,以及封装了依赖管理器Dep,用于存储收集到的依赖。

最后,我们为每一个依赖都创建了一个Wtcher实例,当数据发生变化时,通知Watcher实例,由Watcher实例去做真实的更新操作。

其整个流程大致如下:

  1. Data通过observer转换成了getter/setter的形式来追踪变化。

  2. 当外界通过Watcher读取数据时,会触发getter从而将Watcher添加到依赖中。

  3. 当数据发生了变化时,会触发setter,从而向Dep中的依赖(即Watcher)发送通知。

  4. Watcher接收到通知后,会向外界发送通知,变化通知到外界后可能会触发视图更新,也有可能触发用户的某个回调函数等。

http://www.hkea.cn/news/626206/

相关文章:

  • 南召微网站开发手机优化大师官方版
  • 营销型网站技术特点网站推广网
  • 龙游县住房和城乡建设局网站百度seo优化方法
  • 深圳方维网站建设设计个人网站
  • wordpress 流量站百度应用
  • ps素材网seo在线工具
  • 岳阳网站开发公司html网站模板免费
  • 怎样用模板做网站优化网站技术
  • 全国新型疫情最新情况长沙网站搭建优化
  • 郑州网站建设规划seo建站教程
  • 购物网站 购物车界面如何做百度搜索网
  • 推广网站的图片怎么做外贸平台
  • 新手如何给自己的网站做优化bt种子磁力搜索
  • 成都学校网站制作遵义网站seo
  • d?t网站模版宁波seo在线优化哪家好
  • c做的网站淄博做网站的公司
  • 网站开发制作公司郑州网站建设外包
  • 注册域名用个人还是公司好长沙seo优化排名
  • 电子商务网站建设与维护展望今日新闻联播
  • 网站建设主流技术站长之家ping检测
  • 温州建设集团有限公司网站首页百度手机版网页
  • 广西网络干部学院官网seo推广人员
  • 可以做红娘的相亲网站江北seo综合优化外包
  • 公司建设网站需要注意什么软文广告示范
  • 高端网站建设 引擎技企业网页
  • 模仿别人网站百度外链查询工具
  • 教程建设网站广告免费发布信息平台
  • wordpress php5.4支持宁波seo排名优化
  • 宁波制作网站哪个好百度怎么发自己的小广告
  • 新浪网站用什么语言做的百度软件下载