Vue.js 插件中的绑定上下文?

Vue.js binding context in plugin?

我正在尝试在 Vue.js 中创建一个简单的插件来包装 vue-resource 插件以跟踪请求的状态。

function State() {}

State.prototype.post = function (ctx, name, url, data, successCB, errorCB) {
    var options = {};

    if (errorCB) {
        options.error = function (resp) {
            ctx[name] = 'error';

            return errorCB(resp);
        };
    }

    ctx[name] = 'sending';

    ctx.$http.post(url, data, function (res, code, req) {
        ctx[name] = 'sent';

        return successCB(res, code, req);
    }, options);
};

function install(Vue) {
    Object.defineProperties(Vue.prototype, {
        $state: {
            get: function () {
                return new State;
                // return Vue.state.bind({$vm: this});
            }
        }
    });
}

module.exports = install;

您会看到我从调用 Vue 传递 ctx 上下文以访问它的 data 值。我已经看到 vue-resource 插件有一种方法可以通过插件自动绑定它 bat 不能完全正确地获得语法。

基本上我想避免每次都必须传递 ctx 上下文,它应该已经有了正确的上下文。

编辑

澄清一下,我正在寻找一种解决方案来传递适当的上下文。以上只是一个示例,我并不是在寻找一种跟踪状态的解决方案。

例如在 vue-resource 插件中,如果我们发出任何 http 请求。

this.$http.get('/some/url', {}, function () {
    this.func();

    console.log(this.var);
});

上下文已经在回调中。我不需要做某种 var _this = this 来进入视图范围。我想为我的插件实现相同的目的,以便正确的 this 就在那里。我试图从 vue-resource 插件中找出答案,但很难理解所有代码。

将我的评论扩展到答案 -

所以你的 Vue 组件上有一个 name 属性,你希望这个插件随着 HTTP 请求的进行更新那个值?我认为这会给你带来糟糕的责任链。您的 Vue 实例将需要有一个 name 属性,并且您的插件不会是独立的。

最好让插件自行处理所有状态跟踪。您可以创建一个名为 status 的 属性 状态,它会随着请求的进行而更新。然后你可以使用 this.$state.status 知道当前状态。然后插件负责它的目的,组件保持独立

State.prototype.status = "not sent"; 

State.prototype.post = function (url, data, successCB, errorCB) {
    var options = {};

    if (errorCB) {
        options.error = function (resp) {
            this.status = 'error';

            return errorCB(resp);
        };
    }

    this.status = 'sending';

    this.Vue.http.post(url, data, function (res, code, req) {
        this.status = 'sent';

        return successCB(res, code, req);
    }, options);
};

function install(Vue) {
    Object.defineProperties(Vue.prototype, {
        $state: {
            get: function () {
                var state = new State;
                state.Vue = Vue;
                return state;
            }
        }
    });
}

然后在html:

<div v-if="$state.status == 'sending'">Sending...</div>
<div v-if="$state.status == 'sent'">Sent!</div>
<div v-if="$state.status == 'error'">Error!</div>

如果你确实想按自己的方式做事,我认为你只需要每次在 Vue 组件中将 this 绑定到 post()

this.$state.post(args){

}.bind(this)

所以在 post 函数中 this 将是你的 Vue.我认为第一种方式最好

编辑 --

函数 successCberrorCb 已经 运行 在 Vue 组件的范围内,因为你在那里定义了它们。 vue-resource 回调在您的情况下具有 State 的范围,因为您在此处定义了它们,除非您像您一样传递上下文,否则不会改变。但这里的重点是你的插件不需要知道组件的上下文,就像 vue-resource 永远不知道组件的上下文一样。它只是获取数据,发送请求,然后 运行s 回调。对调用组件一无所知。

因此,在您作为回调发送至 this.$state.post 的函数中,您可以使用 this.var - 编辑您的 Vue 数据,正如您应该能够 那样。在您从您的州发送到 Vue.http.post 的回调中,您可以编辑 State 对象的属性 - 同样,这是预期的行为。您需要使 namestatus 变量成为 State 的一部分,然后在您的 Vue 组件中将其引用为 this.$state.name 以检查状态。

编辑 2:

你甚至可以有一个变量 $state.response 并传入 myCustomVar,然后跟踪 $state.response.myCustomVar。这样你就可以在每个请求中传递不同的自定义变量并独立跟踪它们

我最终解决了这个问题,它比我想象的要容易。

它只是 vue-router$http 方法的一个简单快捷方式包装器,因此可以像这样进行调用:

this.$state.get('/buildings', data, function (resp) {
    this.buildings = resp.data;
}, {
    track: 'getBuildingState'
});

this.$state('/buildings', {
    data: data,
    track: 'getBuildingState',
    success: function (resp) {
        this.buildings = resp.data;
    }
});

可以在 Gihub 上查看代码片段 here