grid.html 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <script src="../../dist/vue.global.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">Search <input name="query" v-model="searchQuery" /></form>
  79. <demo-grid :data="gridData" :columns="gridColumns" :filter-key="searchQuery">
  80. </demo-grid>
  81. </div>
  82. <!-- App script -->
  83. <script>
  84. Vue.createApp({
  85. components: {
  86. DemoGrid,
  87. },
  88. data: () => ({
  89. searchQuery: '',
  90. gridColumns: ['name', 'power'],
  91. gridData: [
  92. { name: 'Chuck Norris', power: Infinity },
  93. { name: 'Bruce Lee', power: 9000 },
  94. { name: 'Jackie Chan', power: 7000 },
  95. { name: 'Jet Li', power: 8000 },
  96. ],
  97. }),
  98. }).mount('#demo')
  99. </script>
  100. <style>
  101. body {
  102. font-family:
  103. Helvetica Neue,
  104. Arial,
  105. sans-serif;
  106. font-size: 14px;
  107. color: #444;
  108. }
  109. table {
  110. border: 2px solid #42b983;
  111. border-radius: 3px;
  112. background-color: #fff;
  113. }
  114. th {
  115. background-color: #42b983;
  116. color: rgba(255, 255, 255, 0.66);
  117. cursor: pointer;
  118. -webkit-user-select: none;
  119. -moz-user-select: none;
  120. -ms-user-select: none;
  121. user-select: none;
  122. }
  123. td {
  124. background-color: #f9f9f9;
  125. }
  126. th,
  127. td {
  128. min-width: 120px;
  129. padding: 10px 20px;
  130. }
  131. th.active {
  132. color: #fff;
  133. }
  134. th.active .arrow {
  135. opacity: 1;
  136. }
  137. .arrow {
  138. display: inline-block;
  139. vertical-align: middle;
  140. width: 0;
  141. height: 0;
  142. margin-left: 5px;
  143. opacity: 0.66;
  144. }
  145. .arrow.asc {
  146. border-left: 4px solid transparent;
  147. border-right: 4px solid transparent;
  148. border-bottom: 4px solid #fff;
  149. }
  150. .arrow.dsc {
  151. border-left: 4px solid transparent;
  152. border-right: 4px solid transparent;
  153. border-top: 4px solid #fff;
  154. }
  155. </style>