首页 > 解决方案 > 何时使用 Vue 拆分成组件?

问题描述

在我的 Laravel 应用程序中,我使用 Vue 创建了一个带分页的可搜索表。这是源代码:

@extends ('layouts.app')

@section('title', 'Library')

@section ('content')

{{-- Breadcrumbs --}}
@component('components.breadcrumb-bar',
[
'breadcrumbs' => array(
[
'name' => "Home",
'url' => route('welcome-page')
],
[
'name' => "Library",
'url' => route('library.index')
]
)
])
@endcomponent

{{-- Page Header --}}
@component('components.page-header')

Library

@slot('introduction')
Welcome to the Library. Here you can view, download and share all templates and forms from across
the organisation. If you have any queries or ideas on how we can improve this section, contact us.
@endslot

@endcomponent

<div id="library-container">

<div class="container">
    <div class="row">

        <div class="col-12 col-md-6">

            <form method="get" action="{{ route('library.search') }}" class="mb-5">
                <div class="input-group">
                    <input type="text" name="q" class="form-control" id="" autocomplete="off" placeholder="Search the library" v-model="query"/>
                    <span class="input-group-append">
                        <button class="btn btn-outline-secondary" type="button" v-on:click="search()">
                            <i class="fa fa-search"></i>
                        </button>
                    </span>
                </div>
            </form>

        </div>

        <div class="col-12 col-md-6">
            <form>
                <select v-model="category" v-on:change="fetch_files_by_category()" class="form-control">
                    <option value="">Select a category</option>
                    <option v-for="category in categories" v-bind:value="category">@{{ category }}</option>
                </select>
            </form>
        </div>

        <div class="col-12">

            <div class="alert alert-info" role="alert" v-if="loading">
                <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
                Loading files
            </div>

            <div class="alert alert-danger" role="alert" v-if="error">
                <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
                @{{ error }}
            </div>

            <table class="table table-library" v-if="shouldDisplayTable">
                <thead>
                    <tr>
                        <th scope="col">Name</th>
                        <th scope="col">Category</th>
                        <th scope="col">Type</th>
                        <th colspan="2" scope="col">Actions</th>
                    </tr>
                </thead>

                <tbody>
                    <tr v-for="element in results" v-bind:key="element.id">
                        <td><span v-html="element.icon"></span><a v-bind:href="'/download/' + element.name">@{{ element.name }}</a></td>
                        <td>@{{ element.category }}</td>
                        <td>@{{ element.extension }}</td>
                        <td>
                            <a v-bind:href="'/download/' + element.name" class="btn btn-bright-blue">Download</a>
                        </td>
                        <td>
                            <a href="#" v-if="element.is_liked" v-on:click.prevent="like(element)">
                                <i  class="fas fa-heart"></i>
                            </a>
                            <a href="#" v-else v-on:click.prevent="like(element)">
                                <i  class="far fa-heart"></i>
                            </a>
                        </td>
                    </tr>
                </tbody>
            </table>

            <ul class="pagination justify-content-end">
                <li class="page-item">
                    <button v-on:click="fetch_results(pagination.prev_page_url)" :disabled="!pagination.prev_page_url" class="page-link">Previous</button>
                </li>
                <li class="page-item">
                    <button v-on:click="fetch_results(pagination.next_page_url)" :disabled="!pagination.next_page_url" class="page-link">Next</button>
                </li>
            </ul>

            <p class="justify-content-end">Showing @{{ pagination.from }} of @{{ pagination.to }} of @{{ pagination.total }}</p>

        </div>

    </div>
</div>

</div>

@endsection

@section('inline-script')

<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

<script type="text/babel">

new Vue({
    el: '#library-container',
    data: {
        query: '',
        categories: '',
        category: '',
        results: [],
        pagination: {},
        loading: false,
        error: '',
    },
    computed: {
        shouldDisplayTable(){
            if(this.loading == true || this.error !== ''){
                return false;
            }

            return true;
        }
    },
    created(){
        this.fetch_categories();
        this.fetch_results();
    },
    watch: {
        query(after, before) {
            this.search();
        }
    },
    methods: {
            search: _.debounce(function(){
            if(this.query !== ""){
                let vm = this;

                this.results = [];
                this.loading = true;
                this.error = '';
                axios.get("/library/api/search",{params: {q: this.query}})
                .then(response => ([
                    vm.makePagination(response.data),
                    this.results = response.data.data,
                    this.error = response.data.error ? response.data.error : '',
                    this.loading = false
                ]))
                .catch(this.error = '');
            } else{
                this.fetch_results();
            }
        }, 500),
        fetch_categories:function(){
            axios.get('/library/api/categories')
                 .then(response => ([
                     this.categories = response.data
                 ]))
                 .catch()
        },
        fetch_results: function(page_url){
            let vm = this;

            page_url = page_url || '/library/api/all'

            this.results = [];
            this.loading = true;
            this.error = '';
            axios.get(page_url)
            .then(response => ([
                vm.makePagination(response.data),
                this.results = response.data.data,
                this.loading = false
            ]))
            .catch(this.error = '');
        },
        fetch_files_by_category: function(){
            let vm = this;

            this.results = [];
            this.loading = true;
            this.error = '';
            axios.get('/library/api/' + this.category)
            .then(response => ([
                vm.makePagination(response.data),
                this.results = response.data.data,
                this.loading = false
            ]))
            .catch(this.error = '');
        },
        makePagination: function(data){
            var pagination = {
                from: data.from,
                to: data.to,
                total: data.total,
                current_page: data.current_page,
                last_page: data.last_page,
                next_page_url: data.next_page_url,
                prev_page_url: data.prev_page_url
            }

            this.pagination = pagination
        },
        like: function(element){
            axios.post('/like/file/' + element.id)
            .then(response => ([
                element.is_liked == true ? element.is_liked = false : element.is_liked = true
            ]))
            .catch(response => console.log(response.data));
        }
    }
});

</script>

@endsection

但是,我觉得这不是 Vue 应该使用的方式。

我的问题是:你会将哪些部分分成组件,或者你会更进一步,将整个东西变成一个模板?

这正是我想要的工作方式,但是以这种方式混合 Blade 和 Vue 感觉是错误的。

标签: javascriptvue.js

解决方案


推荐阅读