提交 453e0bad 编写于 作者: 璃白.'s avatar 璃白. 🌻

feat:添加高度自适应和内容长度限制

上级 8df9a059
......@@ -10,6 +10,9 @@
width: 600px !important;
margin: 40px auto;
}
body {
/* background-color: #222226; */
}
</style>
</head>
<body>
......@@ -20,7 +23,7 @@
el: "#app", // required
value: "34567567567",
themeOptions: {
dark: true,
// dark: true,
borderColor: "#dbdbdb",
borderColorActive: "#409eff",
textColor: "#303030",
......@@ -36,19 +39,29 @@
ol: true,
task: true,
table: true,
file: true,
fullScreen: true
},
zIndex: 7000,
maxLength: 600,
showWordLimit: true,
rows: "auto",
rule: /http:\/\/www\.baidu\.com/,
canPreview: true,
canAttachFile: true,
placeholder: "请输入内容",
onFocus: function(res) {
console.log(res);
},
throttle: 1000,
// onFocus: function(res) {
// console.log(res);
// },
onBlur: function(res) {
console.log(res);
},
onInput: function(res) {
console.log("input");
},
onChange: function(res) {
console.log(res);
console.log("change");
},
onSubmit: function(res) {
console.log(res);
......
此差异已折叠。
{
"name": "markdown-editor",
"description": " A open source markdown editor of csdn codechina team contributed",
"version": "0.3.1",
"version": "0.4.1",
"publisher": "guoweijia",
"scripts": {
"start": "webpack serve --mode=development",
......
......@@ -8,6 +8,16 @@
:canPreview="canPreview"
:toolsOptions="toolsOptions"
:fullScreen.sync="fullScreen"
@upload="$refs.mdUploadFile.click()"
/>
<input
ref="mdUploadFile"
class="md_upload"
type="file"
hidden
name="md-upload-file"
id="md-upload-file"
@change="upload"
/>
<markdownPreview :text="text" :html.sync="html" v-show="showPreview" />
<markdown-editor
......@@ -16,17 +26,25 @@
:fileList.sync="fileList"
:placeholder="placeholder"
:isFocus.sync="isFocus"
:throttleTime="throttle"
:fullScreen.sync="fullScreen"
:maxLength="maxLength"
:textLength.sync="textLength"
:rows="rows"
@submit="submit"
v-show="!showPreview"
/>
<markdown-footer
<div v-if="maxLength && showWordLimit" class="word_limit">
<span>{{ textLength }}</span
>/<span>{{ maxLength }}</span>
</div>
<!-- <markdown-footer
:fileList.sync="fileList"
:canAttachFile="canAttachFile"
:isFocus.sync="isFocus"
:can-attach-file="canAttachFile"
v-if="!showPreview && canAttachFile"
/>
/> -->
</div>
</template>
<script>
......@@ -55,6 +73,10 @@ export default {
type: [String, Number],
default: ""
},
throttle: {
type: Number,
default: 1000
},
canPreview: {
type: Boolean,
default: true
......@@ -62,6 +84,22 @@ export default {
toolsOptions: {
type: Object,
default: () => {}
},
rows: {
type: [Number, String],
default: ""
},
maxLength: {
type: [Number, String],
default: ""
},
showWordLimit: {
type: Boolean,
default: false
},
rule: {
type: RegExp,
default: /./
}
},
data() {
......@@ -72,6 +110,7 @@ export default {
fileList: [],
text: "",
html: "",
textLength: "",
selectionInfo: {
selectorId: "",
selectionStart: "",
......@@ -79,14 +118,20 @@ export default {
}
};
},
watch: {
html: {
immediate: true,
handler: function(val) {
this.textLength = this.text.length;
this.$emit("change", {
text: this.text,
html: this.html
});
this.$emit("input", {
text: this.text,
html: this.html
});
}
},
isFocus: {
......@@ -133,6 +178,9 @@ export default {
}
},
methods: {
upload(e) {
this.fileList = Array.from(e.target.files);
},
submit() {
this.$emit("submit", {
text: this.text,
......@@ -152,8 +200,16 @@ export default {
padding: 10px 16px;
box-sizing: border-box;
transition: border 0.3s;
position: relative;
&.active {
border: 1px solid var(--md-editor-border-color-active);
}
.word_limit {
position: absolute;
right: 10px;
bottom: 8px;
font-size: 12px;
color: var(--md-editor-text-color);
}
}
</style>
......@@ -12,8 +12,24 @@ export function getSelectionInfo(selectorId) {
};
}
// 节流
export const throttle = function(fn, wait) {
var timer = null;
return function() {
var context = this;
var args = arguments;
if (!timer) {
timer = setTimeout(function() {
fn.apply(context, args);
timer = null;
}, wait);
}
};
};
export const getPosition = function(selectorId) {
const element = document.getElementById(selectorId);
if (!element) return 0;
let cursorPos = 0;
if (document.selection) {
//IE
......@@ -38,6 +54,13 @@ export function formatText(text, selectionInfo, startStr = "", endStr = "") {
return newText;
}
export function setzIndex(index) {
document.documentElement.style.setProperty(
"--md-editor-fullScrren-zIndex",
index
);
}
// 初始化样式
export function initStyle({
dark,
......@@ -51,13 +74,13 @@ export function initStyle({
}) {
// 夜晚模式
if (dark) {
borderColor = "#b2b2b2";
borderColorActive = "#fff";
textColor = "#fff";
textColorActive = "#fff";
frameBgColor = "#343434";
codeBgColor = "#484848";
contentBgColor = "#484848";
borderColor = "#44444F";
borderColorActive = "#2998F2";
textColor = "#777888";
textColorActive = "#CCCCD8";
frameBgColor = "#222226";
codeBgColor = "#777888";
contentBgColor = "#222226";
}
if (frameBgColor) {
document.documentElement.style.setProperty(
......@@ -69,7 +92,7 @@ export function initStyle({
document.documentElement.style.setProperty(
"--md-editor-content-bg-color",
contentBgColor
);
);
}
if (codeBgColor) {
......
......@@ -6,4 +6,5 @@
--md-editor-frame-bg-color: #fff;
--md-editor-content-bg-color: #fff;
--md-editor-code-bg-color: #f3f4f5;
--md-editor-fullScrren-zIndex: 2000;
}
......@@ -3,6 +3,7 @@
<textarea
:id="id"
@change="$emit('update:text', textContent)"
@input="input"
@focus="setFocus(true)"
@blur="setFocus(false)"
@paste="pasteFile"
......@@ -10,7 +11,9 @@
@keydown.ctrl.enter.exact="submit"
v-model="textContent"
:placeholder="placeholder"
rows="10"
:maxlength="maxLength"
:rows="rows"
:style="{ height: editorHeight, overflow: autoSize ? 'hidden' : 'auto' }"
>
</textarea>
<span
......@@ -21,13 +24,21 @@
</div>
</template>
<script>
import { getSelectionInfo, getPosition } from "@/assets/js/utils";
import {
getSelectionInfo,
getPosition,
throttle as throttleFn
} from "@/assets/js/utils";
export default {
props: {
fullScreen: {
type: Boolean,
default: false
},
throttleTime: {
type: Number,
default: 1000
},
isFocus: {
type: Boolean,
default: false
......@@ -44,15 +55,25 @@ export default {
type: [String, Number],
default: ""
},
maxLength: {
type: [String, Number],
default: ""
},
rows: {
type: [String, Number],
default: ""
},
selectionInfo: {
type: Object,
default: () => {}
}
},
data() {
return {
id: new Date().getTime(),
textContent: ""
textContent: "",
editorHeight: "auto"
};
},
created() {
......@@ -64,13 +85,62 @@ export default {
handler: function(val) {
this.textContent = val;
}
},
textContent: {
immediate: true,
handler: function() {
setTimeout(() => {
if (!this.autoSize) return;
this.reSizeHeight();
}, 0);
}
}
},
beforeDestroy() {
document.removeEventListener("mouseup", this.checkSelection);
},
computed: {
emitText() {
return throttleFn(() => {
this.$emit("update:text", this.textContent);
}, this.throttleTime);
},
autoSize() {
return this.rows === "auto";
}
},
methods: {
input() {
this.$emit("update:textLength", this.textContent.length);
this.emitText();
},
reSizeHeight() {
const textEl = document.getElementById(this.id);
if (!textEl) return;
const fontSize = getComputedStyle(textEl).getPropertyValue("font-size");
const lineHeight = getComputedStyle(textEl).getPropertyValue(
"line-height"
);
const fontFamily = getComputedStyle(textEl).getPropertyValue(
"font-family"
);
const hideElId = "hdieEl" + this.id;
let hideEl = document.getElementById(hideElId);
if (!hideEl) {
hideEl = document.createElement("div");
textEl.parentNode.appendChild(hideEl);
}
hideEl.id = hideElId;
hideEl.style.fontSize = fontSize;
hideEl.style.lineHeight = lineHeight;
hideEl.style.fontFamily = fontFamily;
hideEl.innerText = this.textContent;
const contentHeight = hideEl.offsetHeight;
this.editorHeight = `${contentHeight + parseFloat(fontSize) * 1.2}px`;
textEl.parentNode.removeChild(hideEl);
},
submit() {
this.$emit("submit");
},
......@@ -108,17 +178,17 @@ export default {
<style lang="less" scoped>
.md_textarea {
position: relative;
padding: 10px 0;
padding: 14px 0;
background: var(--md-editor-content-bg-color);
border-left: 1px solid var(--md-editor-border-color);
border-right: 1px solid var(--md-editor-border-color);
// border-left: 1px solid var(--md-editor-border-color);
// border-right: 1px solid var(--md-editor-border-color);
transition: border 0.3s;
padding: 14px;
// padding: 14px;
box-sizing: border-box;
&.isFocus {
border-left: 1px solid var(--md-editor-border-color-active);
border-right: 1px solid var(--md-editor-border-color-active);
}
// &.isFocus {
// border-left: 1px solid var(--md-editor-border-color-active);
// border-right: 1px solid var(--md-editor-border-color-active);
// }
&.fullScreen {
position: fixed;
width: 100vw;
......@@ -126,23 +196,29 @@ export default {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 99;
z-index: var(--md-editor-fullScrren-zIndex);
padding: 40px 60px;
box-sizing: border-box;
textarea {
font-size: 20px;
}
}
textarea {
display: block;
width: 100%;
height: 100%;
box-sizing: border-box;
background: var(--md-editor-content-bg-color);
color: var(--md-editor-text-color);
color: var(--md-editor-text-color-active);
height: var(--md-editor-height);
resize: none;
font-family: "Menlo", "DejaVu Sans Mono", "Liberation Mono", "Consolas",
"Ubuntu Mono", "Courier New", "andale mono", "lucida console", monospace;
&::placeholder {
color: var(--md-editor-text-color);
}
}
.icon {
position: absolute;
......
......@@ -21,6 +21,7 @@
:fullScreen="fullScreen"
@setFullScreen="$emit('update:fullScreen', true)"
@updateText="updateText"
@upload="$emit('upload')"
v-for="(item, index) in toolsShow"
:key="index"
:text="text"
......@@ -55,6 +56,7 @@ export default {
type: Object,
default: () => {}
},
text: {
type: [String, Number],
default: ""
......@@ -101,9 +103,9 @@ export default {
{
name: "code",
icon: "code",
tip: "插入代码",
startStr: "`",
endStr: "`"
tip: "插入代码",
startStr: "\n```\n",
endStr: "\n```"
},
{
name: "link",
......@@ -126,6 +128,13 @@ export default {
startStr: "",
endStr: ""
},
{
name: "file",
icon: "tupian",
tip: "上传文件",
startStr: "",
endStr: ""
},
{
name: "task",
icon: "renwu",
......
......@@ -26,10 +26,6 @@ export default {
selectionInfo: {
type: Object,
default: () => {}
},
uploadPath: {
type: String,
default: ""
}
},
data() {
......@@ -55,6 +51,9 @@ export default {
this.updateText(`\n${ulNum}. `, "");
this.ulNum++;
break;
case "file":
this.$emit("upload");
break;
case "fullScreen":
this.$emit("setFullScreen", true);
break;
......@@ -80,6 +79,9 @@ export default {
&:hover {
color: var(--md-editor-text-color-active);
}
&.icon-tupian {
font-size: 24px;
}
}
}
</style>
......@@ -2,7 +2,7 @@ import Vue from "vue";
import App from "./App";
import Vtip from "vtip";
import "vtip/lib/index.min.css";
import { initStyle, isNotEmpty } from "@/assets/js/utils";
import { initStyle, setzIndex, isNotEmpty } from "@/assets/js/utils";
import "@/assets/style/global.less";
Vue.use(Vtip.directive);
......@@ -10,13 +10,20 @@ Vue.use(Vtip.directive);
function initMdEditor(obj) {
const {
el,
onChange,
onUpload,
onFocus,
onBlur,
onSubmit,
onChange = () => {},
onUpload = () => {},
onFocus = () => {},
onBlur = () => {},
onInput = () => {},
onSubmit = () => {},
placeholder,
value,
zIndex = 2000,
rule,
rows = 10,
maxLength,
showWordLimit,
throttle,
canPreview,
canAttachFile,
themeOptions,
......@@ -24,7 +31,7 @@ function initMdEditor(obj) {
} = obj;
if (!el || !document.querySelector(el)) throw new Error("请指定容器");
if (isNotEmpty(themeOptions)) initStyle(themeOptions);
if (isNotEmpty(zIndex)) setzIndex(zIndex);
new Vue({
render: h =>
h(App, {
......@@ -32,6 +39,9 @@ function initMdEditor(obj) {
change(val) {
onChange(val);
},
input(val) {
onInput(val);
},
focus(val) {
onFocus(val);
},
......@@ -50,9 +60,14 @@ function initMdEditor(obj) {
props: {
canAttachFile,
value,
rule,
rows,
throttle,
canPreview,
toolsOptions,
placeholder
placeholder,
maxLength,
showWordLimit
}
})
}).$mount(el);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册