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

网站推广排名外包工作室网站域名

网站推广排名外包,工作室网站域名,有必要自建网站做导购吗,网站运营一般做那些分析Vue2.x 响应式原理 Vue2.x 响应式#xff1a; 实现原理 对象类型#xff1a;通过 Object.defineProperty() 对属性的读取、修改进行拦截( 数据劫持 )数组类型#xff1a;通过重写数组方法#xff0c;并作为拦截器挂载到数组对象与数组原型之间#xff0c;来实现拦截。 存在… Vue2.x 响应式原理 Vue2.x 响应式 实现原理 对象类型通过 Object.defineProperty() 对属性的读取、修改进行拦截( 数据劫持 )数组类型通过重写数组方法并作为拦截器挂载到数组对象与数组原型之间来实现拦截。 存在问题 对于对象类型直接操作对象新增属性或删除属性界面不会更新因为Vue无法监听到对于数组类型直接通过下标修改数组元素界面不会更新。直接修改数组长度也不会生效。Vue 同样无法监听到解决办法 通过 this.$set() 或 Vue.set() 来实现对于对象类型的属性新增。通过 this.$delete 来删除对象类型中的属性。通过可以通过 this.$set() 或 Vue.set() 来实现对于数组类型的数组元素修改。也可以通过 调用拦截器中的数组方法来改变数组元素例如splice Vue3.x的响应式 因为Vue3重新改写了底层响应式原理那我们大胆猜测一下Vue3 应该修复了 Vue2.x 版本的问题也就是说 Vue3 能够直接监听到对于对象的新增属性或删除属性同时还能直接通过数组下标来操作数组或通过 length 属性直接改变数组长度而不用依赖于 $set 方法、$delete 方法或 splice 方法。 新增或删除对象中的属性 templatebutton clickaddSex点击新增 sex 属性/buttonbutton clickdeleteName点击删除 name 属性/button /templatelet person reactive({name: al, });function addSex() {person.sex 男 // Proxy(Object){name:al,sex:男} }function deleteName() {delete person.name // Proxy(Object){sex:男} } 新增或删除数组中的元素由此可以证明只要是能改变原数组的方法在操作数组之后都会被 Vue3 所监听到 let person reactive({hobby:[吃饭,睡觉] });// 新增第三个元素 function updateHobby() {person.hobby[2] 打豆豆 // Proxy(Object) {hobby: [吃饭, 睡觉]} }//删除第一个元素 function deleteArr() {// 通过shift 删除第一个元素person.hobby.shift() // Proxy(Object) {hobby: [睡觉, 打豆豆]}// 通过splice 删除第一个元素person.hobby.splice(0,1) // Proxy(Object) {hobby: [睡觉, 打豆豆]}// 通过pop删除最后一个元素person.hobby.pop() // Proxy(Object) {hobby: [吃饭,睡觉]}} 通过数组下标改变数组元素 let person reactive({hobby:[吃饭,睡觉] });//通过数组下标改变数组元素 function changeHobby (){person.hobby[0] 学习 // Proxy(Object) {hobby: [学习, 睡觉]} } 通过length直接改变数组长度 function changeLength() {person.hobby.length 1 //[吃饭] 数组 length 变为1 }function changeLength() {person.hobby.length 4 //[ 吃饭, 睡觉, null, null ] 数组 length 变为4 } Vue3响应式方式区分 上面说了这么多Vue3响应式的使用方式我们发现 Vue3 针对于 Vue2 的痛点Vue3给出了解决办法那我们现在来看一下Vue3 是怎么解决这些问题的。 首先Vue3 存在两种响应式转化的方式分别是 ref()函数 和 reactive()函数。 ref() 函数能接收基本数据类型也能接收引用类型的数据所以Vue3推荐使用 ref() 函数来实现响应式。 reactive() 函数只能接受引用类型数据不能转化基本类型数据。 所以 ref() 函数和 reactive()函数进行响应式转化的底层原理其实是不一样的。 ref()函数实现响应式 在调用 ref() 函数时会先调用 createRef() 函数。 export function ref(value) {return createRef(value, false); } 然后在 createRef() 函数中 判断当前接收的参数是否为 ref 对象如果是则直接返回该响应式数据避免重复转化如果不是则调用 new RefImpl() 构造函数生成 RefImpl 引用对象 // 接收两个参数 // 第一个参数 rawValue 是需要转化为 ref 的原始值 // 第二个参数 shallow 是一个布尔值标识是否是浅层响应如果为 true则只处理表面层次的响应式而不会递归处理嵌套对象function createRef(rawValue, shallow) {// 判断需要转化的数据是否已经是 ref 对象如果是则直接返回该数据避免重复转化// 但是 isRef 函数并不会进行深度响应式判断如果对一个深度响应式对象再次使用 ref 或 reactive可能会导致嵌套的代理对象if (isRef(rawValue)) {return rawValue;}// 如果不是 ref 对象则调用 RefImpl 构造函数生成新的 RefImpl 引用对象// 同时传递 rawValue 和 shallow 来初始化响应式数据以及确定相应深度return new RefImpl(rawValue, shallow); } RefImpl 类是 ref 对象的实际实现。主要包括 存储原始值以及响应值_rawValue 存储原始值_value存储响应值 响应式处理通过 shallow 来决定是否进行深层响应式数据处理 依赖收集与分发在 get 函数中通过 trackRefValue 函数来收集依赖。在set函数中通过 triggerRefValue 函数通知依赖更新。 RefImpl 类解析 class RefImpl {private _value: any; // 用来存储响应值private _rawValue: any; // 用来存储原始值public dep?: Dep undefined; // 用来收集分发依赖public readonly __v_isRef true; //是否只读暂不考虑// 接收 new RefImpl() 传递过来的 rawValue 和 shallow constructor(value, public readonly __v_isShallow: boolean) {// 判断是否需要深层响应如果不用直接返回 Value 值如果需要深层响应则调用 toRaw 函数解除 value 的响应式将其转化为原始值以保证后续的深层响应this._rawValue __v_isShallow ? value : toRaw(value);// 判断是否需要深层响应如果不用则直接返回Value不做响应式处理。如果需要深层响应则调用 reactive 函数进行深层响应this._value __v_isShallow ? value : reactive(value);}get value() {// 收集依赖trackRefValue(this);// 返回响应式数据return this._value;}set value(newVal) {// 将 newVal 转化为原始值并于初始原始值比较若不同则准备更新数据渲染页面分发依赖if (hasChanged(toRaw(newVal), this._rawValue)) {//判断是否需要深层响应如果不用直接返回 newVal 值如果需要深层响应则调用 toRaw 函数解除 newVal 的响应式将其转化为原始值以保证后续的深层响应this._rawValue this.__v_isShallow ? newVal : toRaw(newVal);// 判断是否需要深层响应如果不用则直接返回Value不做响应式处理。如果需要深层响应则调用 reactive 函数进行深层响应this._value this.__v_isShallow ? newVal : reactive(newVal);// 分发依赖通知更新triggerRefValue(this);}} } trackRefValue() 函数用来收集依赖 // 接收参数 ref 也就是当前 refImpl 引用实例对象 function trackRefValue(ref) {// 判断当前是否处于依赖收集状态在 Vue2.x 中相当于 window.target 。一般用来判断当前是否有活跃的响应式副作用正在运行if (isTracking()) {// ref.dep 是 RefImpl 实例对象上的一个属性相当于 Vue2.x中的 Dep 类用来收集或分发依赖// 判断 ref.dep 是否存在。若存在则直接使用若不存在则通过 createDep 函数创建一个新的依赖集合并赋值给 ref.dep ,然后使用// 将当前活跃的副作用effect添加到 ref.dep 中以便在将来 ref 值变化时能够触发这些副作用。trackEffects(ref.dep || (ref.dep createDep()));} } triggerRefValue()函数用来分发依赖 function triggerRefValue(ref) {// ref.dep依赖集合。如果存在依赖集合则继续进行触发操作。if (ref.dep) {// 遍历并执行 ref.dep 中的所有副作用effect以响应 ref 值的变化。这个函数会通知所有依赖于 ref 值的副作用重新运行。类似于 Vue2.x中的 nofiny() triggerEffects(ref.dep);} }如果需要深层响应转化则需要用到 reactive() 函数这里需要重点说明一下 reactive()函数的设计是单例模式也就是说对同一个对象多次调用 reactive() 函数返回的都是同一个代理对象。对一个代理对象调用reactive() 函数总会返回代理对象自身。所以如果 ref 函数接收的是一个 Proxy代理对象的话调用 reactive 函数之后返回的还是本身的 Proxy 代理对象并不会重复转化一次。 这个规则对嵌套对象也适用。依靠深层响应性响应式对象内的嵌套对象依然是代理对象。 reactive 函数的响应式原理 上面说到了 在 ref函数中如果接收了一个对象且需要深层响应的话就会调用 reactive 函数来进行响应式转化那我们现在来看看 reactive 函数转化响应式数据的原理 首先在了解 reactive 函数的原理时我们需要了解reactive 函数的基本概念可以参考我的上一篇博文--reactive()函数。在这篇博文中我大概讲了一下 reactive 函数是怎么通过 Proxy 代理对象以及 Reflect 对象来实现响应式操作的。现在让我们完善一下 reactive函数的响应式原理吧。 import { isObject, toRawType } from vue/shared; import { mutableHandlers } from ./baseHandlers; import { ReactiveFlags, reactiveMap } from ./reactive;export function reactive(target) {// 判断 target 是否是一个对象if (!isObject(target)) {return target;}// 如果 target 已经是一个响应式对象直接返回它if (target[ReactiveFlags.IS_REACTIVE]) {return target;}// 如果已经存在对应的 Proxy 对象直接返回缓存的 Proxy 对象const existingProxy reactiveMap.get(target);if (existingProxy) {return existingProxy;}// 否则创建一个新的 Proxy 对象const proxy new Proxy(target, mutableHandlers);// 缓存创建的 Proxy 对象避免重复创建这就是单例模式--reactive函数对于Proxy代理对象返回的是其本身reactiveMap.set(target, proxy);return proxy; }到了这一步已经完成了数据代理通过对Proxy代理对象的操作可以同步影响源对象。这时我们就需要进行数据监测了而这一步其实就是在  mutableHandlers 对象之中。 const proxy new Proxy(target, mutableHandlers);mutableHandlers 是 Proxy 代理的核心它定义了各种操作的拦截器如 get、set、has、deleteProperty 等。在 Vue 3 中get 和 set 是最重要的两个拦截器为了方便解释我把 mutableHandlers 中的所有属性方法全部抽离出来了真正源码不是这样的。 import { track, trigger } from ./effect; import { toRaw, reactive, readonly } from ./reactive; import { isObject, hasOwn, isSymbol, hasChanged } from vue/shared; import { ReactiveFlags, toReactive, toReadonly } from ./reactive;const get createGetter(); const set createSetter(); const deleteProperty createDeleteProperty(); const has createHas(); const ownKeys createOwnKeys();export const mutableHandlers {get,set,deleteProperty,has,ownKeys };到这里我们能了解 mutableHandlers 对象中基本都有些什么然后就需要对每个方法进行深入解析了。 在介绍方法之前我们了解一些概念 副作用函数Effect使用了响应式数据的函数例如组件的渲染函数。当数据发生变化时这些函数需要重新执行以更新视图或计算新的值。依赖关系在 Vue 3 中每个响应式属性都可能有多个副作用函数依赖于它。依赖关系在 track 函数中被收集而在 trigger 函数中被使用。全局状态activeEffectVue 3 的响应式系统中有一个全局状态activeEffect用于保存当前正在执行的副作用函数。当我们读取响应式数据时Vue 会检查是否存在当前副作用函数并将其与数据的依赖关联起来。在组件渲染过程中activeEffect 会指向当前的渲染函数从而实现对所有使用到的响应式数据的依赖收集。 get方法get拦截器负责处理对对象属性的读取操作。这是 Vue 响应式系统中最重要的部分之一因为它涉及到依赖追踪。 function createGetter() {return function get(target, key, receiver) {// Reflect.get(target, key, receiver): 使用 Reflect.get 来获取源对象属性的值。// 这是现代 JavaScript 中获取属性值的标准方式可以避免一些特殊情况下的错误。// 可以参考上一篇博文--reactive函数const res Reflect.get(target, key, receiver);// 依赖收集 track(target, get, key): 调用 track 函数来进行依赖收集。// 这使得 Vue 能够追踪哪些组件依赖于这个属性以便在属性变化时触发重新渲染。track(target, get, key);// 如果属性值是对象类型则递归地将其转化为响应式对象实现深度响应式。if (isObject(res)) {return reactive(res); // 深度响应式}// 如果属性值是基本类型则直接返回return res;}; }set方法set 拦截器负责处理对象属性的修改操作这是触发依赖更新的关键部分。 function createSetter() {return function set(target, key, value, receiver) {// 获取上一次的属性值const oldValue target[key];// Reflect.set(): 使用 Reflect.set 来设置对象属性的值,与get一致,返回Boolean值来判断是否设置成功const result Reflect.set(target, key, value, receiver);// 检查新值与旧值是否不同只有在值确实发生变化时才触发更新。if (hasChanged(value, oldValue)) {// 调用 trigger 函数触发响应式更新通知所有依赖该属性的副作用函数如渲染函数重新运行。trigger(target, set, key, value);}// 返回设置的结果状态,true or falsereturn result;}; }deleteProperty 拦截 delete 操作在删除对象属性时触发响应式更新。 function deleteProperty(target, key) {// 检查 target 是否具有 key 属性const hadKey hasOwn(target, key); // 删除 target 的 key 属性与get 和 set 方法类似const result Reflect.deleteProperty(target, key); // 如果删除成功并且 key 属性确实存在if (result hadKey) { // 触发响应式系统的更新通知trigger(target, delete, key); }// 返回删除操作的结果true 或 falsereturn result; },has用于检查一个对象是否拥有某个属性相当于in 操作符 。 has(target, key) {// 判断 target 对象中是否存在属性key返回 Boolean 值const result Reflect.has(target, key);// 收集依赖track(target, has, key);// 返回结果return result;}, ownKeys Reflect.ownKeys 方法返回一个由目标对象自身的属性键组成的数组。它的返回值等同于Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))。 function ownKeys(target) {// 依赖收集标记为数组类型track(target, iterate, array);// 返回所有键--是一个数组return Reflect.ownKeys(target);} 上面是操作对象的方法其中 track 则是收集依赖的方法trigger则是分发依赖通知更新的方法下面简单介绍一下这两个方法是如何工作的。 track收集依赖track 函数 会将 target、key 和当前的副作用函数关联起来这样在 key 对应的属性值发生变化时Vue 就能找到所有依赖这个属性的副作用函数并触发它们重新执行。 function track(target, type, key) {// 首先检查当前是否有正在执行的副作用函数。如果没有则不需要进行依赖收集。// 副作用函数一般在 Vue 的响应式系统运行时注册比如在组件的渲染过程中Vue 会把当前的渲染函数注册为全局的副作用函数。if (!isTracking()) return;// targetMap 是一个全局的 WeakMap用于存储所有的响应式对象及其依赖关系。// 从 targetMap 中获取当前 target 对象的依赖图即 depsMap如果不存在则创建一个新的 Map。//depsMap 是一个 Map用于存储 target 对象中每个属性即 key的依赖集合deplet depsMap targetMap.get(target);if (!depsMap) {targetMap.set(target, (depsMap new Map()));}// dep 是一个 Set用于存储依赖于某个特定属性 key 的所有副作用函数。// 从 depsMap 中获取 key 的依赖集合 dep如果不存在则创建一个新的 Set。let dep depsMap.get(key);if (!dep) {depsMap.set(key, (dep createDep()));}// 将当前的副作用函数添加到 dep 中// 这一步是将当前正在执行的副作用函数如渲染函数添加到依赖集合中以便在这个 key 发生变化时能够重新执行这些副作用函数。trackEffects(dep); }trigger当响应式对象的属性值发生变化时Vue 会通过调用 trigger 函数来通知依赖该属性的所有副作用函数如组件渲染函数、计算属性等重新执行从而实现视图的自动更新。 function trigger(target, type, key, newValue, oldValue) {// targetMap 是全局存储所有响应式对象及其依赖关系的 WeakMap。targetMap 的键是响应式对象 target值是一个 Map这个 Map 存储了该对象每个属性 key 的依赖集合。// depsMap 是当前 target 对象的依赖图里面存储了 key 与其依赖的副作用函数的映射关系。// 如果 depsMap 不存在说明这个 target 对象没有被任何副作用函数依赖直接返回。const depsMap targetMap.get(target);if (!depsMap) {return;}// effects 是一个 Set用于去重并存储所有需要触发的副作用函数。这样可以避免重复触发相同的副作用函数。const effects new Set();// 如果是 SET 操作收集相关副作用函数, 从 depsMap 中获取与 key 相关的副作用函数集合并将其添加到 effects 中。if (key ! undefined) {addEffects(depsMap.get(key));}// addEffects 函数检查是否存在与当前 key 相关的副作用函数如果存在它们将被添加到 effects 集合中。const addEffects (effectsToAdd) {if (effectsToAdd) {effectsToAdd.forEach(effect effects.add(effect));}};// 如果操作类型是 add、delete 或 set而且对象是数组或其他特殊数据结构还需要处理特殊的依赖关系。例如操作数组的 length 属性时需要触发依赖于 length 的副作用函数。if (type add || type delete || type set) {addEffects(depsMap.get(Array.isArray(target) ? length : ));}// 遍历 effects 集合并执行其中的每个副作用函数// 如果副作用函数有一个 scheduler 调度器通常是用来调度执行顺序的则调用调度器否则直接执行副作用函数。effects.forEach(effect {if (effect.options.scheduler) {effect.options.scheduler(effect);} else {effect();}}); }trackEffects 收集依赖 通过源码我们可以知道不论是ref还是reactive在收集依赖时最终都使用了 trackEffects 函数其作用是将当前正在执行的副作用函数例如渲染函数、计算属性等添加到某个响应式数据的依赖集合中。这是依赖收集的一部分目的是在数据变化时触发相关的副作用函数进行更新。 function trackEffects(dep) {// 获取当前正在执行的副作用函数let shouldTrack shouldTrackEffect(dep);if (shouldTrack) {// 将当前的副作用函数 activeEffect 添加到 dep 中。这一步建立了属性与副作用函数之间的单向关联即这个属性知道有哪些副作用函数依赖于它dep.add(activeEffect);// 同时将 dep 添加到 activeEffect 的 deps 数组中。这一步建立了副作用函数与属性之间的双向关联即这个副作用函数知道它依赖于哪些属性。activeEffect.deps.push(dep);} }// 检查当前的副作用函数是否已经被添加到 dep 中以避免重复添加。 function shouldTrackEffect(dep) {// 如果 dep 中已经存在 activeEffect则返回 false表示不需要重复添加否则返回 true。return !dep.has(activeEffect); }在 if 判断中Vue3实现了 双向依赖管理这样做的好处是 避免重复添加由于 dep 是一个 Set它会自动去重确保每个副作用函数只会被添加一次。双向清理在副作用函数停止依赖某个属性时可以通过清理 activeEffect.deps 中的 dep从而移除双向关联避免内存泄漏。 同样的在这里我们也需要理解一些基本概念那就是dep 、 effect、activeEffect、activeEffect.deps dep是一个 Set 集合用来存储依赖某个响应式属性的所有副作用函数。effect是一个包装了副作用逻辑的函数例如渲染函数、计算属性等。当 effect 函数被执行时它会触发响应式数据的读取从而进行依赖收集。activeEffect是一个全局变量用于指向当前正在运行的副作用函数。每当副作用函数被执行时activeEffect 就会被设置为当前的副作用函数从而在依赖收集时可以将这个函数与相应的响应式属性关联起来。activeEffect.depsactiveEffect.deps 是一个数组用来存储当前副作用函数依赖的所有 dep 集合。也就是说activeEffect.deps 中的每一个元素都是一个 dep而每个 dep 都包含了当前副作用函数所依赖的响应式属性。 举一个栗子就是假设我们有一个响应式对象和一个依赖于这个对象的副作用函数 const state reactive({ count: 0 });const effectFn effect(() {console.log(state.count); });在执行 effectFn 的过程中Vue 会执行以下操作 依赖收集effectFn 会读取 state.count因此 state.count 对应的 dep 集合会被收集并且 effectFn 会被添加到这个 dep 集合中。 记录依赖同时Vue 还会将这个 dep 集合添加到 activeEffect.deps 中以便将来进行依赖关系的清理。 触发更新当 state.count 的值发生变化时Vue 会遍历 dep 集合中的所有副作用函数并触发它们重新执行。 清理旧的依赖如果在下一次执行 effectFn 之前某些依赖关系已经不再存在例如副作用函数不再依赖某个属性Vue 会通过遍历 activeEffect.deps 来清理这些不再需要的依赖。 总结 Vue2的响应式 原理通过Object.definePropoty() 实现对数据每个属性的劫持通过get和set实现了响应式问题对于数组数据无法通过数组下标直接操作无法通过 length直接设置数组长度无法             直接给对象或数组添加属性解决通过 vm.$set() 或 this.set() 来对对象或数组进行操作 Vue3响应式 原理Ref响应式还是通过Object.definePropoty()对数据劫持通过get和set实现响应式。reactive则是通过 Proxy对数据进行代理劫持实现响应式。然后通过Reflect实现对源数据的操作优势Proxy是实现对象的监听而不是对某个属性的监听。而且是惰性的嵌套对象只有在被访问时才会被转化为响应式。这种方式避免了不必要的性能开销尤其是在处理大型数据结构时。
文章转载自:
http://www.morning.thrtt.cn.gov.cn.thrtt.cn
http://www.morning.pshtf.cn.gov.cn.pshtf.cn
http://www.morning.tkjh.cn.gov.cn.tkjh.cn
http://www.morning.hmjasw.com.gov.cn.hmjasw.com
http://www.morning.sblgt.cn.gov.cn.sblgt.cn
http://www.morning.flfdm.cn.gov.cn.flfdm.cn
http://www.morning.hmqwn.cn.gov.cn.hmqwn.cn
http://www.morning.qwbht.cn.gov.cn.qwbht.cn
http://www.morning.qiyelm.com.gov.cn.qiyelm.com
http://www.morning.crrmg.cn.gov.cn.crrmg.cn
http://www.morning.zrnph.cn.gov.cn.zrnph.cn
http://www.morning.kqzt.cn.gov.cn.kqzt.cn
http://www.morning.rqqmd.cn.gov.cn.rqqmd.cn
http://www.morning.wjqbr.cn.gov.cn.wjqbr.cn
http://www.morning.rgksz.cn.gov.cn.rgksz.cn
http://www.morning.xykst.cn.gov.cn.xykst.cn
http://www.morning.jbmbj.cn.gov.cn.jbmbj.cn
http://www.morning.nfdty.cn.gov.cn.nfdty.cn
http://www.morning.wfjyn.cn.gov.cn.wfjyn.cn
http://www.morning.pbgnx.cn.gov.cn.pbgnx.cn
http://www.morning.rfjmy.cn.gov.cn.rfjmy.cn
http://www.morning.mumgou.com.gov.cn.mumgou.com
http://www.morning.nxfuke.com.gov.cn.nxfuke.com
http://www.morning.mnbgx.cn.gov.cn.mnbgx.cn
http://www.morning.lonlie.com.gov.cn.lonlie.com
http://www.morning.wrdpj.cn.gov.cn.wrdpj.cn
http://www.morning.gjlxn.cn.gov.cn.gjlxn.cn
http://www.morning.zbqry.cn.gov.cn.zbqry.cn
http://www.morning.rnmmh.cn.gov.cn.rnmmh.cn
http://www.morning.gthgf.cn.gov.cn.gthgf.cn
http://www.morning.jmbgl.cn.gov.cn.jmbgl.cn
http://www.morning.xnpml.cn.gov.cn.xnpml.cn
http://www.morning.hdnd.cn.gov.cn.hdnd.cn
http://www.morning.zcncb.cn.gov.cn.zcncb.cn
http://www.morning.thrgp.cn.gov.cn.thrgp.cn
http://www.morning.kmqwp.cn.gov.cn.kmqwp.cn
http://www.morning.dpdns.cn.gov.cn.dpdns.cn
http://www.morning.gjlst.cn.gov.cn.gjlst.cn
http://www.morning.jfzbk.cn.gov.cn.jfzbk.cn
http://www.morning.lwgrf.cn.gov.cn.lwgrf.cn
http://www.morning.yjxfj.cn.gov.cn.yjxfj.cn
http://www.morning.ymwny.cn.gov.cn.ymwny.cn
http://www.morning.hxljc.cn.gov.cn.hxljc.cn
http://www.morning.ttxnj.cn.gov.cn.ttxnj.cn
http://www.morning.zcfmb.cn.gov.cn.zcfmb.cn
http://www.morning.wzwyz.cn.gov.cn.wzwyz.cn
http://www.morning.nkyqh.cn.gov.cn.nkyqh.cn
http://www.morning.rdtq.cn.gov.cn.rdtq.cn
http://www.morning.bsjxh.cn.gov.cn.bsjxh.cn
http://www.morning.zfhwm.cn.gov.cn.zfhwm.cn
http://www.morning.bpmfg.cn.gov.cn.bpmfg.cn
http://www.morning.rshkh.cn.gov.cn.rshkh.cn
http://www.morning.rjcqb.cn.gov.cn.rjcqb.cn
http://www.morning.djpps.cn.gov.cn.djpps.cn
http://www.morning.lxfyn.cn.gov.cn.lxfyn.cn
http://www.morning.fqlxg.cn.gov.cn.fqlxg.cn
http://www.morning.gcfrt.cn.gov.cn.gcfrt.cn
http://www.morning.nfbxgtj.com.gov.cn.nfbxgtj.com
http://www.morning.jtfsd.cn.gov.cn.jtfsd.cn
http://www.morning.tfei69.cn.gov.cn.tfei69.cn
http://www.morning.yrxcn.cn.gov.cn.yrxcn.cn
http://www.morning.fbhmn.cn.gov.cn.fbhmn.cn
http://www.morning.qbccg.cn.gov.cn.qbccg.cn
http://www.morning.qpmmg.cn.gov.cn.qpmmg.cn
http://www.morning.yjqkk.cn.gov.cn.yjqkk.cn
http://www.morning.rwlnk.cn.gov.cn.rwlnk.cn
http://www.morning.pdmc.cn.gov.cn.pdmc.cn
http://www.morning.qhmhz.cn.gov.cn.qhmhz.cn
http://www.morning.xqjrg.cn.gov.cn.xqjrg.cn
http://www.morning.xcyzy.cn.gov.cn.xcyzy.cn
http://www.morning.gktds.cn.gov.cn.gktds.cn
http://www.morning.tyjp.cn.gov.cn.tyjp.cn
http://www.morning.nhlyl.cn.gov.cn.nhlyl.cn
http://www.morning.bzlfw.cn.gov.cn.bzlfw.cn
http://www.morning.yhwyh.cn.gov.cn.yhwyh.cn
http://www.morning.mtmnk.cn.gov.cn.mtmnk.cn
http://www.morning.slmbg.cn.gov.cn.slmbg.cn
http://www.morning.qsfys.cn.gov.cn.qsfys.cn
http://www.morning.jnbsx.cn.gov.cn.jnbsx.cn
http://www.morning.hlzpb.cn.gov.cn.hlzpb.cn
http://www.tj-hxxt.cn/news/250883.html

相关文章:

  • 网站手机客户端开发教程广州品牌型网站
  • 大学生个人网站模板布吉网站建设哪家服务周到
  • 源码下载站百度免费推广
  • 做网站的集团手机应用下载网站源码
  • wordpress网站绑定多个域名高端网站建设哪里好
  • 学习网站建设课程济南网站建设公司晟创未来
  • vivo手机的网站开发网站页面设计主要包括
  • 服务之家网站推广公司泉州官方网站
  • 南京高端品牌网站建设公众号关注推广
  • 专业网站设计力荐亿企邦WordPress社区论坛
  • 湖北响应式网站建设费用垦利区建设局网站
  • 腾讯如何做网站个人备案的公司网站
  • 酷万网站建设常州本地做网站的大公司
  • 网站建设的目的包含哪些方面关于数据库的网站开发
  • 上海网站建设收费标准微信app下载安装官方版2021
  • 深圳企业公司网站设计网站建设及推广培训
  • 商务网站制作工程师无需下载直接登录qq手机版
  • 上海做原创网站互联网定制网站
  • 安徽做手机网站国外做的好的医疗网站
  • 壶关网站建设绍兴手机网站制作
  • 青岛做网站哪个最好襄阳网站seo技巧
  • 餐饮酒店网站建设wordpress djiango
  • 太原网站建设最好喀什哪有做网站的
  • 谷歌网站收录入口wordpress 首页分页
  • 设计网官方网站网站建设狼雨
  • 国外空间网站源码.net 网站开发 教程
  • 门类细分网站杭州企业营销网站建设公司
  • 显示网站目录军事新闻最新消息中国视频
  • 一个企业网站建设需要多长时间青海网站建设公司哪家好
  • 大型网站建设部署方案免费好用的云电脑