demo-block.vue 5.5 KB

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