javascript - 如何在 Textarea 元素中显示数组

标签 javascript html reactjs

我想在文本区域中显示非常困难的数组和困难的数组。现在,它显示在文本区域下,因为我不知道如何在文本区域中显示它。用户给出输入,服务器响应来自用户输入的困难和非常困难的句子。难句有黄色背景,非常难句有红色背景。目前,只有分别带有黄色和红色背景的难句和非常难的句子显示在文本区域下方,而不是整个内容,但我认为这不直观,因为用户必须再次在文本区域中搜索句子句子的确切位置。因此,我希望整个内容显示在文本区域本身中,并以黄色和红色背景突出显示困难和非常困难的句子。

现在我的代码看起来像这样:

state={
    hardArray: [],
    vhardArray: []
}

  performHard = async () => {
    const { enteredText } = this.state;
    const body = { text: enteredText };
    const stringifiedBody = JSON.stringify(body);
    const options = {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Accept: "application/json"
      },
      body: stringifiedBody
    };
    const url = "api/same";

    try {
      const response = await fetch(url, options);
      const result = await response.json();
      this.setState(prevState => ({
        hardArray: [...prevState.hardArray, ...result.hard]
      }));
    } catch (error) {
      console.error("error");
    }
  };
  performVHard = async () => {
    const { enteredText } = this.state;
    const body = { text: enteredText };
    const stringifiedBody = JSON.stringify(body);
    const options = {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Accept: "application/json"
      },
      body: stringifiedBody
    };
    const url ="api/same";
    try {
      const response = await fetch(url, options);
      const result = await response.json();
      this.setState(prevState => ({
        vhardArray: [...prevState.vhardArray, ...result.very_hard]
      }));
    } catch (error) {
      console.error("error");
    }
  };
  performAnalysis = () => {
    this.performHard();
    this.performVHard();
  };

  <textarea
    name="enteredText"       
    className="textareaclass"
    placeholder="Enter your text here"
    onChange={this.handleChange}
    value={enteredText}
    ></textarea>
  <Button 
   className="rectangle-3" 
   onClick={this.performAnalysis}>Analyse
   </Button>
  <div>
   {this.state.hardArray.map((word, i) => (
     <span className="hardColor">{word}</span>
   ))}
   {this.state.vhardArray.map((word, i) => (
     <span className="vhardColor">{word}</span>
   ))}
  </div>

编辑:这就是我从服务器接收响应的方式

{
  "hard": [
    "It's the possibility of having a dream come true that makes life interesting",
    "I cannot fix on the hour, or the spot, or the look or the words, which laid the foundation.",
  ]
 "very_hard": [
    “He stepped down, trying not to look long at her, as if she were the sun, yet he saw her, like the sun, even 
     without looking.”
  ]
}

我想在用户编写内容的同一个文本区域中显示所有文本,而不是在浏览器中的其他任何地方显示,因为这会让所有内容看起来很丑。

最佳答案

你只能给一个textarea一种背景颜色,但是你可以让它透明并把东西放在它后面来添加一些颜色,是的,这完全是一个黑客,你需要摆弄大小和空白行将文本向下移动一点 - 我将把这个练习留给你。

这也没有显示如何将您的值放入 textarea 中,但这可能是简单的 JavaScript/react 代码。

我用一些函数对此进行了更改,以说明您可以简单地在 textarea 中添加/删除空白行以匹配背景颜色的高度 - 可能需要调整背景以匹配此情况溢出尺寸,或者您可以调整背景以使其更小以适应颜色。

我将让您决定哪个是更好的选择,我使用 "|""||" 作为行/节分隔符,就像以前一样位于文本区域并进行编辑后,您将需要类似的内容。

我现在有时间来增强这一点,但应该为这种没有明确标准解决方案的边缘情况提供一个起点。

.message {
  width: 300px;
  height: 150px;
  display: block;
  position: absolute;
}

textarea.format-custom,
.custom-underlay,
.underlay {
  margin: 0;
  box-sizing: border-box;
  vertical-align: top;
  display: block;
  position: absolute;
  border: lime solid 1px;
}

textarea.format-custom {
  width: 100%;
  height: 100%;
  background: transparent;
  resize: none;
  display: block;
}

.underlay {
  width: 100%;
  height: 100%;
  background: transparent;
  display: block;
  z-index: -1;
}

.custom-underlay {
  width: 100%;
  height: 50%;
  margin: 0;
  box-sizing: border-box;
  vertical-align: top;
}

.custom-underlay.top {
  background-color: #FFDDDD;
  top: 0;
  left: 0;
}

.custom-underlay.bottom {
  background-color: #DDDDFF;
  top: 50%;
  left: 0;
}
<div class="message">
  <label for="msg">Your message:</label>
  <textarea id="msg" name="user_message" class="format-custom">howdy, I am here
  
  
  
  
bottom of here</textarea>
  <div class="underlay">
    <div class="custom-underlay top"></div>
    <div class="custom-underlay bottom"></div>
  </div>
</div>

问题的替代想法,将文本放在 div 的后面:

'use strict';
// borrowed code from https://stackoverflow.com/a/17590149/125981
// makeClass - By Hubert Kauker (MIT Licensed)
// original by John Resig (MIT Licensed).
var makeClass = (function(Void) {
  return function() {
    var constructor = function() {
      var init = constructor.prototype.init,
        hasInitMethod = (typeof init == "function"),
        instance;
      if (this instanceof constructor) {
        if (hasInitMethod) init.apply(this, arguments);
      } else {
        Void.prototype = constructor.prototype;
        instance = new Void();
        if (hasInitMethod) init.apply(instance, arguments);
        return instance;
      }
    };
    return constructor;
  };
})(function() {});

//make a class MyApp using above
var MyApp = makeClass();

// create MyApp functional part using the init:
MyApp.prototype.init = function(myItem, showmeClass = "showme", separator = "|", groupSeparator = "||") {
  let eventChangeName = "change";
  let textElement = document.getElementById(myItem);
  let showme = textElement.closest(".container").getElementsByClassName(showmeClass)[0];
  let lineSep = "|\n";
  let myData = {
    hard: [],
    very_hard: []
  };
  this.sentData = {
    hard: [],
    very_hard: []
  };

  //so we can tell the lines
  function getStyle(elId, styleProp) {
    var x = document.getElementById(elId);
    let y = {};
    if (x.currentStyle) {
      y = x.currentStyle[styleProp];
    } else if (window.getComputedStyle) {
      y = document.defaultView.getComputedStyle(x, null).getPropertyValue(styleProp);
    }
    return y;
  }

  function getTextareaThings(myTextarea) {
    let taComputedStyles = window.getComputedStyle(myTextarea);
    return {
      height: myTextarea.style.height,
      rows: myTextarea.rows,
      clientHeight: myTextarea.clientHeight,
      lineHeight: taComputedStyles.getPropertyValue('line-height'),
      font: taComputedStyles.getPropertyValue('font-size')
    };
  }

  function getLinesInString(myString) {
    /* new line things: /r old Mac, /cr/lf some, /n some
     all the "new line": regex: /\r\n|\n|\r/gm
     above reduced regex: g and m are for global and multiline flags */
    let nl = /[\r\n]+/gm;
    let lines = [];
    lines = myString.split(nl);
    return lines;
  }

  function splitGroupString(myString, separator) {
    let strings = [];
    strings = myString.split(separator);
    return strings;
  }

  function getGroupsInString(myString) {
    return splitGroupString(myString, groupSeparator);
  }

  function getGroupItemsInString(myString) {
    return splitGroupString(myString, separator);
  }

  function getCurrentValue() {
    return textElement.value;
  }

  function addNewLines(text, count) {
    let newLine = "\n";
    return text + newLine.repeat(count);
  }
  // make stuff obvious
  function onFocusTextareaValue(event) {
    showForDebug(event);
  }

  function onChangeTextareaValue(event) {
    if (event.type == eventChangeName) {
      event.stopPropagation();
      event.stopImmediatePropagation();
    }
    showForDebug(event);
  }

  function showForDebug(event) {
    let what = "Event: " + event.type;
    let b = "<br />";
    let tat = getTextareaThings(event.target);
    let v = getCurrentValue().replace(what, "");
    showme.innerHTML = what + b + ": lines:" + getLinesInString(v).length + b + v;
  }

  function getStringLineCount(arr) {
    arr.length;
  }

  function getGroupItems() {
    let groups = getGroupsInString(getCurrentValue());
    let groupItems = {
      count: groups.length, // how many groups, two in the definition (top/bottom)
      groups: []
    };
    groups.forEach(function(group, index, groupsArr) {
      let items = getGroupItemsInString(group);
      // determine how to define "group name", I use a string and the index here
      let gname = "group" + index;
      let g = {
        itemCount: items.length // number in this group
      };
      g[gname] = {
        items: []
      };
      items.forEach(function(item, itemindex, itemsArr) {
        let itemName = "item" + itemindex;
        let itemobj = {};
        itemobj[itemName] = {
          items: item
        };
        g[gname].items.push(itemobj);
      });
      groupItems.groups.push(g);
    });
    return groupItems;
  }
  // setup events
  textElement.addEventListener(eventChangeName, onChangeTextareaValue, false);
  textElement.addEventListener("focus", onFocusTextareaValue, false);
  this.getGeometry = function() {
    let geometry = {};
    let element = textElement;
    let rect = element.getBoundingClientRect();
    geometry.top = rect.top;
    geometry.right = rect.right;
    geometry.bottom = rect.bottom;
    geometry.left = rect.left;
    geometry.offsetHeight = element.offsetHeight;
    geometry.rows = element.rows;
    geometry.clientHeight = element.clientHeight;
    geometry.fontSize = this.getStyleProperty("font-size");
    geometry.lineCount = this.getLines().length;
    geometry.lineHeight = this.getLineHeight();
    geometry.height = geometry.bottom - geometry.top;
    geometry.width = geometry.right - geometry.left;
    console.log("Geometry:",geometry);
  };
  
  this.getMetrics = function() {
    let fSize = this.getStyleProperty("font-size");
    let lineCount = this.getLines().length;
    let lineHeight = this.getLineHeight();
    let yh = lineHeight / lineCount;

    let yfhPixel = parseInt(fSize, 10);
    let yLineY = yh * yfhPixel;
    console.log("LH:", lineHeight, "font:", fSize, "Lines:", lineCount, "lineHeight:", lineHeight, "yh:", yh, "yfPixel:", yfhPixel, "yLineY:", yLineY);
  };

  this.getStyleProperty = function(propertyName) {
    return getStyle(textElement.id, propertyName)
  };

  // public functions and objects
  this.getLines = function() {
    return getLinesInString(getCurrentValue());
  };
  this.getGroups = function() {
    return getGroupsInString(getCurrentValue());
  };
  this.setText = function(content) {
    if (!content) {
      content = this.sentData;
    }

    let hard = content.hard.join(lineSep);
    let veryHard = content.very_hard.join(lineSep);
    this.textElement.value = hard.concat("|" + lineSep, veryHard);
  };
  this.getLineHeight = function(element) {
    if (!element) {
      element = textElement;
    }
    let temp = document.createElement(element.nodeName);
    temp.setAttribute("style", "margin:0px;padding:0px;font-family:" + element.style.fontFamily + ";font-size:" + element.style.fontSize);
    temp.innerHTML = "test";
    temp = element.parentNode.appendChild(temp);
    let lineHeight = temp.clientHeight;
    temp.parentNode.removeChild(temp);
    return lineHeight;
  };

  this.getGroupItems = function() {
    return getGroupItems();
  };
  this.textElement = textElement;
  this.showme = showme;
};
let sentData = {
  hard: [
    "It's the possibility of having a dream come true that makes life interesting",
    "I cannot fix on the hour, or the spot, or the look or the words, which laid the foundation."
  ],
  very_hard: ["He stepped down, trying not to look long at her, as if she were the sun, yet he saw her, like the sun, even without looking."]
};

// create instances and use our app, pass the id
var containerApp = MyApp("textThing"); //default last three parameters

containerApp.sentData = sentData;
containerApp.setText();
let groups = containerApp.getGroups();
let groupItems = containerApp.getGroupItems();
containerApp.getMetrics();
containerApp.getGeometry();


// create instances and use our app, pass the id
var containerApp2 = MyApp("msgTwo", "showme", "|", "||");

//console.log("Second One Lines:", containerApp2.getLines().length);
//containerApp2.getMetrics();
//containerApp2.getGeometry();
.page-container {
  display: flex;
  /* center and stack the containers*/
  justify-content: center;
  flex-direction: column;
  align-items: center;
  font-size: 62.5%;
}

.container {
  border: solid 1px black;
}

.container-block {
  border: 2px dashed #AAAAAA;
}

.container-items {
  width: 500px;
  position: relative;
}

.container-items .format-custom,
.container-items label {
  width: 100%;
}

.container-items .format-custom {
  height: 10em
}

.message-hr {
  border: 1px solid blue;
  background-color: blue;
  height: 0.05em;
  width: 450px;
  align-items: center;
  margin: 0.5em;
}

.showme {
  border: dotted 2px dodgerblue;
  background-color: #EEEEEE;
  padding: 1em;
}

textarea.format-custom,
.custom-underlay,
.underlay {
  margin: 0;
  box-sizing: border-box;
  vertical-align: top;
  display: block;
  border: lime solid 1px;
}

textarea.format-custom {
  width: 100%;
  height: 3em;
  background: transparent;
  resize: none;
  border: red solid 1px;
  padding: 0.5em;
}

.underlay {
  border: 1px solid #fff;
  width: 100%;
  height: 100%;
  background: transparent;
  top: 1em;
  left: 0;
  display: block;
  z-index: -1;
  position: absolute;
}

.custom-underlay {
  width: 100%;
  height: 50%;
  margin: 0;
  box-sizing: border-box;
  vertical-align: top;
  position: absolute;
}

.custom-underlay.top {
  background-color: #FFFF00;
  top: 0;
  left: 0;
}

.custom-underlay.bottom {
  background-color: #FFAAAA;
  top: 50%;
  left: 0;
}
<div class="page-container">
  <div class="container">
    <div class="container-block">
      <div class="container-items">
        <label for="textThing">Your message:</label>
        <textarea id="textThing" name="textThing" class="format-custom">howdy, I am here|another one | cheese burgers
fries and a drink   
|| 
bottom of here| bottom second</textarea>
        <div class="underlay">
          <div class="custom-underlay top"></div>
          <div class="custom-underlay bottom"></div>
        </div>
      </div>
    </div>
    <div class="showme">xxxone</div>
  </div>
  <div class="container">
    <div class="container-block">
      <div class="message-hr container-items">
        &nbsp;</div>
    </div>
  </div>
  <div class="container">
    <div class="container-block">
      <div class="container-items">
        <label for="msgTwo">Second message:</label>
        <textarea id="msgTwo" name="msgTwo" class="format-custom">Not the same|Nxxt one 
  
  
  
  
  
  
  
 || 
bottom of next</textarea>
        <div class="underlay">
          <div class="custom-underlay top"></div>
          <div class="custom-underlay bottom"></div>
        </div>
      </div>
    </div>
    <div class="showme">xxxtwo</div>
  </div>
</div>

关于javascript - 如何在 Textarea 元素中显示数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59336105/

相关文章:

javascript - 用于 cordova 插件的 Typescript 到 Javascript

javascript - 通过 Chrome 的开发工具编辑资源时,有没有办法监视 keyup 事件?

css - 从 html4 迁移到 html5

javascript - 为什么React组件无限更新

reactjs - 无法使用 npx create-react-app 创建新的 React 应用程序

node.js - 将服务器端 axios 请求的响应发送到 React/Redux 应用程序

javascript - 我可以关闭javascript代码中的确认框吗

javascript - Bootstrap 3 单选按钮正确的语法

html - Css: 不能改变 <li> 的大小

java - 正则表达式在 <a> 之前添加 <span> 标签