首页 > 解决方案 > Phoenix,在模板 eex 中使用 socket.js 之外的套接字和 Presence

问题描述

我想以我自己的方式组织模板中socket和的使用。Presence作为一个新手,在我看来,将所有处理通道的客户端代码放入其中sockets.js可以将其转换为非常大的一块。特别是如果有许多页面使用套接字/存在。我不知道哪个是最好的解决方案(或者这是否对其他人来说是个问题),但是我误解了 js 的功能,导致我很好地组织了代码。

socket.js

    import {Socket, Presence} from "phoenix"
    // Other stuff
    export {
      Presence,
      socket
    }

app.js,而不是import socket from "./socket"在结尾,我写

import {Presence, socket} from "./socket"

window.getPhoenixSocket = function () {
    return socket;
};
window.getPhoenixPresence = function () {
    return Presence;
};

在模板中eex(我知道混合 html 和脚本不是一个好习惯)(除了 React 家伙!)我编写了以下脚本:

<script>
  window.onload = function () {
    let channel = getPhoenixSocket (). channel ("cute: channel", {})
    let Presence = getPhoenixPresence ();
....
// Here I can use channel and Presence for my obscure purposes
....
}
</script>

因此,使用套接字的每个页面的代码都保留在自己的页面中,而不是在socket.js

由于我对这个解决方案并不完全满意,所以我问你,这是正确的吗?是不是?最好的方法是什么?有没有人有这个问题?

===== 编辑 ======

解决方案1:

elixirforum同行曝光了一个清晰、聪明、善良和完整的回应

解决方案2:

Deini 在 Elixir-Lang 的 Slack Channel 中指出的另一个解决方案再次使用 Webpack,并且涉及更多 Phoenix-Elixir 风格,已由 hoang_nguyen 在Medium上发布。

解决方案3:

在Diacode和第二页中使用早午餐和使用Webpack

标签: javascriptsocketselixirphoenix-frameworkphoenix-channels

解决方案


选择的解决方案有几个部分,如diacode所示,只需少量更改即可在 Phoenix> = 1.4 的未来 Webpack 中应用。

首先是指明我们要加载哪个js文件,为了方便我们将其命名为模块-模板对。

该名称在 中的函数中创建layout_view.ex,并作为属性放置在Body标签中,app.html.eex如下所示:

<body data-js-view-name="<%= js_view_name(@view_module, @view_template) %>">

然后,app.js负责为我们放置的每个模板加载特定的 js,assests/js/views并调用加载函数。

import loadView from './views/view_loader';

function handleDOMContentLoaded() {
  //// Get the current view name
  const viewName = document.getElementsByTagName('body')[0].dataset.jsViewName;
  // Load view class and mount it
  const ViewClass = loadView(viewName);

  window.currentView = new ViewClass();
  window.currentView.mount();
}

function handleDocumentUnload() {
  window.currentView.unmount();
}

window.addEventListener('DOMContentLoaded', handleDOMContentLoaded, false);
window.addEventListener('unload', handleDocumentUnload, false);

视图的加载器是:

    import MainView    from './main';
    import RoomShowView from './room_show';
    import UserShowView from './user_show';

    // Collection of specific view modules
    const views = {
      "room_show": RoomShowView,
      "user_show": UserShowView
    };

    export default function loadView(viewName) {
      return views[viewName] || MainView;
    }

现在,你必须导入视图(这将随着 Webpack 改变)

每个 js 文件的结构是一对函数mountunmount, (默认情况下调用视图父级)我们放置代码的位置。

import MainView from './main';
import socket from "../socket";
import {Presence} from "phoenix";

export default class View extends MainView {
  mount() {
    super.mount();
    // the code
    console.log('room-show mounted');
    console.log('eex room.id: '+eex["@room.id"])
  }

  unmount() {
    super.unmount();

    // Specific logic here
    console.log('room-show unmounted');
  }
}

在模板中,我们将从服务器嵌入的变量放在我们从动态加载的代码访问的字典中。

<script>
var eex = {
  "@room.id": <%= @room.id %>,
  "@current_user.name": "<%= @current_user.name %>",
  "@current_user.id": <%= @current_user.id %>
}
</script>

想法是仅在一个模板中使用单个通道,并为所有模板的通用目的维护另一个通道。频道是在 中创建的app.js,您可以push在任何其他模板中,我已将其放入main.js

我省略了代码,因为它在链接中,我相信你已经在其他任何地方看到过它。

还有很多工作要做,这是一个未完成的代码。但是在 GitHub 上


推荐阅读