ly-markdown.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. <template>
  2. <view>
  3. <view>
  4. <view class="toolbar">
  5. <view class="iconfont icon-bold" @click="toolBarClick('bold')"></view>
  6. <view class="iconfont icon-italic" @click="toolBarClick('italic')"></view>
  7. <view class="iconfont icon-xiahuaxian1" @click="toolBarClick('header')"></view>
  8. <view class="iconfont icon-underline" @click="toolBarClick('underline')"></view>
  9. <view class="iconfont icon-strike" @click="toolBarClick('strike')"></view>
  10. <view class="iconfont icon-sup" @click="toolBarClick('sup')"></view>
  11. <view class="iconfont icon-sub" @click="toolBarClick('sub')"></view>
  12. <view class="iconfont icon-alignleft" @click="toolBarClick('alignleft')"></view>
  13. <view class="iconfont icon-aligncenter" @click="toolBarClick('aligncenter')"></view>
  14. <view class="iconfont icon-alignright" @click="toolBarClick('alignright')"></view>
  15. <view class="iconfont icon-link" @click="toolBarClick('link')"></view>
  16. <view class="iconfont icon-image" @click="toolBarClick('imgage')"></view>
  17. <view class="iconfont icon-code" @click="toolBarClick('code')"></view>
  18. <view class="iconfont icon-table" @click="toolBarClick('table')"></view>
  19. <view class="iconfont icon-qingkong" @click="toolBarClick('clear')"></view>
  20. </view>
  21. <view class="input-content">
  22. <textarea auto-height maxlength="-1" v-model="textareaDataSync" @blur="getCursor"></textarea>
  23. </view>
  24. </view>
  25. <view class="preview" v-if="showPreview && textareaHtmlSync">
  26. <scroll-view scroll-y :style="'height:'+screenHeight/2.5+'px;padding:10px;box-sizing: border-box;'">
  27. <uParse :content="textareaHtmlSync" @preview="preview" @navigate="navigate" />
  28. </scroll-view>
  29. </view>
  30. </view>
  31. </template>
  32. <script>
  33. import marked from '../marked'
  34. import uParse from '../uParse/src/wxParse.vue'
  35. export default {
  36. name: "ly-markdown",
  37. components: {
  38. uParse
  39. },
  40. data: function() {
  41. return {
  42. screenHeight: 0,
  43. cursor: 0,
  44. textareaDataSync: '',
  45. textareaHtmlSync: ''
  46. }
  47. },
  48. props: {
  49. textareaData: {
  50. type: String,
  51. default: ''
  52. },
  53. textareaHtml: {
  54. type: String,
  55. default: ''
  56. },
  57. showPreview: {
  58. type: Boolean,
  59. default: false
  60. }
  61. },
  62. methods: {
  63. preview(src, e) {
  64. uni.previewImage({
  65. urls: src,
  66. })
  67. },
  68. navigate(href, e) {
  69. // 如允许点击超链接跳转,则应该打开一个新页面,并传入href,由新页面内嵌webview组件负责显示该链接内容
  70. // #ifdef APP-PLUS
  71. plus.runtime.openURL(href)
  72. // #endif
  73. // #ifdef MP-WEIXIN
  74. uni.setClipboardData({
  75. data: href,
  76. success: function() {
  77. uni.showModal({
  78. content: "网址已复制,请在浏览器中粘贴打开",
  79. showCancel: false
  80. })
  81. }
  82. })
  83. // #endif
  84. },
  85. toolBarClick(type) {
  86. if (type == 'bold') {
  87. this.textareaDataSync += "**粗体文字** "
  88. } else if (type == "italic") {
  89. this.textareaDataSync += "*斜体* "
  90. } else if (type == "header") {
  91. uni.showActionSheet({
  92. itemList: ["标题1", "标题2", "标题3", "标题4", "标题5", "标题6"],
  93. success: res => {
  94. switch (res.tapIndex) {
  95. case 0:
  96. this.textareaDataSync += "# 标题1\r";
  97. return;
  98. case 1:
  99. this.textareaDataSync += "## 标题2\r";
  100. return;
  101. case 2:
  102. this.textareaDataSync += "### 标题3\r";
  103. return;
  104. case 3:
  105. this.textareaDataSync += "#### 标题4\r";
  106. return;
  107. case 4:
  108. this.textareaDataSync += "##### 标题5\r";
  109. return;
  110. case 5:
  111. this.textareaDataSync += "###### 标题6\r";
  112. return;
  113. }
  114. }
  115. })
  116. } else if (type == "underline") {
  117. this.textareaDataSync += "++下划线++ "
  118. } else if (type == "strike") {
  119. this.textareaDataSync += "~~中划线~~ "
  120. } else if (type == "sup") {
  121. this.textareaDataSync += "^上角标^ "
  122. } else if (type == "sub") {
  123. this.textareaDataSync += "~下角标~ "
  124. } else if (type == "alignleft") {
  125. this.textareaDataSync += "\n::: hljs-left\n\n左对齐\n\n:::\n"
  126. } else if (type == "aligncenter") {
  127. this.textareaDataSync += "\n::: hljs-center\n\n居中对齐\n\n:::\n"
  128. } else if (type == "alignright") {
  129. this.textareaDataSync += "\n::: hljs-right\n\n\n\n右对齐\n\n:::\n"
  130. } else if (type == "link") {
  131. this.textareaDataSync += "[在此输入网址描述](在此输入网址) "
  132. } else if (type == "imgage") {
  133. this.textareaDataSync += "![](在此输入图片地址) "
  134. } else if (type == "code") {
  135. this.textareaDataSync += "\n``` 代码块 \n\n```\n"
  136. } else if (type == "table") {
  137. this.textareaDataSync += "\n|列1|列2|列3|\n|-|-|-|\n|单元格1|单元格2|单元格3|\n"
  138. } else if (type == "clear") {
  139. uni.showModal({
  140. title: "提示",
  141. content: "确定清空?",
  142. success: res => {
  143. if (res.confirm) {
  144. this.textareaDataSync = "";
  145. }
  146. }
  147. })
  148. }
  149. },
  150. getCursor(e) {
  151. //安卓失去焦点获取不到cursor位置,暂不使用
  152. //this.cursor = e.detail.cursor;
  153. }
  154. },
  155. watch: {
  156. "textareaDataSync": function(newValue, oldValue) {
  157. this.textareaHtmlSync = marked(newValue)
  158. this.$emit('update:textareaData', newValue)
  159. this.$emit('update:textareaHtml', this.textareaHtmlSync)
  160. }
  161. },
  162. created() {
  163. this.textareaDataSync = this.textareaData;
  164. this.textareaHtmlSync = this.textareaHtml;
  165. },
  166. mounted() {
  167. uni.getSystemInfo({
  168. success: res => {
  169. this.screenHeight = res.screenHeight
  170. }
  171. })
  172. }
  173. }
  174. </script>
  175. <style>
  176. @import './markdown.css';
  177. @import url("../uParse/src/wxParse.css");
  178. .input-content {
  179. width: 100%;
  180. }
  181. .input-content textarea {
  182. padding: 16upx 25upx 15upx 25upx;
  183. font-size: 30upx;
  184. min-height: 500upx;
  185. line-height: 1.5;
  186. }
  187. .preview {
  188. border-top: 1upx solid #e0e0e0;
  189. width: 100%;
  190. }
  191. .toolbar {
  192. width: 100%;
  193. border: none;
  194. box-shadow: 0 0upx 4upx rgba(0, 0, 0, 0.157), 0 0upx 4upx rgba(0, 0, 0, 0.227);
  195. }
  196. .toolbar .iconfont {
  197. display: inline-block;
  198. cursor: pointer;
  199. height: 61.6upx;
  200. width: 61.6upx;
  201. margin: 13upx 0 11upx 0upx;
  202. font-size: 33upx;
  203. padding: 10upx 13upx 11upx 8upx;
  204. color: #757575;
  205. border-radius: 11upx;
  206. text-align: center;
  207. background: none;
  208. border: none;
  209. outline: none;
  210. line-height: 2.2;
  211. vertical-align: middle;
  212. }
  213. .input-content {
  214. min-height: ;
  215. }
  216. </style>