| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- <script src="../../dist/vue.min.js"></script>
- <!-- DemoGrid component template -->
- <script type="text/x-template" id="grid-template">
- <table v-if="filteredData.length">
- <thead>
- <tr>
- <th v-for="key in columns"
- @click="sortBy(key)"
- :class="{ active: state.sortKey == key }">
- {{ capitalize(key) }}
- <span class="arrow" :class="state.sortOrders[key] > 0 ? 'asc' : 'dsc'">
- </span>
- </th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="entry in filteredData">
- <td v-for="key in columns">
- {{entry[key]}}
- </td>
- </tr>
- </tbody>
- </table>
- <p v-else>No matches found.</p>
- </script>
- <!-- DemoGrid component script -->
- <script>
- const { reactive, computed } = Vue
- const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)
- const DemoGrid = {
- template: '#grid-template',
- props: {
- data: Array,
- columns: Array,
- filterKey: String
- },
- setup(props) {
- const state = reactive({
- sortKey: '',
- sortOrders: props.columns.reduce((o, key) => (o[key] = 1, o), {})
- })
- const filteredData = computed(() => {
- let { data, filterKey } = props
- if (filterKey) {
- filterKey = filterKey.toLowerCase()
- data = data.filter(row => {
- return Object.keys(row).some(key => {
- return String(row[key]).toLowerCase().indexOf(filterKey) > -1
- })
- })
- }
- const { sortKey } = state
- if (sortKey) {
- const order = state.sortOrders[sortKey]
- data = data.slice().sort((a, b) => {
- a = a[sortKey]
- b = b[sortKey]
- return (a === b ? 0 : a > b ? 1 : -1) * order
- })
- }
- return data
- })
- function sortBy(key) {
- state.sortKey = key
- state.sortOrders[key] *= -1
- }
- return {
- state,
- filteredData,
- sortBy,
- capitalize
- }
- }
- }
- </script>
- <!-- App template (in DOM) -->
- <div id="demo">
- <form id="search">
- Search <input name="query" v-model="searchQuery">
- </form>
- <demo-grid
- :data="gridData"
- :columns="gridColumns"
- :filter-key="searchQuery">
- </demo-grid>
- </div>
- <!-- App script -->
- <script>
- new Vue({
- components: {
- DemoGrid
- },
- data: () => ({
- searchQuery: '',
- gridColumns: ['name', 'power'],
- gridData: [
- { name: 'Chuck Norris', power: Infinity },
- { name: 'Bruce Lee', power: 9000 },
- { name: 'Jackie Chan', power: 7000 },
- { name: 'Jet Li', power: 8000 }
- ]
- })
- }).$mount('#demo')
- </script>
- <style>
- body {
- font-family: Helvetica Neue, Arial, sans-serif;
- font-size: 14px;
- color: #444;
- }
- table {
- border: 2px solid #42b983;
- border-radius: 3px;
- background-color: #fff;
- }
- th {
- background-color: #42b983;
- color: rgba(255,255,255,0.66);
- cursor: pointer;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- }
- td {
- background-color: #f9f9f9;
- }
- th, td {
- min-width: 120px;
- padding: 10px 20px;
- }
- th.active {
- color: #fff;
- }
- th.active .arrow {
- opacity: 1;
- }
- .arrow {
- display: inline-block;
- vertical-align: middle;
- width: 0;
- height: 0;
- margin-left: 5px;
- opacity: 0.66;
- }
- .arrow.asc {
- border-left: 4px solid transparent;
- border-right: 4px solid transparent;
- border-bottom: 4px solid #fff;
- }
- .arrow.dsc {
- border-left: 4px solid transparent;
- border-right: 4px solid transparent;
- border-top: 4px solid #fff;
- }
- </style>
|