精华内容
下载资源
问答
  • vue.js的发布者与订阅者

    千次阅读 2020-03-24 20:39:01
    $once 订阅者只订阅一次消息(比如我订阅了一个公众号,它只给我推送了一个内容,我就把它取消订阅了,后续不会再收到) $off 取消订阅(所有的订阅者只接受一次消息) 代码具体介绍 /*--------------------------...

    介绍

    就像一个微信公众号,它会定时推送内容,而订阅它的所有用户就会收到这个推送的内容

    发布与订阅需要在同一个实例下才能够起效果
    $emit - 发布者
    $on — 声明订阅者
    $once 订阅者只订阅一次消息(比如我订阅了一个公众号,它只给我推送了一个内容,我就把它取消订阅了,后续不会再收到)
    $off 取消订阅(所有的订阅者只接受一次消息)

    代码具体介绍

    /*---------------------------html--------------------------*/
    <div id="root">
        <input type="button" @click="fn" :value="num">  //当我点击这个按钮的时候,触发fn事件
    </div>
    /*---------------------------js--------------------------*/
       new Vue({
            el:"#root",
            data:{
                num:1
            },
            methods:{
               fn(){  //当这个事件触发的时候
                      // 发布一个名字为one的消息。
                      //当它发布这个消息以后,订阅这个消息的订阅者都会被触发
                      //第一个参数是你消息的名字,后面的是传的值
                   this.$emit("one",1,2,3,4);
               }
            },
            mounted(){
                // 声明订阅者,订阅了一个名字为one的消息
                this.$on("one",(a,b,c,d)=>{
                    this.$off("one");
                    console.log(a,b,c,d);
                })
                this.$once("one",()=>{
                    console.log(222222222222);
                })
            }
        })
    

    结果展示:(点击 button 以后)
    在这里插入图片描述

    展开全文
  • 主要介绍了Vue发布订阅模式实现过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • zh众所周知,vue2.x版本是通过Object.defineProperty() 种的get进行拦截,set进行发送,其实这只是表面理解,实际运用的是JavaScript的 订阅者、发布者模式。首先,了解一下什么是订阅者、发布者模式 吧。w3c 上是...

    zh众所周知,vue2.x版本是通过Object.defineProperty() 种的get进行拦截,set进行发送, 

    其实这只是表面理解,实际运用的是 JavaScript 的  订阅者、发布者模式。

    首先,了解一下什么是  订阅者、发布者模式 吧。


    w3c 上是这么定义的 


    可以用一个图来理解 



    首先我们来实现一下使用原型链的写法吧

    //定义一个函数,用来承载
    
    function publisher () {
        //定义一个空数组用来接收传递过来数据
        this.arr = [];
    }
    
    publisher.prototype = {
        //订阅
        subscribe : function (fn) {
            //订阅将'订阅者'push到arr数组中
            this.arr.push (fn)
        },
        //解除订阅
        unSubscribe : function (fn) {
            //过滤订阅者,如果'订阅者'el存在arr数组中,就解绑订阅
            this.arr = this.arr.forEach(function (el) {
                if(el !== fn) {
                    return el;
                }
            })
        },
    
        //更新订阅内容
        upDate : function (o,thisObj) {
            //o => 剩余订阅者 
            var scoped = thisObj || window ;
            //或者
            var scoped = thisObj || this.subscribe;
            this.fns.forEach (function (el) {
                // scoped 可以随便设置,el最终会替换scoped,将o 剩余订阅者传递进arr数组,将
                   订阅的人的信息打印出来
                el.call(scoped,o)
            }) 
        }
    }
    
    
    //创建一个实例
    var newSubScribe = new publisher () ;
    
    //创建一个订阅者
    var user = function (data) {
        console.log (` 第一位订阅者 ${data} 订阅了。`)
    }
    
    //创建第二位订阅者
    var newUser = function (data) {
        console.log (` 第二位订阅者 ${data} 订阅了。`)
    }
    
    //绑定订阅
    newSubScribe.subscribe(user);
    
    newSubScribe.subscribe(newUser);
    
    //更新订阅内容,看下效果
    newSubScribe.upDate(`Z先生`);
    
    //解绑第一个订阅者
    newSubScribe.unSubscribe(user);
    
    //在更新下数据
    newSubScribe.upDate(`Z女士`);
    
    /*
        下面我们看下打印结果
    */
    复制代码


    可以看到,已经实现了,第一位订阅者没有了,只剩第二位 订阅者了,当然实现的方法有很多种,这只是其中一种使用原型链

    实现



    转载于:https://juejin.im/post/5c7f6efce51d45043849da2f

    展开全文
  • 要搞清楚vue中的双向数据绑定原理,就必须理解什么是发布、订阅者模式!! 1、首先想好谁是发布者、谁是订阅者(例如NBA专栏就是发布者,NBA球迷就是订阅者) 2、然后给发布者添加一个缓存列表,用于存放回调函数...

     发布/订阅者模式

    要搞清楚vue中的双向数据绑定原理,就必须理解什么是发布、订阅者模式!!

     1、首先想好谁是发布者、谁是订阅者(例如NBA专栏就是发布者,NBA球迷就是订阅者)

     2、然后给发布者添加一个缓存列表,用于存放回调函数用来通知订阅者

      3、最后就是发布消息,发布者者遍历这个缓存列表,依次触发订阅者的回调函数

    废话不多说,直接上代码!希望大家能读懂源码再继续往下看vue的数据更新原理

            let NBAcol = {}; // 自定义一个NBA专栏对象(这就是发布者)
            NBAcol.list = []; // 这里用一个列表来缓存订阅者的回调函数
    
            NBAcol.on = function(key, fun) {// on方法是给list数组添加相应的回调函数
                // 如果还没有订阅此类消息,给该类消息创建一个缓存列表
                /**
                 * list:["xiaoming": [fun], "xiaoqiang": [fun]]
                 */
                if(!this.list[key]) {
                    this.list[key] = [];
                }
                this.list[key].push(fun); // fun就是通知订阅者的回调函数
            }
    
            // 发布事件
            NBAcol.emit = function(key, value) {
                let funs = this.list[key] // 取出list中对应key的用于通知的回调函数数组
                if(!funs || funs.length === 0){// 如果没有订阅过消息,直接返回
                    return;
                }
                funs.forEach(fn => {
                    fn(value)
                });
            }
            // 取消事件的订阅
            NBAcol.remove = function(key, fun) {
                let funcs = this.list[key];
                if(!funcs) {
                    return false
                }else {
                    funs.forEach((item, index) => {
                        if(item === fun) {
                            funcs.splice(index, 1)
                        }
                    })
                }
            }
    
            // 小明的订阅NBA专栏
            NBAcol.on("xiaoming",function(team) {
                console.log("小明订阅的球队是:" + team);
            })
            // 小强的订阅NBA专栏
            NBAcol.on("xiaoqiang", function(team) {
                console.log("小强订阅的球队是:" + team);
            })
    
            NBAcol.emit("xiaoming",'湖人');
            NBAcol.emit("xiaoqiang", '勇士');
    
            // 取消订阅
            NBAcol.remove('xiaoli',function(team){
                console.log("我订阅的球队是:"+team)
            });

    理解了什么是发布,订阅者模式之后我们再来看看vue中更新数据原理

    现象:数据有变化,相关依赖项也会跟着变化

    实现:把依赖项的方法(回调函数)封装在Dep依赖项里面,数据变化时下发通知Dep重新执行相关方法

    let data = {price: 5, quantity: 2};
    let target = null;
    
    class Dep{
        constructor() {
            this.subscribers = [];
        }
        depend() {
            if(target && !this.subscribers.includes(target)) { // target就是对数据的一些操作,即添加订阅者
                this.subscribers.push(target)
            }
        }
        notify() {
            this.subscribers.forEach(sub => sub())
        }
    }
    
    //使用Object.defineProperty来更新data里面的数据
    Object.keys(data).forEach(key => {
        let internalValue = data[key];
    
        const dep = new Dep;
        Object.defineProperty(data, key, {
            get(){
                dep.depend();
                return internalValue;
            },
            set(newValue) {
                internalValue = newValue;
                dep.notify();
            }
        })
    })
    
    function watcher(myFunc) {
        target = myFunc;
        target();
        target = null;
    }
    
    watcher(() => {
        data.total = data.price * data.quantity;
    })
    
    data.price = 200;
    
    console.log(data.total);

    总结:

    1、首先建立一个Dep依赖项(类):在Dep类里面定义一个subscrers数组用于收集订阅者的回调函数(depend())并且逐个执行(notify());

      2、创建数据的劫持: 使用Object.keys(data);遍历data的key,然后通过Object.defineProperty(data, key, {...})来更新data里的数据;  并在遍历中实例化Dep且在get中执行dep.depend(),在get()中执行dep.notify(),注意这里是更新后再执行!

     3、最后就是定义一个监听函数watcher()了;该函数参数是一个函数,把该函数赋值给target并执行之后置为null,taget就是一个订阅者的回调函数

    展开全文
  • 上一篇https://blog.csdn.net/qq_38765789/article/details/99952976讲到数据劫持部分...1.需要一个可以容纳订阅者的消息订阅器Dep function Dep(){ this.subs = []; } Dep.prototype = { addSub:funct...

    上一篇 https://blog.csdn.net/qq_38765789/article/details/99952976 讲到数据劫持部分, 这一部分实现一个订阅者

     

    1.需要一个可以容纳订阅者的消息订阅器Dep

            function Dep(){
      		this.subs = [];
      	}
      	Dep.prototype = {
      		addSub:function(sub){
      			this.subs.push(sub);
      		},
      		notify:function(){
      			// 依次通知
      			this.subs.forEach(sub=>{
      				sub.update();
      			})
      		}
      	}

    2.订阅者

            // vm是vue实例
      	// exp指令的属性值 比如v-model='name'的name
      	// cb是更新函数
     	function Watcher(vm, exp, cb) {
    	    this.cb = cb;
    	    this.vm = vm;
    	    this.exp = exp;
    	    this.value = this.get();  // 将自己添加到订阅器的操作
    	}
    	 
    	Watcher.prototype = {
    	    update: function() {
    	        var value = this.vm.data[this.exp];  //data.name 可能已经更改的数据
    	        var oldVal = this.value; // 添加订阅者时初始化的数据
    	        // 判断是否需要更新
    	        if (value !== oldVal) {
    	            this.value = value;
    	            this.cb.call(this.vm, value, oldVal);
    	        }
    	    },
    	    get: function() {
    	        Dep.target = this;  // 缓存自己
    	        var value = this.vm.data[this.exp]  // selfVue.data['name'] 触发Observe中的get 
    	        Dep.target = null;  // 释放自己 由于target是Dep的原型变量,以免影响其他观察者
    	        return value;
    	    }
    	};

    3. 修改观察者(发布者)部分

            function defineProxy(obj,key,value){
      		// 递归所有子属性
      		Observe(value);
    
      		// 对于每一个属性,都有一个订阅者数组
      		let dep = new Dep();
    
      		// 每调用一次defineProxy,就产生一个该函数上下文,保存这个val
      		let val = value;
      		Object.defineProperty(obj,key,{
      			enumerable:true,
    	  		configurable:true,
    	  		set(newVal){
    	  			if(val === newVal){
    	  				return;
    	  			}
    	  			console.log(`${val}=>${newVal}`)
    	  			val = newVal;
    	  			dep.notify(); //通知订阅者
    	  		},
    	  		get(){
    	  			if(Dep.target){
    	  				dep.addSub(Dep.target)
    	  			}
    	  			return val;
    	  		}
      		})
      	}
      	function Observe(data){
      		if (!data || typeof data !== 'object') {
            	return;
    	    }
    	    Object.keys(data).forEach(function(key) {
    	        defineProxy(data, key, data[key]);
    	    });
      	}

    4.初始化Vue实例

            function SelfVue (data, el, exp) {
    	    this.data = data;
    	    Observe(data);
    	    el.innerHTML = this.data[exp];// 初始化模板数据的值 exp:data.name  
    
    	    // 添加订阅者
    	    new Watcher(this, exp, function (value) {
    	        el.innerHTML = value;
    	    });
    	    return this;
    	}
    
    
        	var ele = document.querySelector('#name');
            var selfVue = new SelfVue({
                name: 'hello world'
            }, ele, 'name');
    
            function changeName(){
        	    selfVue.data.name =  document.querySelector('#editName').value; //触发data的set拦截器
            }

    5.测试

     

    这样就实现了一个简单的双向绑定,但还是需要一个模板解析器compile,用来解析所有结点,并将需要绑定数据的结点绑定为订阅者。具体可以参考https://github.com/canfoo/self-vue/tree/master/v2

    展开全文
  • vue发布订阅者模式$emit、$on

    千次阅读 2019-07-21 11:19:10
    vue中自定义事件,就是用了发布订阅者模式,vm.$on通过自定义事件,事先订阅一件事,vm.$emit通过自定义事件发布消息,vm.$on会接收到。非父子组件数据传递,通常会用到这两个方法: 下边我们先来用js实现发布...
  • 模拟 Vue 响应式原理。 准备工作 数据驱动 数据响应式 数据模型仅仅是普通的 JavaScript 对象,而当我们修改数据时,视图会进行更新,避免了繁琐的 DOM 操作,提高开发效率。 双向绑定 数据改变,视图改变;...
  • 订阅者 发布者 信号中心(事件中心) 我们假定:存在一个“信号中心”,某个任务执行完成,就向信号中心“发布”一个信号,其它任务可以向信号中心“订阅”(subscribe)这个信号,从而知道什么时候可以开始执行,这...
  • i++) { defineReactive(val, keys[i], val[keys[i]]) // 这里的val[keys[i] 是key中key 是为了判定key还有没有其他的对象 } } //订阅者watcher 也就是依赖 export class Watcher{ constructor(vm, expOrFn, cb) { ...
  • vue中发布订阅者模式

    千次阅读 2020-01-13 10:54:07
    https://www.jianshu.com/p/2ec316ca0f8b
  • 监听器Observer和订阅者Watcher 实现简单版Vue的过程,主要实现{{}}、v-model和事件指令的功能 主要分为三个部分 github源码 1.数据监听器Observer,能够对数据对象的所有属性进行监听; 实现数据的双向绑定,首先...
  • 订阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象。这个主题对象在自身状态变化时,会通知所有订阅者对象,使它们能够自动更新自己的状态。 比如addEventListener 这个api就是个...
  • 发布订阅模式:也称作观察模式,定义对象间的一对多的依赖关系,当一个对象的状态发 生改变 时,所有依赖于它的对象都将得到通知; 编码中常用的场景: //订阅事件 window.addEventListener('click',()=&...
  • Vue 发布订阅模式

    2021-09-23 08:43:26
    发布订阅模式:订阅者,发布者,信号中心 我们假定,存在一个“信号中心”,某个任务执行完成,就向信号中心"发布"(publish)一个信号,其它任务可以向信号中心“订阅”(subscribe)这个信号,从而知道什么时候自己...
  • class Vue { constructor(options) { // 获取到根元素 this.el = document.querySelector(options.el) // #root // 获取到数据 this.data = options.data ...
  • Vue消息订阅与发布

    千次阅读 2020-03-24 14:43:13
    Vue的原型上定义一个变量bus,在所有的组件里都可以这个变量,使用this.bus.$emit()发布消息,this.bus.$on订阅消息 <!-- 在Vue的原型上定义一个变量bus,所有Vue的实例或组件都将共享这个bus,可以用bus来发布...
  • 数据劫持+发布者订阅者模式 数据劫持 new vue时候拿到data中返回的对象,通过object.key().forEach()遍历,给原来对象中的属性通过object.defineProperty重新定义赋值。通过这个方法在对象使用这个属性的时候(obj...
  • 订阅者 发布者 信号中心 我们假定,存在一个“信号中心”,某个任务执行完成,就向信号中心“发布”(publish)一个信号,其他任务可以向信号中心“订阅”(subscribe)这个信号,从而知道什么时候自己可以开始...
  • Vue双向绑定(数据劫持,发布订阅者模式,diff算法) 最近一段时间自己找点东西学习,因为面试vue双向绑定问的挺多的,就想去深入研究一下本质原理,说是本质也不算,就是看了看别人的研究总结一点自己的看法和理解...
  • 发布 订阅模式 // 事件触发器 class EventEmitter { constructor () { // { 'click': [fn1, fn2], 'change': [fn] } this.subs = Object.create(null) } // 注册事件 $on (eventType, handler) { ...
  • 观察者(订阅者) – Watcher update():当事件发生时,具体要做的事情 目标(发布者) – Dep subs 数组:存储所有的观察者 addSub():添加观察者 notify():当事件发生,调用所有观察者的 update() 方法 没有...
  • 观察模式与发布订阅模式对比 有人说观察模式是发布订阅的升级版,也有人说发布订阅是进阶版的观察模式,但是无论是观察模式还是发布订阅模式,它们都是定义了对象之间的一种一对多的依赖关系。 观察模式...
  • 发布订阅模式 $ 定义 基于一个自定义事件通道,收集与之相关的订阅成员,通过发布自定义事件的方式通知各个订阅成员。 $ Vue中的语法 // Vue 自定义事件 let vm = new Vue() // 注册事件(订阅消息) vm.$on('data...
  • 发布订阅模式中订阅者和发布者没有关联,所以观察者模式中包含了发布订阅模式(watcher和deep) 2、数据传递 /** *1.vue是单向数据流 *2.Vue组件间传值的方式及之间的区别 *3.props和emit父组件向子...
  • 1.Vue1.0 事件的广播与接收(观察模式) 早期vue1.0组件之间的这通信传递数据的方法,vue官网给出了两上方法 $dispatch 和 $broadcast。 但vue2.0之后就弃用 这两个方法,以下原因是vue官网给出来的 官方文档 2....
  • vue使用的「发布-订阅」模式是什么

    千次阅读 2020-05-05 18:11:46
    发布-订阅模式也叫观察模式
  • 。。 转载于:https://www.cnblogs.com/stephenleee/p/10298939.html
  • 订阅者 发布者 信号中心 我们假定,存在一个“信号中心”,某个任务执行完成,就向信号中心发布(publish)一个信号,其他任务可以向信号中心订阅(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就...
  • ... MVVM拆开来即为Model-View-ViewModel,有View,ViewModel,Model三部分组成。View层代表的是视图、模版,负责将数据模型转化为UI展现出来。Model层代表的是模型、数据,可以在Model层中定义数据修改和操作的...
  • 结合 Vue 源码谈谈发布-订阅模式

    千次阅读 2018-10-21 10:23:23
    最近的工作学习中接触到了发布-订阅模式。该思想编程中的应用也是很广泛的, 例如在 Vue中也大量使用了该设计模式,... 一个缓存订阅者以及订阅者的回调函数的列表 取消订阅(需要分情况讨论) 这么看下来,其实就像 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,509
精华内容 5,003
关键字:

vue订阅者

vue 订阅