grid.html 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <script src="../../dist/vue.min.js"></script>
  2. <!-- DemoGrid component template -->
  3. <script type="text/x-template" id="grid-template">
  4. <table v-if="filteredData.length">
  5. <thead>
  6. <tr>
  7. <th v-for="key in columns"
  8. @click="sortBy(key)"
  9. :class="{ active: state.sortKey == key }">
  10. {{ capitalize(key) }}
  11. <span class="arrow" :class="state.sortOrders[key] > 0 ? 'asc' : 'dsc'">
  12. </span>
  13. </th>
  14. </tr>
  15. </thead>
  16. <tbody>
  17. <tr v-for="entry in filteredData">
  18. <td v-for="key in columns">
  19. {{entry[key]}}
  20. </td>
  21. </tr>
  22. </tbody>
  23. </table>
  24. <p v-else>No matches found.</p>
  25. </script>
  26. <!-- DemoGrid component script -->
  27. <script>
  28. const { reactive, computed } = Vue
  29. const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)
  30. const DemoGrid = {
  31. template: '#grid-template',
  32. props: {
  33. data: Array,
  34. columns: Array,
  35. filterKey: String
  36. },
  37. setup(props) {
  38. const state = reactive({
  39. sortKey: '',
  40. sortOrders: props.columns.reduce((o, key) => (o[key] = 1, o), {})
  41. })
  42. const filteredData = computed(() => {
  43. let { data, filterKey } = props
  44. if (filterKey) {
  45. filterKey = filterKey.toLowerCase()
  46. data = data.filter(row => {
  47. return Object.keys(row).some(key => {
  48. return String(row[key]).toLowerCase().indexOf(filterKey) > -1
  49. })
  50. })
  51. }
  52. const { sortKey } = state
  53. if (sortKey) {
  54. const order = state.sortOrders[sortKey]
  55. data = data.slice().sort((a, b) => {
  56. a = a[sortKey]
  57. b = b[sortKey]
  58. return (a === b ? 0 : a > b ? 1 : -1) * order
  59. })
  60. }
  61. return data
  62. })
  63. function sortBy(key) {
  64. state.sortKey = key
  65. state.sortOrders[key] *= -1
  66. }
  67. return {
  68. state,
  69. filteredData,
  70. sortBy,
  71. capitalize
  72. }
  73. }
  74. }
  75. </script>
  76. <!-- App template (in DOM) -->
  77. <div id="demo">
  78. <form id="search">
  79. Search <input name="query" v-model="searchQuery">
  80. </form>
  81. <demo-grid
  82. :data="gridData"
  83. :columns="gridColumns"
  84. :filter-key="searchQuery">
  85. </demo-grid>
  86. </div>
  87. <!-- App script -->
  88. <script>
  89. new Vue({
  90. components: {
  91. DemoGrid
  92. },
  93. data: () => ({
  94. searchQuery: '',
  95. gridColumns: ['name', 'power'],
  96. gridData: [
  97. { name: 'Chuck Norris', power: Infinity },
  98. { name: 'Bruce Lee', power: 9000 },
  99. { name: 'Jackie Chan', power: 7000 },
  100. { name: 'Jet Li', power: 8000 }
  101. ]
  102. })
  103. }).$mount('#demo')
  104. </script>
  105. <style>
  106. body {
  107. font-family: Helvetica Neue, Arial, sans-serif;
  108. font-size: 14px;
  109. color: #444;
  110. }
  111. table {
  112. border: 2px solid #42b983;
  113. border-radius: 3px;
  114. background-color: #fff;
  115. }
  116. th {
  117. background-color: #42b983;
  118. color: rgba(255,255,255,0.66);
  119. cursor: pointer;
  120. -webkit-user-select: none;
  121. -moz-user-select: none;
  122. -ms-user-select: none;
  123. user-select: none;
  124. }
  125. td {
  126. background-color: #f9f9f9;
  127. }
  128. th, td {
  129. min-width: 120px;
  130. padding: 10px 20px;
  131. }
  132. th.active {
  133. color: #fff;
  134. }
  135. th.active .arrow {
  136. opacity: 1;
  137. }
  138. .arrow {
  139. display: inline-block;
  140. vertical-align: middle;
  141. width: 0;
  142. height: 0;
  143. margin-left: 5px;
  144. opacity: 0.66;
  145. }
  146. .arrow.asc {
  147. border-left: 4px solid transparent;
  148. border-right: 4px solid transparent;
  149. border-bottom: 4px solid #fff;
  150. }
  151. .arrow.dsc {
  152. border-left: 4px solid transparent;
  153. border-right: 4px solid transparent;
  154. border-top: 4px solid #fff;
  155. }
  156. </style>