在 Backbone js 中永久引用来自另一个数据的数据

Permanently reference a piece of data from another in Backbone js

本文关键字:数据 另一个 引用 Backbone js      更新时间:2023-09-26

我正在使用 Backbone 创建一个用户与内容(书签、星号等)交互的网站,我想要一种方法来存储用户在用户数据中与之交互的内容。很简单,但我正在寻找有关最佳方法的信息。

我已经构建了一个没有用户帐户的原型(数据加载到 localStorage 中),因此内容本身现在存储用户交互(在该内容的元数据中),但要一次向多个用户开放,我想更改它,以便一旦用户保存一段内容, 该内容的 ID(或永久内容)将保存到用户帐户数据中。

我当前使用的是 localStorage 适配器,我在页面加载时加载内容,但对于 Backbone,模型的 ID 每次都会更改。一旦我移动到具有用户帐户的 REST 数据库,我不确定如何将用户与之交互的内容保存在其帐户详细信息对象中,并能够在 UI 中可靠地使用它。

任何帮助为我指明正确的方向都会很棒。其他人是如何解决这个问题的?自定义 uid?数据库中的 ID?

谢谢

保罗

更新:在与OP的私人对话中,他解释说,他需要在各种设备中显示网站的多个实例,以显示登录用户的一致用户数据(即用户偏好应反映在所有设备上)。为了在客户端和服务器之间保持新的链接,OP 将使用 socket.io。

解决方案概述

在此方案中,基本上将传递三种类型的数据。网站内容数据,将显示为单个视图。服务器用于识别用户的用户配置文件数据;基本上是唯一的用户 ID (UID)。最后,反映用户已添加书签(加星标)的 conent 的数据。

挑战在于保持给定用户的所有并发会话中的用户选择数据最新。我将在下面描述的想法将解释如何在所有三个数据源之间建立通信链接,以便动态数据(用户选择)可以持久化并立即刷新。为此,我们将使用 Backbone 的事件聚合器,以及 Backbone 视图和模型提供的封装。

数据库结构式

为了反映三组数据,数据库应设计有三个表:User Profile表、Content表和User Content查找表。架构应如下所示,

                     User Profile                         Content
       ---------------------------------------   --------------------------
       | UID | Username | First | Last | ... |   | ID | Title| Date | ... |
       ---------------------------------------   --------------------------
                                User Content Lookup 
                                   ------------
                                   | UID | ID | 
                                   ------------

前端设计

我们必须设置三种类型的 Backbone 对象来处理数据轮循机制。用于实例化我们的用户偏好对象的用户视图。用于处理事件委派和项目呈现的每个内容项的视图。以及一个 Backbone 集合对象,它将充当控制器,具有用于持久保存和获取数据的逻辑。为了让每个人都说话,我们将安装一个具有本地范围的事件聚合器,所有这些视图都可以订阅和发布到该聚合器。

用户和内容视图

用户视图是普通的主干视图。在图形上,它只提供登录/注销,帐户配置文件等链接。它也是用户配置文件数据的存储库,它将其存储为模型。我们关心的是它 1.具有用户的唯一 ID,以及 2。将使用该 UID 实例化控制器对象。

// We set up the user model to initialize the 
// controller when the data has been fetched
var UserModel = Backbone.Model.extend({
  initialize: function(options) {
    this.controller= options.controller; // A reference to the controller is passed
                                         // in before we instantiate the model
    _.bindAll(this, "initializeController"); // Ensures proper context
    this.listenTo(this, "add", this.initializeController);
  },
  initializeController: function () {
    this.controller.fetch({ id: this.get('UID') });
  },
}); 
// We fetch the user data, which, when it comes in, initialized the
// user's ID
var usrModel = new UserModel({ controller: appController });
usrModel.fetch();

每个内容行都有自己的视图。这允许在用户与该内容项交互时轻松管理事件。每个视图都会将自己的 ID 以及描述交互的事件发送到控制器。相反,控制器可以发送视图事件,在单独的并发会话中的用户选择或取消选择视图时向其发出警报。

// We wire the star event
initialize: function() {
  _.bindAll(this, "checkItem", "uncheckItem", "onClickStar");
  // Listen to items that have changed in a concurrent session
  this.listenTo(App.vent, "new:item:selected", this.checkItem);
  this.listenTo(App.vent, "new:item:unselected", this.uncheckItem);
},
events: {
  "click .star": "onClickStar"
},
onClickStar: function () {
  // we check if the star has been checked or unchecked
  // Here you can roll your own, depending on your implementation (e.g. checkbox)
  if (checked)
   App.vent.trigger("item:selected", this.model.get('ID'));
  else
   App.vent.trigger("item:unselected", this.model.get('ID'));
},
checkItem: function (id) {
  if (this.model.get('ID') == id)
    // find the check item and check it (without using click)
},
uncheckItem: function (id) {
  if (this.model.get('ID') == id)
    // find the check item and uncheck it (without using click)
}

关键是在触发器上发送ID,这样监听触发器的控制器就知道要add/remove什么。

控制器

控制器本身就是操作的大脑。下面是我们订阅内容项更改,并在后端传播这些更改,我们在后端侦听更改并将其发布到视图中。在这里,我们设置了与内容事件交互的 socket.io 绑定。

// Let's define the controller collection object
// The controller has to defined AND instantitated BEFORE 
// the user model object, so that it can pass a reference to
// itself to the user model
var Controller = Backbone.Collection.extend({
  initialize: function () {
    _.bindAll(this, "socketIni");
    this.socketIni();
  },
  // We override fetch to pass in the id we need for the fetch route
  fetch: function(options) {
    this.url = "/user/" + options.id + "/content";
    return Backbone.Collection.prototype.fetch.call(this, options);
  },
  socketIni: function() {
    var socket = io();
    this.listenTo(App.vent, "item:selected", function (id) {
      // When a check is added, socket emits the id and event
      socket.emit('item added', id);
    });
    this.listenTo(App.vent, "item:unselected", function (id) {
      // When a check is removed, socket emits the id and event
      socket.emit('item removed', id);
    });
    // Set up socket to let the content views when something changes in the db
    socket.on('new item selected', function(id) {
      App.vent.trigger('new:item:selected', id);
    });
    socket.on('new item unselected', function(id) {
      App.vent.trigger('new:item:unselected', id);
    });
  },
});
// We instantiate the controller that we passed in to usrModel
// REMEMBER: This must be done BEFORE you construct userModel.
vet appController = new Controller();

上面的代码可能并不完美,但它演示了如何在多个并发会话中保持大量视图新鲜的基本思想。