提交 89f3b395 编写于 作者: 璃白.'s avatar 璃白. 🌻

feat:添加@事件

上级 549b7a90
......@@ -9,7 +9,7 @@
.md_container {
/* width: 600px !important; */
margin: 40px auto;
margin-top: 600px;
/* margin-top: 600px; */
}
body {
/* background-color: #222226; */
......@@ -86,6 +86,7 @@ void main()
"## edswgdfgdfgdfg\n**dfgdfgdfg**\n_ergdfgdfg_\n> ergergdfg\n```\nwefgdfsfdgdf\n```\n- efwefsdfsdf\n\n\nsdgfdfgdfgdfg\n\n\nedrfgdfgdfg\n\n\n\nergergergergerg\nergergergerg\n\n\nedrfgdfgdfg\n\n\n\nergergergergerg\nergergergerg\n\n\nedrfgdfgdfg\n\n\n\nergergergergerg\nergergergerg",
value:
"![img](https://img2.baidu.com/it/u=4025475678,645544065&fm=26&fmt=auto&gp=0.jpg)",
value: "",
disabled: false,
themeOptions: {
dark: false,
......@@ -166,7 +167,51 @@ void main()
setTimeout(() => {
callback(newLinks);
}, 2000);
}
},
// queryUserList: function(val, callback) {
// const list = [
// {
// id: 1,
// name: "藤原拓海",
// avatar:
// "https://img2.baidu.com/it/u=2380211986,3979961921&fm=26&fmt=auto&gp=0.jpg"
// },
// {
// id: 2,
// name: "高桥凉介",
// avatar:
// "https://img0.baidu.com/it/u=777620324,2343967729&fm=26&fmt=auto&gp=0.jpg"
// },
// {
// id: 3,
// name: "马奎斯",
// avatar:
// "https://img2.baidu.com/it/u=1297316011,1869565258&fm=26&fmt=auto&gp=0.jpg"
// },
// {
// id: 4,
// name: "王一博",
// avatar:
// "https://img2.baidu.com/it/u=298051053,3773223854&fm=26&fmt=auto&gp=0.jpg"
// },
// {
// id: 5,
// name: "王俊凯",
// avatar:
// "https://img1.baidu.com/it/u=2378425879,2273515018&fm=26&fmt=auto&gp=0.jpg"
// }
// ];
// if (!val) {
// callback(list);
// return;
// }
// callback(
// list.filter(item => {
// return item.name.includes(val);
// })
// );
// }
});
// ee.focus();
......
此差异已折叠。
......@@ -59,6 +59,7 @@
:disabled="disabled"
:show-help="showHelp"
:formatType="formatType"
:userList="userList"
:ref="'md_textarea' + id"
@tab="$refs['md_header' + id].tab()"
@submit="submit"
......@@ -66,6 +67,7 @@
@getFilteredTags="filteredTags = $event"
@updateShowHelp="showHelp = $event"
@renderLinksHtml="renderLinksHtml"
@queryUserList="queryUserList"
v-else
/>
<div v-if="maxLength && showWordLimit && !showPreview" class="word_limit">
......@@ -214,6 +216,7 @@ export default {
htmlMinHeight: 150,
showHelp: false,
textLength: "",
userList: [],
selectionInfo: {
selectorId: "",
selectionStart: "",
......@@ -228,10 +231,6 @@ export default {
html: this.html
});
}, 0);
// if(this.isMobile) {
// }
},
watch: {
focus: {
......@@ -276,16 +275,13 @@ export default {
html: {
immediate: false,
handler: function(val) {
console.log("html update");
const emitContent = {
text: this.text,
html: this.html
};
if (this.filePathRule) {
const checkResult = checktUrl(val, this.filePathRule);
emitContent.invalidList = checkResult;
console.log(checkResult);
}
emitContent.filteredTags = this.filteredTags;
this.$emit("change", emitContent);
......@@ -354,6 +350,15 @@ export default {
html: this.html
});
},
queryUserList(keyWord) {
const _this = this;
this.$emit("queryUserList", {
keyWord,
callback: function(list) {
_this.userList = list;
}
});
},
renderLinksHtml({ vDom, links }) {
new Promise((resolve, reject) => {
this.$emit("renderLinks", {
......
......@@ -157,6 +157,7 @@ export default {
padding-right: 14px;
height: 100%;
scrollbar-color: transparent transparent;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
......
<template>
<div
class="md_select_user"
:style="{ left: this.left + 'px', top: this.top + 'px' }"
>
选择用户弹窗
</div>
</template>
<script>
export default {
props: {
position: {
type: Object,
default: () => {
return {
left: 0,
top: 0
};
}
}
},
watch: {
position: {
immediate: true,
handler: function({ left, top }) {
this.left = left + 14;
this.top = top + 14;
}
}
},
data() {
return {
left: 0,
top: 0
};
}
};
</script>
<style lang="less" scoped>
.md_select_user {
position: fixed;
width: 100px;
height: 200px;
background: #fff;
border: 1px solid red;
box-shadow: 0 1px 6px rgb(0 0 0 / 10%);
border: 1px solid var(--md-editor-border-color);
border-radius: 4px;
z-index: var(--md-editor-fullScrren-zIndex);
box-sizing: border-box;
padding: 6px 8px;
margin: 0;
}
</style>
<template>
<div
class="md_select_container"
:style="{ left: this.left + 'px', top: this.top + 'px' }"
>
<ul v-show="userList.length" class="md_select_user">
<li
@click="selectUser(item)"
v-for="(item, index) in userList"
:key="index"
>
<img class="md_select_user_avatar" :src="item.avatar" />
<div class="md_select_user_info">
<div class="md_select_user_name">{{ item.name }}</div>
<div class="md_select_user_desc">最近回答过类似问题</div>
</div>
</li>
</ul>
<div v-show="userList.length" class="after"></div>
<div v-show="!userList.length" class="md_select_no_data">
轻敲空格完成输入
</div>
</div>
</template>
<script>
export default {
props: {
position: {
type: Object,
default: () => {
return {
left: 0,
top: 0
};
}
},
userList: {
type: Array,
default: () => []
}
},
watch: {
position: {
immediate: true,
handler: function({ left, top }) {
this.left = left + 14;
this.top = top + 20;
}
}
},
data() {
return {
left: 0,
top: 0
};
},
methods: {
selectUser(user) {
this.$emit("selectUser", user);
}
}
};
</script>
<style lang="less" scoped>
.md_select_container {
position: relative;
position: fixed;
background: #fff;
box-shadow: 0 1px 6px rgb(0 0 0 / 10%);
border: 1px solid var(--md-editor-border-color);
border-radius: 4px;
z-index: var(--md-editor-fullScrren-zIndex);
margin: 0;
.after {
pointer-events: none;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 28px;
background: linear-gradient(
to top,
var(--md-editor-content-bg-color),
rgba(255, 255, 255, 0)
);
}
.md_select_user {
max-height: 214px;
width: 180px;
// background: #fff;
// box-shadow: 0 1px 6px rgb(0 0 0 / 10%);
// border: 1px solid var(--md-editor-border-color);
// border-radius: 4px;
// z-index: var(--md-editor-fullScrren-zIndex);
// margin: 0;
padding: 6px 0;
box-sizing: border-box;
overflow-y: auto;
scrollbar-color: transparent transparent;
scrollbar-width: none;
margin: 0 !important;
list-style: none !important;
&::-webkit-scrollbar {
display: none;
}
&::-webkit-scrollbar-thumb {
border-radius: 1em;
background-color: rgba(50, 50, 50, 0.3);
}
&::-webkit-scrollbar-track {
border-radius: 1em;
background-color: rgba(50, 50, 50, 0);
}
li {
display: flex;
box-sizing: border-box;
padding: 6px 8px;
cursor: pointer;
&:hover {
background: #f5f7fa;
}
// & + li {
// margin-top: 10px;
// }
.md_select_user_avatar {
width: 44px;
height: 44px;
border-radius: 50%;
object-fit: cover;
margin-right: 8px;
}
.md_select_user_info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: flex-start;
.md_select_user_name {
font-size: 14px;
color: var(--md-editor-text-color-active);
}
.md_select_user_desc {
font-size: 12px;
color: var(--md-editor-helpdoc-color);
}
}
}
}
.md_select_no_data {
font-size: 12px;
padding: 4px 8px;
box-sizing: border-box;
color: var(--md-editor-helpdoc-color);
}
}
</style>
......@@ -8,11 +8,11 @@
@focus="setFocus(true)"
@blur="setFocus(false)"
@paste="pasteFile"
@keydown.enter="$emit('enter')"
@keydown.stop.50="keyup"
@keydown.enter="handleEnter"
@keydown.meta.enter.exact="submit"
@keydown.ctrl.enter.exact="submit"
@keydown.tab.prevent="$emit('tab')"
@keyup="keyup"
v-model="textContent"
:placeholder="placeholder"
:maxlength="maxLength"
......@@ -37,7 +37,12 @@
/>
</transition>
<transition name="slideup-fade">
<selectUser v-show="showSelectUser" :position="selectUserPosition" />
<selectUser
:userList="userList"
v-show="showSelectUser"
:position="selectUserPosition"
@selectUser="selectUser"
/>
</transition>
</div>
</template>
......@@ -52,7 +57,7 @@ import {
throttle as throttleFn
} from "@/assets/js/utils";
import marked from "marked";
import selectUser from "./components/select-user";
import selectUser from "./components/user-select";
import helpDoc from "./components/help-doc";
import DOMPurify from "dompurify";
export default {
......@@ -119,6 +124,10 @@ export default {
showHelp: {
type: Boolean,
default: false
},
userList: {
type: Array,
default: () => []
}
},
......@@ -128,6 +137,11 @@ export default {
editorHeight: "auto",
editorOverFlow: "auto",
showSelectUser: false,
queryInfo: {
startPosition: "",
endPosition: "",
keyWord: ""
},
selectUserPosition: { left: 0, top: 0 }
};
},
......@@ -173,6 +187,13 @@ export default {
this.reSizeTextareaHeight();
}, 0);
}
},
showSelectUser: {
handler: function(val) {
if (!val) {
this.resetQueryInfo();
}
}
}
},
beforeDestroy() {
......@@ -198,6 +219,13 @@ export default {
this.$emit("update:htmlMinHeight", height);
}, 0);
},
resetQueryInfo() {
this.queryInfo = {
startPosition: "",
endPosition: "",
keyWord: ""
};
},
transferMarkdown(val) {
marked.setOptions({
breaks: true,
......@@ -232,18 +260,48 @@ export default {
if (links.length) this.$emit("renderLinksHtml", { vDom, links });
},
input() {
if (this.showSelectUser) this.handleQueryUser();
this.$emit("update:textLength", this.textContent.length);
this.emitText();
},
selectUser(user) {
const originalText = this.textContent;
const queryInfo = this.queryInfo;
const cursorPosition = getPosition(this.id);
const username = user.name + " ";
const newText =
originalText.slice(0, queryInfo.startPosition) +
username +
originalText.slice(queryInfo.endPosition);
this.textContent = newText;
this.emitText();
this.showSelectUser = false;
this.$nextTick(() => {
const textEl = document.getElementById(this.id);
textEl.setSelectionRange(
cursorPosition + username.length,
cursorPosition + username.length
);
textEl.focus();
});
},
handleQueryUser() {
const endPosition = getPosition(this.id);
const startPosition = this.queryInfo.startPosition + 1;
const keyWord = this.textContent.slice(startPosition, endPosition);
this.queryInfo.endPosition = endPosition;
if (endPosition < startPosition || keyWord.slice(-1) === " ") {
this.showSelectUser = false;
return;
}
this.queryInfo.keyWord = keyWord;
this.$emit("queryUserList", keyWord);
},
keyup(e) {
if (e.key === "@") {
this.createSelectUserDialog();
}
// console.log(e);
if (e.code === "Space" || e.code === "Enter") {
this.showSelectUser = false;
}
},
createSelectUserDialog() {
const textEl = document.getElementById(this.id);
......@@ -283,6 +341,9 @@ export default {
};
textEl.parentNode.removeChild(hideEl);
this.showSelectUser = true;
this.queryInfo.startPosition = getPosition(this.id);
this.queryInfo.endPosition = getPosition(this.id);
this.$emit("queryUserList", this.queryInfo.keyWord);
});
},
createHideEl(type) {
......@@ -326,6 +387,18 @@ export default {
this.autoSize && !this.fullScreen && !this.height ? "hidden" : "auto";
textEl.parentNode.removeChild(hideEl);
},
handleEnter() {
if (this.showSelectUser) {
const textEl = document.getElementById(this.id);
textEl.blur();
setTimeout(() => {
textEl.focus();
// this.showSelectUser = false;
}, 0);
return;
}
this.$emit("enter");
},
submit() {
this.$emit("submit");
},
......@@ -398,6 +471,7 @@ export default {
height: var(--md-editor-height);
resize: none;
font-size: 14px;
line-height: 18px;
word-break: break-all;
font-family: "Menlo", -apple-system, SF UI Text, Arial, PingFang SC,
Hiragino Sans GB, Microsoft YaHei, WenQuanYi Micro Hei, sans-serif, SimHei,
......
......@@ -82,8 +82,7 @@ ul {
padding-top: 4px;
box-sizing: border-box;
scrollbar-color: transparent transparent;
// scrollbar-track-color: transparent;
// -ms-scrollbar-track-color: transparent;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
......
......@@ -23,6 +23,7 @@ function initMdEditor(obj) {
onInput = () => {},
onSubmit = () => {},
renderLinks = () => {},
queryUserList = () => {},
placeholder,
value,
disabled,
......@@ -113,6 +114,58 @@ function initMdEditor(obj) {
renderLinks(links, function(res) {
callback(res);
});
},
queryUserList({ keyWord, callback }) {
// queryUserList(keyWord, function(res) {
const list = [
{
id: 1,
name: "藤原拓海",
avatar:
"https://img2.baidu.com/it/u=2380211986,3979961921&fm=26&fmt=auto&gp=0.jpg"
},
{
id: 2,
name: "高桥凉介",
avatar:
"https://img0.baidu.com/it/u=777620324,2343967729&fm=26&fmt=auto&gp=0.jpg"
},
{
id: 3,
name: "马奎斯",
avatar:
"https://img2.baidu.com/it/u=1297316011,1869565258&fm=26&fmt=auto&gp=0.jpg"
},
{
id: 4,
name: "王一博",
avatar:
"https://img2.baidu.com/it/u=298051053,3773223854&fm=26&fmt=auto&gp=0.jpg"
},
{
id: 5,
name: "王俊凯",
avatar:
"https://img1.baidu.com/it/u=2378425879,2273515018&fm=26&fmt=auto&gp=0.jpg"
},
{
id: 6,
name: "易烊千玺",
avatar:
"https://img0.baidu.com/it/u=2227200088,1939721201&fm=26&fmt=auto&gp=0.jpg"
}
];
if (!keyWord) {
callback(list);
return;
}
callback(
list.filter(item => {
return item.name.includes(keyWord);
})
);
// });
}
};
this.vEl = new Vue({
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册