123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- <!-- -->
- <template>
- <div class="warpper">
- <div class="write-box" id="container">
- <!-- <div @click="onConfirm">确定</div> -->
- <!-- -->
- <div class="content" id="content" :style="`height:${inputHeight}px;`">
- <!-- <div contenteditable v-html="text" :style="`height:${lineCount * 40}px;`" @keydown="hanlderWrite($event)" id="write-info"></div> -->
- <textarea maxLength="1000" :style="`height:${lineCount * 40}px;`" @paste="onPaste" @keydown="hanlderWrite($event)" id="write-info" v-model="inputText"> </textarea>
- <div id="msg" class="msg-box">{{ inputText }}</div>
- <div class="item" :style="`top:${index * 40}px;`" v-for="(i, index) in lineCount"></div>
- </div>
- </div>
- </div>
- </template>
- <script setup>
- import { reactive, ref, toRefs, onBeforeMount, computed, onMounted, nextTick, defineEmits, defineProps } from "vue";
- const props = defineProps({
- text: {
- type: String,
- default: "",
- },
- textIndex: {
- type: Number,
- default: 0,
- },
- });
- const emits = defineEmits(["onTextConfirm", "onTextChange"]);
- const inputText = ref("");
- const lineCount = ref(1);
- const inputHeight = ref(0);
- const getLineCount = () => {
- let containerH = document.getElementById("container").clientHeight;
- let count = Math.floor(containerH / 40);
- lineCount.value = count;
- inputHeight.value = count * 40;
- // textAreaHeight.value = lineCount.value * 40;
- };
- const onConfirm = () => {
- let page = 1;
- if (msgHeight.value < 400) {
- page = 1;
- } else {
- page = page + Math.ceil((msgHeight.value - 400) / 1080);
- }
- emits("onTextConfirm", { text: inputText.value, msgHeight: msgHeight.value, page });
- };
- const msgHeight = ref(40);
- defineExpose({ onConfirm });
- const hanlderWrite = (e) => {
- let msgH = document.getElementById("msg").clientHeight;
- msgHeight.value = msgH;
- let msgCount = Math.floor(msgH / 40);
- let containerH = document.getElementById("container").clientHeight;
- let containerCount = Math.floor(containerH / 40);
- // text.value = e.target.innerHTML;
- if (msgCount > containerCount) {
- if (e && e.keyCode == 13) {
- msgCount++;
- }
- lineCount.value = msgCount;
- } else {
- lineCount.value = containerCount;
- }
- emits("onTextChange", { text: inputText.value });
- // textAreaHeight.value = msgH;
- };
- const onPaste = (e) => {
- setTimeout(() => {
- // let msgH = document.getElementById('msg').clientHeight;
- hanlderWrite(e);
- let content = document.getElementById("content");
- content.scrollTo(0, 9999999);
- }, 100);
- };
- const setFocusAt = (focusIndex) => {
- let txtarea = document.getElementById("write-info");
- setCaretPosition(txtarea, focusIndex);
- };
- //设置光标位置
- const setCaretPosition = (ctrl, pos) => {
- if (ctrl.setSelectionRange) {
- ctrl.focus();
- ctrl.setSelectionRange(pos, pos);
- } else if (ctrl.createTextRange) {
- var range = ctrl.createTextRange();
- range.collapse(true);
- range.moveEnd("character", pos);
- range.moveStart("character", pos);
- range.select();
- }
- nextTick(() => {
- getSelectionDistance();
- });
- };
- // 获取 textarea 元素
- const getSelectionDistance = () => {
- var textarea = document.getElementById("write-info");
- // // 获取 textarea 的样式属性
- var textareaStyle = getComputedStyle(textarea);
- // // 计算光标位置距离顶部的距离
- var lineHeight = parseInt(textareaStyle.lineHeight, 10); // 获取行高,如果没有设置,会返回默认值
- // 获取光标的起始位置
- var cursorPosition = textarea.selectionStart;
- // 获取 textarea 内容
- var textareaValue = textarea.value;
- // 将内容分割成行
- var lines = textareaValue.split("\n");
- // 计算光标所在的行数1
- var cursorLine = 1; // 初始化行数为1
- for (var i = 0; i < lines.length; i++) {
- if (cursorPosition <= lines[i].length) {
- break; // 找到光标所在的行后退出循环
- }
- cursorPosition -= lines[i].length + 1; // 加1是为了包括换行符
- cursorLine++;
- }
- let scrollBox = document.getElementById("content");
- let scrollHeight = cursorLine * lineHeight;
- let scrollBoxHeight = scrollBox.offsetHeight;
- if (scrollHeight > scrollBoxHeight) {
- console.log("光标所在的行数:", cursorLine);
- scrollBox.scrollTo(0, scrollHeight - scrollBoxHeight);
- }
- };
- onMounted(async () => {
- await nextTick();
- getLineCount();
- inputText.value = props.text;
- setTimeout(() => {
- hanlderWrite();
- if (props.text && props.textIndex) {
- // console.error(props.textIndex);
- setFocusAt(props.textIndex);
- }
- }, 0);
- nextTick(() => {
- let scrollBox = document.getElementById("content");
- scrollBox.addEventListener("scroll", (data) => {
- // console.error(data);
- });
- });
- });
- </script>
- <style lang="scss" scoped>
- .warpper {
- padding: 70px 50px 30px;
- }
- .write-box {
- width: 100%;
- height: calc(100vh - 100px);
- font-size: 24px;
- color: #000;
- overflow: hidden;
- font-family: SimSun-Regular, SimSun;
- .content {
- overflow-y: auto;
- overflow-x: hidden;
- padding-bottom: 5px;
- position: relative;
- .item {
- width: 100%;
- height: 40px;
- border-bottom: 1px solid #000;
- box-sizing: border-box;
- position: absolute;
- left: 0;
- }
- #write-info {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- line-height: 40px;
- outline: none;
- resize: none;
- z-index: 2;
- overflow: hidden;
- font-size: 24px;
- font-family: SimSun-Regular, SimSun;
- }
- .msg-box {
- min-height: 40px;
- white-space: pre-wrap;
- opacity: 0;
- position: absolute;
- width: 100%;
- line-height: 40px;
- z-index: 1;
- }
- }
- }
- </style>
|