首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在ClojureScript / Reagent中将事件处理程序附加到html

在ClojureScript / Reagent中将事件处理程序附加到html
EN

Stack Overflow用户
提问于 2019-12-21 15:27:05
回答 3查看 1.7K关注 0票数 0

我正在ClojureScript / Reagent中开发一个简单的“类似wiki”的超文本视图。

我有一些短信。我现在想把匹配LinkPattern的东西变成可点击的链接。

在“传统”wiki编程中,我只使用regexes代替URL模式。

例如:转弯

this is SomeText that's a link

转到

this is <a href="/view/SomeText">SomeText</a> that's a link

但在这个版本中

( a)我不想使它们成为正常的html锚链接,我想在链接上附加某种点击事件处理程序(这将触发对服务器的Ajax调用,而不是重新加载整个页面)。

( b)我在Clojure的Reagent包装器中工作,负责React。因此,我假设我不想简单地将原始Javascript复制到html中。我希望以一种“原则性”的方式附加事件处理程序,这对ClojureScript和React / Reagent都是正确的。

那我该怎么做呢?

FYI,我正在将标记预处理成HTML,然后使用:危险设置insert将其插入到页面中。因此,无论我如何将单击处理程序添加到链接中,都需要在这种情况下生存下来。

或者我必须在呈现事件处理程序之后添加它们吗?

在这种情况下,我该怎么做?我知道我在JQuery中要做什么,使用"bind“将事件处理程序附加到特定类的跨范围。但是,我对在ClojureScript试剂中正确地思考这个问题感到困惑。在这个世界中,jQuery的"bind“相当于什么?

EN

回答 3

Stack Overflow用户

发布于 2019-12-22 23:48:13

我认为您可能在错误的路径上使用wrt :危险设置I。由于您使用的试剂(它是一个反应包装器),您很少希望以这种方式将HTML注入DOM。

基本方法是对所有HTML使用hiccup,并将应用程序构造为试剂组件的层次结构。除了你使用的试剂成分,你还会有一些“状态”存储在一个试剂原子(或原子)中。一旦连接了所有的位元,应用程序本质上是由对此状态的更改驱动的(您将试剂留给管理DOM)。

例如,(非常简化,从我的头顶!)

您可能有一个具有以下结构的状态原子

代码语言:javascript
复制
(def state (reagent/atom {:articl1 {:title "An Article"
                                    :body "This is the body of the article"
                                    :read false}
                          :article2 {:title "A second article"
                                     :body "Yet another article"
                                      :read false}})

上面的状态原子可以通过AJAX调用来填充以获取文章列表。我可以定义三种试剂成分-

  • 读取开关组件
  • 物品组件
  • 项目列表组件

可以使用许多方法,但essent8ially的思想是,项目列表组件从状态原子获取文章列表,遍历列表,为每一篇文章调用项目组件。文章组件将为每一篇文章生成html --可能会调用其他组件来帮助它(例如,read切换组件,它可能会显示一些文本,其中包含一个单击处理程序,该处理程序将在状态原子中切换:read属性。例如

代码语言:javascript
复制
(defn read-toggle-component [path]
  [:div {:on-click (fn []
                     (swap! state update-in path not))}
  (if (get-in @state [path])
    "Mark unread"
    "Mark read"])

以上内容将生成内容为"Mark“或"Mark”的HTML,具体取决于路径指向的状态原子中的值。例如,这可能是:第1条:从上面的示例读取。如果值为true,则将呈现"Mark“,如果值为false,则将呈现"Mark”。单击处理程序将在单击此值时切换此值。

上面的组件又可以由项目组件调用,这可能类似于

代码语言:javascript
复制
(defn article-component [article-id]
  (let [article (get @state article-id)]
    [:article
      [:h2 (:title article)]
      (when (not (:read article))
        [:p (:body article)])
      [read-toogle-component [article-id :read)]]))

上面的组件将在标签中呈现一篇文章。文章将包含一个标题,可能包含文章主体(取决于:read的值)和一个切换按钮,以在true和false之间切换:read属性。

最后,您将拥有文章列表组件,这可能类似于

代码语言:javascript
复制
(defn article-list-component []
  (let [articles (keys @state)]
    (into
     [:section]
     (for [a articles]
        [article-component a]))))

上面的标签会产生一个标签,在这个标签里,每一篇文章都有标签。

然后,您将在您的clojureScript中得到一些东西,它将挂载文章列表组件。更好的是,您不需要直接处理HTML,甚至不需要直接与DOM交互。页面将在试剂原子被修改后立即更新(通过添加新文章或更改:read属性所带来的天气变化)。

以上是非常粗糙和简化给你的想法。这肯定是充满错误的,但我希望你会指出正确的方向。

你应该熟悉的事情-

最后两个是由重帧的作者编写的,它是一个非常强大但优雅的基于试剂的应用程序编写框架,非常值得一看。即使您认为它对于您的需求来说太大/太复杂,但是在重新框架中有一些非常好的想法,您可以适应您的需求。

如果您还没有这样做,请确保检查凸轮车主。除了提供一个很好的发展环境之外,它还提供了一种简单的“实验”和获得即时反馈的方法,这是学习clojure/clojurescript/试剂的最好方法。

票数 3
EN

Stack Overflow用户

发布于 2019-12-23 15:58:47

你的问题似乎有多个部分。我已经做了一段时间的个人维基了。(存储库这里,直到使用Mercurial后的几个月内,BitBucket将其删除。)

事件处理程序

我的大部分程序都是用Clojure编写的,只有一个Markdown编辑器和用ClojureScript编写的调整大小的控件。我惊讶地获悉,您可以使用带有JavaScript的字符串将事件处理程序添加到hiccup组件中来运行,至少在我尝试过的简单情况下是这样。

例如,下面是我(服务器端)页面呈现逻辑中的一个函数:

代码语言:javascript
复制
(defn sidebar-and-article
  "Return a sidebar and article div with the given content."
  [sidebar article]
  [:div {:class "sidebar-and-article"}
   sidebar
   [:div {:class "vertical-page-divider"}]
   [:div {:class       "vertical-page-splitter"
          :id          "splitter"
          ; Don't forget to translate the hyphen to an underscore. The false
          ; return is required for correct behavior on Safari.
          :onmousedown "cwiki_mde.dragger.onclick_handler(); return false;"}]
   [:article {:class "page-content"}
    article]])

即使这是服务器的一部分,在Clojure中,也可以为:onmousedown事件指定一个处理程序。此代码在页上的列之间绘制垂直分隔符。事件处理程序允许用户拖动拆分器来调整列的大小,然后将这些列发送回服务器,以存储在用户首选项数据库中。

编辑

由于OP要求,添加事件处理程序的方法可以调用用ClojureScript编写的处理程序。例如,在上面的片段中,处理程序引用wiki_mde.dragger.onclick_handler,它只是命名空间中的一个函数:

代码语言:javascript
复制
(ns cwiki-mde.dragger
  (:require [ajax.core :refer [ajax-request text-request-format
                               text-response-format]]))
.
.
.
(defn ^{:export true} onclick_handler []
  (reset! sidebar-ele (.getElementById js/document "left-aside"))
  (reset! starting-basis (- (.-offsetWidth @sidebar-ele) twice-padding-width))
  (reset! dragging true)
  (.addEventListener js/window "mousedown" start-tracking)
  (.addEventListener js/window "mousemove" move)
  (.addEventListener js/window "mouseup" stop-tracking))

不过,OP的评论指出了一些令人困惑的地方。带有事件处理程序的字符串的内容实际上是JavaScript。碰巧的是,ClojureScript编译器已经将函数名转换为JavaScript等效名称。

另一个令人惊讶、也可能令人困惑的事情是,字符串的内容不仅仅是一个函数名,而是两个JavaScript语句。必须添加额外的return false;才能使一个浏览器工作。我感到惊讶的是,竟然有两种说法可以被使用。

链接

和您一样,我最初使用正则表达式来查找和识别wiki链接。然而,他们只是普通的链接与一些样式,以区别链接到不存在的网页.创建链接的方案有点像MediaWiki中使用的方案,它只构建服务器可识别的链接。

从那以后,我转向了一个更高级(更快)的Markdown转换器,柔性标记-java。我不得不为转换器编写一些自定义代码来处理wiki链接。不过,这使我的Java互操作技能达到了极限。也许你可以用这样的东西来构建你想要的链接的类型。

渲染

我认为没有必要使用:dangerouslySetInnerHTML。我处理它的方法是在呈现页面的同时将Markdown转换成HTML,并像其他人所解释的那样将HTML放入一个hiccup :div中。我在服务器上进行转换和页面构建,以响应对上述链接之一的单击。

例如,下面是我现在用于生成上面清单中的articlesidebar内容项的配置。这大部分只是fexmark-java的配置。

代码语言:javascript
复制
(def options (-> (MutableDataSet.)
                 (.set Parser/REFERENCES_KEEP KeepType/LAST)
                 (.set HtmlRenderer/INDENT_SIZE (Integer/valueOf 2))
                 (.set HtmlRenderer/PERCENT_ENCODE_URLS true)
                 (.set TablesExtension/COLUMN_SPANS false)
                 (.set TablesExtension/MIN_HEADER_ROWS (Integer/valueOf 1))
                 (.set TablesExtension/MAX_HEADER_ROWS (Integer/valueOf 1))
                 (.set TablesExtension/APPEND_MISSING_COLUMNS true)
                 (.set TablesExtension/DISCARD_EXTRA_COLUMNS true)
                 (.set TablesExtension/WITH_CAPTION false)
                 (.set TablesExtension/HEADER_SEPARATOR_COLUMN_MATCH true)
                 (.set WikiLinkExtension/LINK_FIRST_SYNTAX true)
                 (.set WikiLinkExtension/LINK_ESCAPE_CHARS "")
                 (.set Parser/EXTENSIONS (ArrayList.
                                           [(FootnoteExtension/create)
                                            (StrikethroughExtension/create)
                                            ; Order is important here.
                                            ; Our custom link resolver must
                                            ; preceed the default resolver.
                                            (CWikiLinkResolverExtension/create)
                                            (WikiLinkExtension/create)
                                            (CWikiLinkAttributeExtension/create)
                                            (TablesExtension/create)]))))

(def parser (.build ^Parser$Builder (Parser/builder options)))
(def renderer (.build ^HtmlRenderer$Builder (HtmlRenderer/builder options)))

(defn- convert-markdown-to-html
  "Convert the markdown formatted input string to html
  and return it."
  [mkdn]
  (->> mkdn
       (.parse parser)
       (.render renderer)))

希望这会有帮助。

票数 3
EN

Stack Overflow用户

发布于 2019-12-23 09:44:43

您可以将标记转换为hiccup (或直接响应元素),而不是HTML。这将让React负责呈现方面,您可以将事件处理程序附加到需要它们的位置,而不必担心DOM。

所以,与其转向

代码语言:javascript
复制
this is SomeText that's a link

转到

代码语言:javascript
复制
this is <a href="/view/SomeText">SomeText</a> that's a link

你把它变成

代码语言:javascript
复制
[:div "this is " [:a {:href "/view/SomeText" :onClick (fn ...)} "SomeText"] "that's a link"]

或者,如果不希望包含元素,则使用:<>而不是:div

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59437437

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档