demo-block.vue 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. <template>
  2. <div
  3. class="demo-block"
  4. :class="[blockClass, { 'hover': hovering }]"
  5. @mouseenter="hovering = true"
  6. @mouseleave="hovering = false">
  7. <slot name="source"></slot>
  8. <div class="meta">
  9. <div class="description">
  10. <slot></slot>
  11. <el-tooltip effect="dark" :content="langConfig['tooltip-text']" placement="right">
  12. <el-button size="small" type="primary" @click="goJsfiddle">{{ langConfig['button-text'] }}</el-button>
  13. </el-tooltip>
  14. </div>
  15. <slot name="highlight"></slot>
  16. </div>
  17. <div class="demo-block-control" @click="isExpanded = !isExpanded">
  18. <transition name="arrow-slide">
  19. <i :class="[iconClass, { 'hovering': hovering }]"></i>
  20. </transition>
  21. <transition name="text-slide">
  22. <span v-show="hovering">{{ controlText }}</span>
  23. </transition>
  24. </div>
  25. </div>
  26. </template>
  27. <style>
  28. .demo-block {
  29. border: solid 1px #eaeefb;
  30. border-radius: 4px;
  31. transition: .2s;
  32. &.hover {
  33. box-shadow: 0 0 8px 0 rgba(232, 237, 250, .6), 0 2px 4px 0 rgba(232, 237, 250, .5);
  34. }
  35. code {
  36. font-family: Menlo, Monaco, Consolas, Courier, monospace;
  37. }
  38. .demo-button {
  39. float: right;
  40. }
  41. .source {
  42. padding: 24px;
  43. }
  44. .meta {
  45. background-color: #f9fafc;
  46. border-top: solid 1px #eaeefb;
  47. clear: both;
  48. overflow: hidden;
  49. height: 0;
  50. transition: height .2s;
  51. }
  52. .description {
  53. padding: 18px 24px;
  54. width: 40%;
  55. box-sizing: border-box;
  56. border-left: solid 1px #eaeefb;
  57. float: right;
  58. font-size: 14px;
  59. line-height: 1.8;
  60. color: #5e6d82;
  61. word-break: break-word;
  62. p {
  63. margin: 0 0 12px;
  64. line-height: 1.8;
  65. }
  66. code {
  67. color: #5e6d82;
  68. background-color: #e6effb;
  69. margin: 0 4px;
  70. display: inline-block;
  71. padding: 1px 5px;
  72. font-size: 12px;
  73. border-radius: 3px;
  74. height: 18px;
  75. line-height: 18px;
  76. }
  77. }
  78. .highlight {
  79. width: 60%;
  80. border-right: solid 1px #eaeefb;
  81. pre {
  82. margin: 0;
  83. }
  84. code.hljs {
  85. margin: 0;
  86. border: none;
  87. max-height: none;
  88. border-radius: 0;
  89. &::before {
  90. content: none;
  91. }
  92. }
  93. }
  94. .demo-block-control {
  95. border-top: solid 1px #eaeefb;
  96. height: 36px;
  97. box-sizing: border-box;
  98. background-color: #fff;
  99. border-bottom-left-radius: 4px;
  100. border-bottom-right-radius: 4px;
  101. text-align: center;
  102. margin-top: -1px;
  103. color: #d3dce6;
  104. cursor: pointer;
  105. transition: .2s;
  106. position: relative;
  107. i {
  108. font-size: 12px;
  109. line-height: 36px;
  110. transition: .3s;
  111. &.hovering {
  112. transform: translateX(-40px);
  113. }
  114. }
  115. span {
  116. position: absolute;
  117. transform: translateX(-30px);
  118. font-size: 14px;
  119. line-height: 36px;
  120. transition: .3s;
  121. display: inline-block;
  122. }
  123. &:hover {
  124. color: #20a0ff;
  125. background-color: #f9fafc;
  126. }
  127. & .text-slide-enter,
  128. & .text-slide-leave-active {
  129. opacity: 0;
  130. transform: translateX(10px);
  131. }
  132. }
  133. }
  134. </style>
  135. <script type="text/babel">
  136. import compoLang from '../i18n/component.json';
  137. import { version } from 'main/index.js';
  138. export default {
  139. data() {
  140. return {
  141. hovering: false,
  142. isExpanded: false
  143. };
  144. },
  145. props: {
  146. jsfiddle: Object,
  147. default() {
  148. return {};
  149. }
  150. },
  151. methods: {
  152. goJsfiddle() {
  153. const { script, html, style } = this.jsfiddle;
  154. const resourcesTpl = '<scr' + 'ipt src="//unpkg.com/vue/dist/vue.js"></scr' + 'ipt>' +
  155. '\n<scr' + `ipt src="//unpkg.com/element-ui@${ version }/lib/index.js"></scr` + 'ipt>';
  156. let jsTpl = (script || '').replace(/export default/, 'var Main =').trim();
  157. let htmlTpl = `${resourcesTpl}\n<div id="app">\n${html.trim()}\n</div>`;
  158. let cssTpl = `@import url("//unpkg.com/element-ui@${ version }/lib/theme-chalk/index.css");\n${(style || '').trim()}\n`;
  159. jsTpl = jsTpl
  160. ? jsTpl + '\nvar Ctor = Vue.extend(Main)\nnew Ctor().$mount(\'#app\')'
  161. : 'new Vue().$mount(\'#app\')';
  162. const data = {
  163. js: jsTpl,
  164. css: cssTpl,
  165. html: htmlTpl,
  166. panel_js: 3,
  167. panel_css: 1
  168. };
  169. const form = document.getElementById('fiddle-form') || document.createElement('form');
  170. form.innerHTML = '';
  171. const node = document.createElement('textarea');
  172. form.method = 'post';
  173. form.action = 'https://jsfiddle.net/api/post/library/pure/';
  174. form.target = '_blank';
  175. for (let name in data) {
  176. node.name = name;
  177. node.value = data[name].toString();
  178. form.appendChild(node.cloneNode());
  179. }
  180. form.setAttribute('id', 'fiddle-form');
  181. form.style.display = 'none';
  182. document.body.appendChild(form);
  183. form.submit();
  184. }
  185. },
  186. computed: {
  187. lang() {
  188. return this.$route.path.split('/')[1];
  189. },
  190. langConfig() {
  191. return compoLang.filter(config => config.lang === this.lang)[0]['demo-block'];
  192. },
  193. blockClass() {
  194. return `demo-${ this.lang } demo-${ this.$router.currentRoute.path.split('/').pop() }`;
  195. },
  196. iconClass() {
  197. return this.isExpanded ? 'el-icon-caret-top' : 'el-icon-caret-bottom';
  198. },
  199. controlText() {
  200. return this.isExpanded ? this.langConfig['hide-text'] : this.langConfig['show-text'];
  201. },
  202. codeArea() {
  203. return this.$el.getElementsByClassName('meta')[0];
  204. },
  205. codeAreaHeight() {
  206. if (this.$el.getElementsByClassName('description').length > 0) {
  207. return Math.max(this.$el.getElementsByClassName('description')[0].clientHeight, this.$el.getElementsByClassName('highlight')[0].clientHeight);
  208. }
  209. return this.$el.getElementsByClassName('highlight')[0].clientHeight;
  210. }
  211. },
  212. watch: {
  213. isExpanded(val) {
  214. this.codeArea.style.height = val ? `${ this.codeAreaHeight + 1 }px` : '0';
  215. }
  216. },
  217. mounted() {
  218. this.$nextTick(() => {
  219. let highlight = this.$el.getElementsByClassName('highlight')[0];
  220. if (this.$el.getElementsByClassName('description').length === 0) {
  221. highlight.style.width = '100%';
  222. highlight.borderRight = 'none';
  223. }
  224. });
  225. }
  226. };
  227. </script>