如何使Textarea像密码字段一样

时间:2012-10-15 12:33:02

标签: javascript html

我试图让textarea看起来像一个密码字段。在webkit浏览器中,我找到了以下属性来实现它

-webkit-text-security : circle    

但它在其他浏览器中不起作用。任何跨浏览器的替代方案......?

3 个答案:

答案 0 :(得分:2)

您可以使用JS,定义变量并在其中存储textarea值,并用任何特殊字符替换textarea中的内容。您将在JS变量中拥有实际值,可用于提交表单或验证等。

为此,您可以为keydown事件编写函数。

答案 1 :(得分:1)

答案 2 :(得分:0)

可以做到,但是实现并不简单。这个想法是使用一个不可见的password=true输入元素作为textarea密码屏蔽版本的状态/代理,并使用JS在显示/隐藏时切换一个带有真实textarea的密码屏蔽(伪)文本区域。

注意事项intgrsimilar question州的评论,

不幸的是,这很快变得很难看。普通密码字段 还允许在中间进行修改,复制,剪切,拖放, 以及其他我无法想到的行为。模拟所有 这些忠实的即使可能,也不值得 麻烦。

我的实现通过使用密码屏蔽的(伪造)文本区域中的单击或箭头键以编程方式禁用文本导航,从而避免了这种复杂性。真实的textarea可以在其中导航和编辑,因此在UX方面损失很小。

在下面查看我的实现

// element handles
const inp = document.getElementById("input-el");
const fta = document.getElementById("fake-textarea-el");
const ftac = document.getElementById("fake-textarea-el-content");
const rta = document.getElementById("real-textarea-el");
const toggle = document.getElementById("pw-toggle");

// initial text element height
const initialHeightPx = fta.clientHeight + 'px';

// show/hide content flag
let hideContent = true;

// util for minimum textarea height workaround
function textWidth(text) {
  const tag = document.createElement('div');
  tag.classList.add('hidden');
  tag.style.whiteSpace = 'nowrap';
  tag.innerHTML = text;

  document.body.appendChild(tag);
  const result = tag.clientWidth;
  
  document.body.removeChild(tag);
  
  return result;
}

function setTextArea(content = '') {
  // update all text elements
  ftac.innerHTML = content.replace(/./g, '•');
  inp.value = content;
  rta.value = content;

  // workaround to use CSS height for minimum
  // textarea height
  let newHeight = initialHeightPx;
  if (textWidth(content) > rta.clientWidth) {
    rta.style.height = 'auto';
    newHeight = rta.scrollHeight + 'px';
  }
  rta.style.height = newHeight;
}

function handleInput(e) {
  const {target: {value}} = e;
  setTextArea(value);
}

inp.oninput = handleInput;
rta.oninput = handleInput;

fta.onfocus = e => {
  inp.focus();
  
  fta.classList.add('has-focus');
  ftac.classList.remove('has-selectall');
}

inp.onblur = e => {
  // deselect input contents
  inp.selectionStart = inp.selectionEnd = -1;
  
  fta.classList.remove('has-focus');
  ftac.classList.remove('has-selectall');
}

inp.onkeydown = e => {
  const {charCode, keyCode, target: {value}} = e;
  const code = keyCode || charCode;
  
  // prevent arrow keys
  if (code >= 37 && code <= 40) {
    e.preventDefault();
  }
  
  // handle ctrl/meta key combinations
  if ((e.metaKey || e.ctrlKey)) {
    switch (e.key) {
      case 'a':
        e.preventDefault();
        inp.setSelectionRange(0, inp.value.length)
        fta.classList.remove('has-focus');
        ftac.classList.add('has-selectall');
        break;
      default:
    }
  } else if (ftac.classList.contains('has-selectall')) {
    fta.classList.add('has-focus');
    ftac.classList.remove('has-selectall');
  }
}

// handle show/hide toggle
toggle.onclick = e => {
  hideContent = !hideContent;
  
  if (hideContent) {
    rta.classList.add('hidden');
    fta.classList.remove('hidden');
    toggle.innerHTML = 'Show';
  } else {
    fta.classList.add('hidden');
    rta.classList.remove('hidden');
    toggle.innerHTML = 'Hide';
  }
}
/* SETUP BEGIN */
* {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}

main {
  align-items: center;
  display: flex;
  height: 100vh;
  justify-content: center;
}

button {
  height: 24px;
  margin: 18px;
  width: 60px;
}
/* SETUP END */


#fake-textarea-el, #real-textarea-el {
  border: none; /* remove user-agent textarea border */
  box-shadow: 0 0 0 1px black;
  box-sizing: border-box;
  display: block;
  height: 24px;
  line-height: 18px;
  margin: 0;
  padding: 2px;
  resize: none;
  width: 150px;
  word-wrap: break-word;
}

#fake-textarea-el {
  height: auto;
  min-height: 24px;
}

.hidden {
  position: absolute;
  bottom: 0px;
  z-index: -1000;
  opacity: 0;
  pointer-events: none;
}

.has-selectall {
  /* default selection bg on MacOS + Chrome */
  background: #ACCEF7;
}

.cursor {
  border-right: 1px solid transparent;
  height: 1rem;
}

.has-focus .cursor {
  animation: cursorBlink 1.14s forwards infinite;
}

@keyframes cursorBlink {
  0% {
    border-color: transparent;
  }
  50% {
    border-color: transparent;
  }
  51% {
    border-color: black;
  }
  100% {
    border-color: black;
  }
}
<main>
  <input id="input-el" class="hidden" type="password" />
  <div id="fake-textarea-el" contenteditable>
    <span id="fake-textarea-el-content"></span><span class="cursor"></span>
  </div>
  <textarea id="real-textarea-el" class="hidden"></textarea>
  <button id="pw-toggle">Show</button>
</main>