1. 程式人生 > >輸入框與顯示框

輸入框與顯示框

white tro content def 體驗 高度自動增加 原來 absolut 覆蓋

輸入框與顯示框

之前做一個項目的時候需要實現怎麽一個場景,有一個做題網站,需要有一個輸入框和一個顯示框。
輸入框可以給用戶輸入簡答題答案,為了讓用戶有更好的輸入體驗,需要可以支持 換行符,並且在數據的數據行數超過原來設定好的輸入框的高度時,輸入框的 高度自動增加,讓用戶能在屏幕上盡量多的看到其輸入的數據。
而之後用戶查看答案時直接把按其輸入時的排版顯示在顯示框中(顯示框的高度由要顯示的內容行數決定)

試驗一

1. 顯示框:

顯示框比較簡單,只要我們給顯示數據的 div 元素添加 css 使其能像 textarea 那樣顯示文字排版就像,具體實現如下:

<style>
.answer
{ white-space: pre-wrap; /* 使該div能顯示換行符: ? , 並且自動換行*/ word-wrap: break-word; /* textarea 默認的表現是這樣的 */ /* word-break: break-all;*/ /* 強制英語單詞換行 */ } </style> <body> <div class="answer"></div> </body>

2. 輸入框:

一般需要輸入較多文字時,我們一般會使用到 textarea 標簽,但由於使用 <textarea>

標簽無法自動在文字內容超過輸入框的高度時自動增加而是顯示滾動條,所以我們就直接不使用 textarea 了。改用 contenteditable 屬性,將一個 div 元素賦上此屬性後就可以在這個 div 中輸入文字,它表現得就像是一個 textarea 一樣,只是它在輸入內容超過其高度時高度會自增。具體實現如下:

<style>
    .input-box {
        width: 250px;
        min-height: 150px;
        border: 1px solid black;
    }
</style>

<body>
<div class="input-box" contenteditable ></div> <!-- 使改div能編輯,並且編輯的時候能 換行 和 高度自增 --> </body>

小提示:

  • 通過 e.target.innerHTML 獲取的是把換行符替代成 <div> 標簽的 html 代碼
  • 通過 e.target.innerText 獲取的是把換行符替代成 ? 符號的文本

試驗二

在試驗一的基礎上,將其和 Vue 一起使用

1. 顯示框

<template>
<div class="content">{{info}}</div>
</template>

<style>
    .content {
        white-space: pre-wrap;
        word-wrap: break-word;
        /* word-break: break-all; */
    }
</style>

2. 輸入框

<template>
    <!-- 使用 contenteditable 來使 div 可編輯 -->
    <div class="input-wrap" contenteditable @input="selectAnswer"></div> 
</template>

<script>
export default {
    data () {
        return {
        }
    },
    methods : {
        selectAnswer (e) {
            var info =  e.target.innerText     //註意是 innerText
        }   
    }
}
</script>

3. 缺點

  • 好像 IE瀏覽器不支持對 <div contenteditable > 添加監聽的 input 事件
  • innerText 的兼容性,FireFox 不支持 innerText 屬性,但是其支持 textContext 屬性,所以需要寫一個兼容的方法,需要註意的是兩者雖然相似,但是還是有點區別,innerText 會忽略行內的樣式和腳本,而 textContext 則會像返回其他文本一樣返回行內樣式和腳本代碼。

最終方案

1. 顯示框

<template>
<div class="content">{{info}}</div>
</template>

<style>
    .content {
        white-space: pre-wrap;
        word-wrap: break-word;
        /* word-break: break-all; */
    }
</style>

2. 輸入框

設置 textarea 的高度跟其父元素 div 的高度一致(height: 100%),當父元素 div 被內容撐大時,裏面的 textarea 也會跟著變大, 並設置其相對於 div 進行絕對定位,覆蓋住 div 。

復制 textarea 裏面輸入的內容到 div 裏,將其高度撐高,由於需要對內容 ( 換行、回車符等 ) 的表現跟 textarea,所以需要設置 white-space: pre-wrap word-wrap: break-word

<template>
    <dir class="answer-wrap">{{questionAnswer}}
        <!-- 註意這裏把 textarea 裏面的內容復制進來了 -->
        <textarea class="issue-answer" @input="selectAnswer($event)"></textarea>
    </dir>
</template>

<script>
export default {
    data () {
        return {
            questionAnswer: ‘‘
        }
    },
    methods : {
        selectAnswer (event) {
            var target = event.target ? event.target : event.srcElement;
            this.questionAnswer = target.value
            console.log(this.questionAnswer)
        }
    }
}
</script>

<style>
/* 統一div 和 textarea 的字體大小和 padding */
.answer-wrap, .issue-answer {
    padding: 6px;
    font-size: 16px;
}
    
.answer-wrap {
    position: relative;
        
    padding: 0 8px;
    margin: 10px 8px;
    min-height: 150px;

    white-space: pre-wrap;  /* 使該 div 的填充字體時表現出來的換行效果與 textarea 一致 */
    word-wrap: break-word;  /* 使該 div 的填充字體時表現出來的換行效果與 textarea 一致 */
    /* word-break: break-all; */
}
    
.issue-answer {
    position: absolute;
    top: 0px;
    right: 0;

    width: 100%;
    height: 100%;  /* 使 textarea 的高度跟其父元素的高度保持一致 */
        
    color: #495060;
    border: 1px solid #dedede;
    outline: none;
}
</style>

如果是使用原生 Js 寫的話也是監聽 textarea 的 input 事件然後在回調函數裏寫 div.innerHTML = textarea.value 就行

輸入框與顯示框