首页 > 解决方案 > 使用ClojureScript,如何自定义material-ui滑块组件中的ValueLabel?

问题描述

这里,有一个例子展示了如何使用 javascript 自定义 ValueLabel。

import React from "react";
import { withStyles, makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import Slider from "@material-ui/core/Slider";
import ValueLabel from "@material-ui/core/Slider/ValueLabel";

const StyledValueLabel = withStyles({
  offset: {
    top: -28,
    left: props => props.index === 0 ? "calc(-50% + -20px)" : "calc(-50% + 12px)"
  },
  circle: {
    transform: props => props.index === 0 ? "rotate(-90deg)" : "rotate(0deg)"
  },
  label: {
    transform: props => props.index === 0 ? "rotate(90deg)" : "rotate(0deg)"
  }
})(ValueLabel);

const useStyles = makeStyles({
  root: {
    width: 300
  }
});

const MySlider = withStyles({
  root: {
    color: "#3880ff",
    height: 2,
    padding: "15px 0"
  },

  track: {
    height: 4
  },
  thumb: {
    background: "transparent",
    "&:focus,&:hover,&$active": {
      boxShadow: "inherit"
    }
  },
  rail: {
    height: 4,
    opacity: 0.5,
    backgroundColor: "#bfbfbf"
  },
  mark: {
    backgroundColor: "#bfbfbf",
    height: 8,
    width: 1,
    marginTop: -2
  }
})(Slider);

function valuetext(value) {
  return `${value}°C`;
}

export default function RangeSlider() {
  const classes = useStyles();
  const [value] = React.useState([31, 37]);

  return (
    <div className={classes.root}>
      <Typography id="range-slider" gutterBottom>
        Temperature range
      </Typography>
      <MySlider
        defaultValue={value}
        valueLabelDisplay="on"
        ValueLabelComponent={StyledValueLabel}
        aria-labelledby="range-slider"
        getAriaValueText={valuetext}
      />
    </div>
  );
}

我尝试将其更改为 ClojureScript 版本,但它不起作用。

(ns XXXX
  (:require [reagent-material-ui.components :as mui] 
            [reagent.core :as reagent]
            [reagent-material-ui.styles :as styles]
            ["@material-ui/core/Slider/ValueLabel" :as js-vl]))

...
(let [vlb (styles/with-styles {:circle {:width 40 :height 40}} 
            (reagent/adapt-react-class (.-default js-vl)))]
   [mui/slider
    {:valuelabelcomponent vlb}])

我收到控制台错误,例如:

Warning: Invalid value for prop `valuelabelcomponent` on <span> tag. Either remove it from the element, or pass a string or number value to keep it in the DOM. For details, see https://reactjs.org/link/attribute-behavior 
    at span
    at eval (http://localhost:5555/ui/cljs-runtime/module$node_modules$$material_ui$core$esm$Slider$Slider.js:16:209)
    at WithStyles(ForwardRef) (http://localhost:5555/ui/cljs-runtime/module$node_modules$$material_ui$styles$withStyles$withStyles.js:4:435)
    at div

标签: material-uiclojurescriptreagent

解决方案


首先,我认为此类问题更适合Clojureverse论坛,因为您有更好的机会接触到 Clojure 社区。另外,我认为有办法改善你原来的问题。例如:解释一下你在你的例子中到底想做什么但没有奏效?(很抱歉我选择了这个,但期望 30 行 JSX 和 4 行 Clojure 以相同的方式工作对我来说真的没有意义。它们一定是不同的。)

问题

要获得完整的答案,让我们从我在 Clojure 代码段中注意到的问题开始:

  • (警告不是错误。但是它们可能与错误密切相关。)

  • 道具的大小写。ValueLabelComponentprops的正确关键字是:ValueLabelComponet. Reagent 是 React 的一个瘦包装器,它直接将 react 名称转换为 Clojure 关键字,而无需修改名称。

  • 的用法reagent-material-ui.styles/with-styles。从它的文档字符串:

采用样式生成函数或样式对象。:classes返回包装另一个组件并向其添加道具的高阶组件。注意:输入组件必须将其所有道具(包括孩子)放在一个地图中。

  • React 组件和 Reagent 组件的区别。这是从试剂文档中大量阅读的内容。尽管它们的相似程度有点令人难以置信,但事实并非如此。尤其是当您与外部 React 库进行大量互操作时。

在 ClojureScript 中为 MaterialUI Slider 自定义 ValueLabel 的示例

我将这个示例放在一起,说明如何在不为您解决所有问题的情况下将各个部分组合在一起,假设您的目标是翻译上面 JSX 片段的每一部分。我希望这足以让你解决剩下的问题。

特别注意 React 组件和 Reagent 组件的区别。

(ns example.core
  (:require
   [reagent-material-ui.core.slider :refer [slider]]
   [reagent-material-ui.styles :as styles]
   [reagent.core :as r]
   [reagent.dom :as rdom]
   ["@material-ui/core/Slider/ValueLabel" :as MuiValueLabel]))

(def mui-value-label
  (r/adapt-react-class (or (.-default MuiValueLabel)
                           (.-ValueLabel MuiValueLabel))))

(def with-my-styles
  (styles/with-styles {:offset {:top 50 :left 50}}))

(defn styled-value-label
  [props]
  [(with-my-styles mui-value-label) props])

(defn main []
  [slider
   {:defaultValue        [31 37]
    :valueLabelDisplay   "on"
    :ValueLabelComponent (r/reactify-component styled-value-label)}])

;; Something that renders the component like: 
;; (rdom/render [main] (js/document.getElementById "app"))

结果

值标签向下偏移 50px,向右偏移 50px:

样式值标签

随时评论我的答案,以便我对其进行编辑。干杯!


推荐阅读