Создание Twitter Like Dialogbox для ввода - PullRequest
2 голосов
/ 12 июня 2019

Я изучаю ReactJS и Material-UI и, следовательно, я работаю над созданием полуколебального клона.

Я сейчас нахожусь на дорожном блоке в том смысле, что не могу понять, как его построить.диалоговое окно ввода, в которое можно поместить весь текст, видео, фото, gif в одно и то же поле.

Используя <Input /> Я могу индивидуально указать, какой тип ввода у меня есть, т.е. адрес электронной почты, пароль и т. д., используя type.Но я не уверен, как спроектировать это конкретное диалоговое окно для нескольких входов.

Можете ли вы показать мне пример рабочего кода?

enter image description here

1 Ответ

2 голосов
/ 14 июня 2019

Его 2019 и многое изменилось.Это очень грубая и хакерская реализация того, как реализован твиттер.Это довольно просто.


Рабочая демонстрационная ссылка

Для людей, которые хотят просто взглянуть на код, перейдите к codesandbox


tweetsheetpic

Примечание : это было сделано очень быстро, чтобы продемонстрировать, что твиттер сделал под капотом.

Редактор в основном состоит из <textarea />, в который добавляется текст для твитов.Под текстовой областью находится расширяющийся блок div, который зацикливает файлы изображений, выбранные из файловой системы.

Что касается смайликов, то для выбора смайликов используется стандартный смайлик, а для добавления смайликов - простой старый javascript.текущее положение курсора в текстовой области.

Я пропустил сборщик картинок, так как он похож на сборщик изображений, с той лишь разницей, что модал открыт для заполнения картинок из giphy.API от Giphy.может быть легко интегрирован для достижения этой цели.

Ниже перечислены компоненты, написанные


FileInput Component

Компонент FileInput используется в качестве кнопки и средства выбора файлов для выбораизображений.Это равнина <input type="file" />.Собственные стили скрыты, и отображается пользовательский значок

const FileInput = ({ onChange, children }) => {
  const fileRef = useRef();
  const onPickFile = event => {
    onChange([...event.target.files]);
  };
  return (
    <div
      style={{
        width: "35px",
        height: "35px",
        borderRadius: "3px"
      }}
      onClick={() => fileRef.current.click()}
    >
      {children}
      <input
        multiple
        ref={fileRef}
        onChange={onPickFile}
        type="file"
        style={{ visibility: "hidden" }}
      />
    </div>
  );
};

Img Component

Компонент Img отображает изображения, выбранные из входных данных.Он использует URL.createObjectURL для создания временного локального URL-адреса, который можно заполнить внутри тега img.Это предварительный просмотр изображения, который можно увидеть в листе твита под текстовой областью.

const Img = ({ file, onRemove, index }) => {
  const [fileUrl, setFileUrl] = useState(null);
  useEffect(() => {
    if (file) {
      setFileUrl(URL.createObjectURL(file));
    }
  }, [file]);

  return fileUrl ? (
    <div style={{ position: "relative", maxWidth: "230px", maxHeight: "95px" }}>
      <img
        style={{
          display: "block",
          maxWidth: "230px",
          maxHeight: "95px",
          width: "auto",
          height: "auto"
        }}
        alt="pic"
        src={fileUrl}
      />
      <div
        onClick={() => onRemove(index)}
        style={{
          position: "absolute",
          right: 0,
          top: 0,
          width: "20px",
          height: "20px",
          borderRadius: "50%",
          background: "black",
          color: "white",
          display: "flex",
          alignItems: "center",
          justifyContent: "center"
        }}
      >
        x
      </div>
    </div>
  ) : null;
};

Приложение (Tweet Sheet)

Это корневой компонент, который объединяет все вместе.

function App() {
  const [text, setText] = useState("");
  const [pics, setPics] = useState([]);
  const textAreaRef = useRef();
  const insertAtPos = value => {
    const { current: taRef } = textAreaRef;
    let startPos = taRef.selectionStart;
    let endPos = taRef.selectionEnd;
    taRef.value =
      taRef.value.substring(0, startPos) +
      value.native +
      taRef.value.substring(endPos, taRef.value.length);
  };
  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        border: "3px solid",
        borderRadius: "5px",
        width: "600px",
        minHeight: "200px",
        padding: "20px"
      }}
    >
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          flex: 1,
          border: "1px solid",
          borderRadius: "5px",
          margin: "0px"
        }}
      >
        <textarea
          ref={textAreaRef}
          value={text}
          style={{ flex: 1, border: "none", minHeight: "150px" }}
          onChange={e => setText(e.target.value)}
        />
        <div
          style={{
            display: "flex",
            flexDirection: "row",
            flexWrap: "wrap",
            background: "fbfbfb"
          }}
        >
          {pics.map((picFile, index) => (
            <Img
              key={index}
              index={index}
              file={picFile}
              onRemove={rmIndx =>
                setPics(pics.filter((pic, index) => index !== rmIndx))
              }
            />
          ))}
        </div>
      </div>
      <div
        style={{
          display: "flex",
          flexDirection: "row",
          alignItems: "center",
          marginTop: "20px"
        }}
      >
        <div style={{ marginRight: "20px" }}>
          <FileInput onChange={pics => setPics(pics)}>
            <ImgIcon />
          </FileInput>
        </div>
        <EmojiPicker onSelect={insertAtPos} />
      </div>
    </div>
  );
}

EmojiPickerModal

const EmojiPicker = ({ onSelect }) => {
  const [show, setShow] = useState(false);
  return (
    <>
      <button
        onClick={() => setShow(oldState => !oldState)}
        style={{
          width: "30px",
          height: "30px",
          borderRadius: "4px",
          border: "3px solid",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          background: "transparent"
        }}
      >
        ej
      </button>
      {ReactDOM.createPortal(
        show && <Picker onSelect={onSelect} />,
        document.body
      )}
    </>
  );
};

Примечание. Для средства выбора смайликов использовался популярный компонент средства выбора смайликов с открытым исходным кодом emoji-mart

...