当前位置: 网站首页>小程序开发>网站优化

尉氏网站制作【尉氏网站优化】尉氏建网站、尉氏微信公众号运营、尉氏网页设计、尉氏微信小程序商城

发表日期: 2021-05-07 09:48:29 浏览次数:84

尉氏网站制作【尉氏网站优化】尉氏建网站、尉氏微信公众号运营、尉氏网页设计、尉氏微信小程序商城


尉氏县位于豫东平原,属河南省开封市。东邻通许县、扶沟县,南与鄢陵县、长葛县接壤,西与新郑市交界,北与祥符区、中牟县相连。南北长40.77公里,东西宽43.76公里,总面积约1307.7平方公里,总人口81万人(2000年),中共尉氏县委、尉氏县人民政府驻地:两湖街道。 [1] 

尉氏古称“尉州”,是河南省经济管理扩权县,电价趸售优惠县,拥有省政府批准的全省八大特色基地之一的河南省中原纺织工业基地,省认定的尉氏高效农业示范园区。 [2] 

2018年,全县完成地区生产总值388亿元,增长8%;一般公共预算收入首次突破20亿元、达到20.6亿元,增长16.8%;税收收入15.96亿元,增长29.9%;城镇和农村居民人均可支配收入预计达到26951元、13911元,分别增长8.3%和8.9%。 [3] 


侦测数据的变化 - [基本实现]

在 初步认识 vue 这篇文章的 hello-world 示例中,我们通过修改数据(app.seen = false),页面中的一行文本(现在你看到我了)就不见了。

这里涉及到 Vue 一个重要特性:响应式系统。数据模型只是普通的 JavaScript 对象,当我们修改时,视图会被更新。而变化侦测是响应式系统的核心。

Object的变化侦测

下面我们就来模拟侦测数据变化的逻辑。

强调一下我们要做的事情:数据变化,通知到外界(外界再做一些自己的逻辑处理,比如重新渲染视图)。

开始编码之前,我们首先得回答以下几个问题:

  1. 如何侦测对象的变化?

    • 使用 Object.defineProperty()。读数据的时候会触发 getter,修改数据会触发 setter。

    • 只有能侦测对象的变化,才能在数据发生变化的时候发出通知

  2. 当数据发生变化的时候,我们通知谁?

    • 通知用到数据的地方。而数据可以用在模板中,也可以用在 vm.$watch() 中,地方不同,行为也不相同,比如这里要渲染模板,那里要进行其他逻辑。所以干脆抽象出一个类。当数据变化的时候通知它,再由它去通知其他地方。

    • 这个类起名叫 Watcher。就是一个中介。

  3. 依赖谁?

    • 通知谁,就依赖谁,依赖 Watcher。

  4. 何时通知?

    • 修改数据的时候。也就是 setter 中通知

  5. 何时收集依赖?

    • 因为要通知用数据的地方。用数据就得读数据,我们就可以在读数据的时候收集,也就是在 getter 中收集

  6. 收集到哪里?

    • 可以在每个属性里面定义一个数组,与该属性有关的依赖都放里面

编码如下(可直接运行):

// 全局变量,用于存储依赖 let globalData = undefined; // 将数据转为响应式 function defineReactive (obj,key,val) {     // 依赖列表     let dependList = []     Object.defineProperty(obj, key, {       enumerable: true,       configurable: true,       get: function () {         // 收集依赖(Watcher)         globalData && dependList.push(globalData)         return val       },       set: function reactiveSetter (newVal) {         if(val === newVal){             return         }         // 通知依赖项(Watcher)         dependList.forEach(w => {             w.update(newVal, val)         })         val = newVal       }     }); } // 依赖 class Watcher{     constructor(data, key, callback){         this.data = data;         this.key = key;         this.callback = callback;         this.val = this.get();     }     // 这段代码可以将自己添加到依赖列表中     get(){         // 将依赖保存在 globalData         globalData = this;         // 读数据的时候收集依赖         let value = this.data[this.key]         globalData = undefined         return value;     }     // 数据改变时收到通知,然后再通知到外界     update(newVal, oldVal){         this.callback(newVal, oldVal)     } } /* 以下是测试代码 */ let data = {}; // 将 name 属性转为响应式 defineReactive(data, 'age', '88') // 当数据 age 改变时,会通知到 Watcher,再由 Watcher 通知到外界 new Watcher(data, 'age', (newVal, oldVal) => {     console.log(`外界:newVal = ${newVal} ; oldVal = ${oldVal}`) }) data.age -= 1 // 控制台输出: 外界:newVal = 87 ; oldVal = 88

在控制台下继续执行 data.age -= 1,则会输出 外界:newVal = 86 ; oldVal = 87

附上一张 Data、defineReactive、dependList、Watcher和外界的关系图。

首先通过 defineReactive() 方法将 data 转为响应式(defineReactive(data, 'age', '88'))。

外界通过 Watcher 读取数据(let value = this.data[this.key]),数据的 getter 则会被触发,于是通过 globalData 收集Watcher。

当数据被修改(data.age -= 1), 会触发 setter,会通知依赖(dependList),依赖则会通知 Watcher(w.update(newVal, val)),最后 Watcher 再通知给外界。

关于 Object 的问题

思考一下:上面的例子,继续执行 delete data.age 会通知到外界吗?

不会。因为不会触发 setter。请接着看:

<!DOCTYPE html> <html> <head>     <meta charset="UTF-8">     <meta name="viewport" content="width=device-width, initial-scale=1.0">     <title>Document</title>     <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body>     <div id='app'>         <section>             {{ p1.name }}             {{ p1.age }}         </section>     </div> <script> const app = new Vue({     el: '#app',     data: {         p1: {             name: 'ph',             age: 18         }     } }) </script> </body> </html>

运行后,页面会显示 ph 18。我们知道更改数据,视图会重新渲染,于是在控制台执行 delete app.p1.name,发现页面没有变化。这与上面示例中执行 delete data.age 一样,都不会触发setter,也就不会通知到外界。

为了解决这个问题,Vue提供了两个 API(稍后将介绍它们):vm.$set 和 vm.$delete。

如果你继续执行 app.$delete(app.p1, 'age'),你会发现页面没有任何信息了(name 属性已经用 delete 删除了,只是当时没有重新渲染而已)。

:如果这里执行 app.p1.sex = 'man',用到数据 p1 的地方也不会被通知到,这个问题可以通过 vm.$set 解决。

Array 的变化侦测

背景

假如数据是 let data = {a:1, b:[11, 22]},通过 Object.defineProperty 将其转为响应式之后,我们修改数据 data.a = 2,会通知到外界,这个好理解;同理 data.b = [11, 22, 33] 也会通知到外界,但如果换一种方式修改数据 b,就像这样 data.b.push(33),是不会通知到外界的,因为没走 setter。请看示例:

function defineReactive(obj, key, val) {     Object.defineProperty(obj, key, {       enumerable: true,       configurable: true,       get: function () {         console.log(`get val = ${val}`)         return val       },       set: function reactiveSetter (newVal) {         if(val === newVal){             return         }         console.log(`set val = ${newVal}; oldVal = ${val}`)         val = newVal       }     }); } // 以下是测试代码 {1} let data = {} defineReactive(data, 'a', [11,22]) data.a.push(33)     // get val = 11,22               (没有触发 setter)    {2}      data.a              // get val = 11,22,33  data.a = 1          // set val = 1; oldVal = 11,22,33(触发 setter)

通过 push() 方法改变数组的值,确实没有触发 setter(行{2}),也就不能通知外界。这里好像说明了一个问题:通过 Object.definePropery() 方法,只能将对象转为响应式,不能将数组转为响应式。

其实 Object.definePropery() 可以将数组转为响应式。请看示例:

// 继续上面的例子,将测试代码(行{1})改为: let data = [] defineReactive(data, '0', 11) data[0] = 22    // set val = 22; oldVal = 11 data.push(33)   // 不会触发                     {10}

虽然 Object.definePropery() 可以将数组转为响应式,但通过 data.push(33)(行{10})这种方式修改数组,仍然不会通知到外界。

所以在 Vue 中,将数据转为响应式,用了两套方式:对象使用 Object.defineProperty();数组则使用另一套。

实现

es6 中可以用 Proxy 侦测数组的变化。请看示例:

let data = [11,22] let p = new Proxy(data, {     set: function(target, prop, value, receiver) {         target[prop] = value;         console.log('property set: ' + prop + ' = ' + value);         return true;     }     }) console.log(p) p.push(33) /* 输出: [ 11, 22 ] property set: 2 = 33 property set: length = 3 */

es6 以前就稍微麻烦点,可以使用拦截器。原理是:当我们执行 [].push() 时会调用数组原型(Array.prototype)中的方法。我们在 [].push() 和 Array.prototype 之间增加一个拦截器,以后调用 [].push() 时先执行拦截器中的 push() 方法,拦截器中的 push() 在调用 Array.prototype 中的 push() 方法。请看示例:

// 数组原型 let arrayPrototype = Array.prototype // 创建拦截器 let interceptor = Object.create(arrayPrototype) // 将拦截器与原始数组的方法关联起来 ;('push,pop,unshift,shift,splice,sort,reverse').split(',') .forEach(method => {     let origin = arrayPrototype[method];     Object.defineProperty(interceptor, method, {         value: function(...args){             console.log(`拦截器: args = ${args}`)             return origin.apply(this, args);         },         enumerable: false,         writable: true,         configurable: true     }) }); // 测试 let arr1 = ['a'] let arr2 = [10] arr1.push('b') // 侦测数组 arr2 的变化 Object.setPrototypeOf(arr2, interceptor)    // {20} arr2.push(11)       // 拦截器: args = 11 arr2.unshift(22)    // 拦截器: args = 22

这个例子将能改变数组自身内容的 7 个方法都加入到了拦截器。如果需要侦测哪个数组的变化,就将该数组的原型指向拦截器(行{20})。当我们通过 push 等 7 个方法修改该数组时,则会在拦截器中触发,从而可以通知外界。

到这里,我们只完成了侦测数组变化的任务。

数据变化,通知到外界。上文编码的实现只是针对 Object 数据,而这里需要针对 Array 数据。

我们也来思考一下同样的问题:

  1. 如何侦测数组的变化?

    • 拦截器

  2. 当数据发生变化的时候,我们通知谁?

    • Watcher

  3. 依赖谁?

    • Watcher

  4. 何时通知?

    • 修改数据的时候。拦截器中通知。

  5. 何时收集依赖?

    • 因为要通知用数据的地方。用数据就得读数据。在读数据的时候收集。这和对象收集依赖是一样的。

    • {a: [11,22]} 比如我们要使用 a 数组,肯定得访问对象的属性 a。

  6. 收集到哪里?

    • 对象是在每个属性中收集依赖,但这里得考虑数组在拦截器中能触发依赖,位置可能得调整

就到这里,不在继续展开了。接下来的文章中,我会将 vue 中与数据侦测相关的源码摘出来,配合本文,简单分析一下。

关于 Array 的问题

// 需要自己引入 vue.js。后续也尽可能只罗列核心代码 <div id='app'>         <section>             {{ p1[0] }}             {{ p1[1] }}         </section> </div> <script> const app = new Vue({     el: '#app',     data: {         p1: ['ph', '18']     } }) </script>

运行后在页面显示 ph 18,控制台执行 app.p1[0] = 'lj' 页面没反应,因为数组只有调用指定的 7 个方法才能通过拦截器通知外界。如果执行 app.$set(app.p1, 0, 'pm') 页面内容会变成 pm 18

微信图片_20210425092605.jpg

尉氏网站制作尉氏网站优化尉氏建网站、尉氏微信公众号运营、尉氏网页设计、尉氏微信小程序商城

400-111-6878
服务热线
顶部

备案号: 苏ICP备11067224号

CopyRight © 2011 书生商友信息科技 All Right Reserved

24小时服务热线:400-111-6878   E-MAIL:1120768800@qq.com   QQ:1120768800

  网址: https://www.768800.com  网站建设上往建站

关键词: 网站建设| 域名邮箱| 服务器空间| 网站推广| 上往建站| 网站制作| 网站设计| 域名注册| 网络营销| 网站维护|

企业邮箱| 虚拟主机| 网络建站| 网站服务| 网页设计| 网店美工设计| 网站定制| 企业建站| 网站设计制作| 网页制作公司|

400电话办理| 书生商友软件| 葬花网| 调温纤维| 海洋馆运营维护| 北京保安公司| 殡仪馆服务| 殡葬服务| 昌平殡葬| 朝阳殡葬|

预约专家

欢迎您免费咨询,请填写以下信息,我们收到后会尽快与您联系

  

服务热线:400-111-6878