demo-block.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. <template>
  2. <div
  3. class="demo-block"
  4. :class="[blockClass, { 'hover': hovering }]"
  5. @mouseenter="hovering = true"
  6. @mouseleave="hovering = false">
  7. <slot></slot>
  8. <div class="demo-block-control" @click="isExpanded = !isExpanded">
  9. <transition name="arrow-slide">
  10. <i :class="[iconClass, { 'hovering': hovering }]"></i>
  11. </transition>
  12. <transition name="text-slide">
  13. <span v-show="hovering">{{ controlText }}</span>
  14. </transition>
  15. </div>
  16. </div>
  17. </template>
  18. <style>
  19. .demo-block {
  20. border: solid 1px #eaeefb;
  21. border-radius: 4px;
  22. transition: .2s;
  23. &.hover {
  24. box-shadow: 0 0 8px 0 rgba(232, 237, 250, .6), 0 2px 4px 0 rgba(232, 237, 250, .5);
  25. }
  26. code {
  27. font-family: Menlo, Monaco, Consolas, Courier, monospace;
  28. }
  29. .source {
  30. padding: 24px;
  31. }
  32. .meta {
  33. background-color: #f9fafc;
  34. border-top: solid 1px #eaeefb;
  35. clear: both;
  36. overflow: hidden;
  37. height: 0;
  38. transition: height .2s;
  39. }
  40. .description {
  41. padding: 18px 24px;
  42. width: 40%;
  43. box-sizing: border-box;
  44. border-left: solid 1px #eaeefb;
  45. float: right;
  46. font-size: 14px;
  47. line-height: 1.8;
  48. color: #5e6d82;
  49. word-break: break-word;
  50. p {
  51. margin: 0;
  52. }
  53. code {
  54. color: #5e6d82;
  55. background-color: #e6effb;
  56. margin: 0 4px;
  57. transform: translateY(-2px);
  58. display: inline-block;
  59. padding: 1px 5px;
  60. font-size: 12px;
  61. border-radius: 3px;
  62. }
  63. }
  64. .highlight {
  65. width: 60%;
  66. border-right: solid 1px #eaeefb;
  67. pre {
  68. margin: 0;
  69. }
  70. code.hljs {
  71. margin: 0;
  72. border: none;
  73. max-height: none;
  74. border-radius: 0;
  75. &::before {
  76. content: none;
  77. }
  78. }
  79. }
  80. .demo-block-control {
  81. border-top: solid 1px #eaeefb;
  82. height: 36px;
  83. box-sizing: border-box;
  84. background-color: #fff;
  85. border-bottom-left-radius: 4px;
  86. border-bottom-right-radius: 4px;
  87. text-align: center;
  88. margin-top: -1px;
  89. color: #d3dce6;
  90. cursor: pointer;
  91. transition: .2s;
  92. position: relative;
  93. i {
  94. font-size: 12px;
  95. line-height: 36px;
  96. transition: .3s;
  97. &.hovering {
  98. transform: translateX(-40px);
  99. }
  100. }
  101. span {
  102. position: absolute;
  103. transform: translateX(-30px);
  104. font-size: 14px;
  105. line-height: 36px;
  106. transition: .3s;
  107. display: inline-block;
  108. }
  109. &:hover {
  110. color: #20a0ff;
  111. background-color: #f9fafc;
  112. }
  113. & .text-slide-enter,
  114. & .text-slide-leave-active {
  115. opacity: 0;
  116. transform: translateX(10px);
  117. }
  118. }
  119. }
  120. </style>
  121. <script type="text/babel">
  122. export default {
  123. data() {
  124. return {
  125. hovering: false,
  126. isExpanded: false
  127. };
  128. },
  129. computed: {
  130. blockClass() {
  131. return `demo-${ this.$router.currentRoute.path.split('/').pop() }`;
  132. },
  133. iconClass() {
  134. return this.isExpanded ? 'el-icon-caret-top' : 'el-icon-caret-bottom';
  135. },
  136. controlText() {
  137. return this.isExpanded ? '隐藏代码' : '显示代码';
  138. },
  139. codeArea() {
  140. return this.$el.getElementsByClassName('meta')[0];
  141. },
  142. codeAreaHeight() {
  143. if (this.$el.getElementsByClassName('description').length > 0) {
  144. return Math.max(this.$el.getElementsByClassName('description')[0].clientHeight, this.$el.getElementsByClassName('highlight')[0].clientHeight);
  145. }
  146. return this.$el.getElementsByClassName('highlight')[0].clientHeight;
  147. }
  148. },
  149. watch: {
  150. isExpanded(val) {
  151. this.codeArea.style.height = val ? `${ this.codeAreaHeight + 1 }px` : '0';
  152. }
  153. },
  154. mounted() {
  155. this.$nextTick(() => {
  156. let highlight = this.$el.getElementsByClassName('highlight')[0];
  157. if (this.$el.getElementsByClassName('description').length === 0) {
  158. highlight.style.width = '100%';
  159. highlight.borderRight = 'none';
  160. }
  161. });
  162. }
  163. };
  164. </script>