如何在ajax调用后手动将内容添加到pluginOutlet?以及如何重新渲染或刷新pluginOutlet?

你好 :wave:

我是 Discourse 主题和 emberjs 的新手,目前正在开发一个包含主网站导航项的主题。

导航项 JSON 来自一个 ajax 请求,我需要在两个位置显示它。

第一个位置是 header-buttons:before。我通过 api.decorateWidget 并触发 site-header:force-refresh appEvents 成功实现了这一点。

ajax( settings.site_navigation_links_endpoint ).then((result) => {

	if (!result.length) {
		return;
	}

	result.map((customHeaderLinksArray) => {

		const anchorAttributes = {
			title  : customHeaderLinksArray.title,
			href   : customHeaderLinksArray.url,
			target : "self"
		};

		headerLinks.push(
			h(
				`li.custom-header-nav-item`,
				h( "a.custom-header-nav-item-link", anchorAttributes, customHeaderLinksArray.title )
			)
		);

	});

	headerNav = h("ul.custom-header-nav", headerLinks);

	if( settings.site_navigation_position == "inline" ) {
		api.decorateWidget("header-buttons:before", (helper) => {
			return headerNav;
		});
	}

	appEvents.trigger("site-header:force-refresh");

	// To display on location (2nd location, see below )
	// ...
	// ...
}

第二个位置是通过 pluginOutlet below-site-header
我认为我不能像上面那样使用 api.decorateWidget,因为这是一个 pluginOutlet 而不是 widget (?)。

我的问题是:

  1. 如何手动将 ajax 内容插入到 pluginOutlet?
  2. 我还想知道如何在 ajax 调用后即时编译 virtual-dom?例如上面的变量 headerNav,我想获得它的编译后的 HTML 标记。不确定使用哪个库/函数。
  3. 如果可能,如何重新渲染 pluginOutlet?类似于 appEvents.trigger("site-header:force-refresh");

提前感谢!:man_bowing:

2 个赞

正确。有两种方法可以解决这个问题……

  1. 您可以将自定义内容制作成 widget,然后像这样在 plugin outlet 中挂载 widget:

    {{mount-widget widget="widget-name"}}
    

    您可以在 Discourse 中看到 widget 的创建示例,例如主页 logo:discourse/app/assets/javascripts/discourse/app/widgets/home-logo.js at 2dbcea9eeeb816dda347027497b3a49634ef851f · discourse/discourse · GitHub

    在主题中,您会将 widget-name.js 文件添加到 javascripts/discourse/widgets 目录中。

    关于 widget 的更多信息,请参阅 https://meta.discourse.org/t/a-tour-of-how-the-widget-virtual-dom-code-in-discourse-works/40347,但请注意,我们将逐步淘汰 widget,因此在此过程中学到的任何东西都将无法长期使用。

  2. 保持 widget 装饰器不变,并创建一个单独的 Ember 组件,在 plugin outlet 中执行您想要的操作。我们一直在用 Ember 组件(Discourse 的大部分内容都是基于此构建的)来取代 widget。

    这个过程将是这样的:

    1. 在主题的 javascripts/discourse/components 目录中创建组件的 JS 和 HBS(模板)文件。

      • component-name.js

      • component-name.hbs

    2. 构建您的 Ember 组件……不幸的是,这一步本质上是“学习 Ember”(Ember Guides)……但我认为这可能会给您一个大致的起点:

      • component-name.js 中:
      import Component from "@glimmer/component";
      import { tracked } from "@glimmer/tracking";
      import { action } from "@ember/object';
      
      const endpoint = settings.site_navigation_links_endpoint;
      
      export default class ComponentName extends Component {
        @tracked navLinks = null;
      
        @action
        async fetchNavLinks() {
          try {
            const response = await fetch(endpoint);
            const data = await response.json(); // 假设这是 json
            this.navLinks = data;
          } catch (error) {
            console.error("Failed:", error);
          }
        }
      }
      
      • component-name.hbs 中:
      <div {{did-insert this.fetchNavLinks}}>
        {{#each this.navLinks as |link|}}
          <a href={{link.anchor}}>{{link.title}}</a>
        {{/each}}
      </div>
      

      这将调用 fetchNavLinks 操作,只要组件被插入(在这种情况下,当您访问 Discourse 站点并渲染应用程序时)。每当 navLinks 更新时,组件的内容就会更新,因为它是一个被跟踪的属性。

      如果您想比组件渲染时更频繁地更新链接,您需要在此处添加更多逻辑到 JS 中……例如检查当前路由(页面)是否满足特定条件。

    3. 通过在 javascripts/discourse/connectors/below-site-header/my-component-connector.hbs 中将其添加到 outlet 来将此组件添加到 plugin outlet:

      <ComponentName />
      
9 个赞

非常感谢 Kris!这非常有帮助。

我选择了第二种方法,使用组件,因为小部件正在逐渐淘汰。除了 .hbs 文件中的函数调用有一个小小的拼写错误,应该是 {{did-insert this. fetchNavLinks}},其他一切都正常!

很高兴知道我们有 did-insert,这让我松了一口气!我现在已经完成了任务。:man_bowing:

1 个赞

啊,很高兴你注意到了,我已经修正了上面的帖子

1 个赞

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.