使用 laravel8 + ajax 實現無限滾動

laradocs發表於2021-10-11

前言

什麼是無限滾動?無限滾動是一種網頁設計技術,可在使用者滾動頁面時連續載入內容,從而無需分頁。

快速開始

使用 composer 安裝 laravel 專案

composer create-project laravel/laravel example-app

cd example-app

php artisan serve

接下來在瀏覽器訪問 http://127.0.0.1:8000 即可:

使用 laravel8 + ajax 實現無線滾動

修改 .env 檔案

.
.
.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_database
DB_USERNAME=your_database_username
DB_PASSWORD=your_database_password
.
.
.

建立模型控制器和遷移

我們可以使用以下命令快速生成 ModelControllerMigrationFactorySeeder 檔案。

php artisan make:model Employee -cmfs

提示資訊:

Model created successfully.
Factory created successfully.
Created Migration: xxxx_xx_xx_xxxxxx_create_employees_table
Seeder created successfully.
Controller created successfully.

修改 Model 檔案

app\Models\Employee.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Employee extends Model
{
    use HasFactory;

    protected $fillable = [
        'name',
        'phone',
    ];
}

修改 Migration 檔案

database/migrations/xxxx_xx_xx_xxxxxx_create_employees_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateEmployeesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('employees', function (Blueprint $table) {
            $table->id();
            $table->string ( 'name' );
            $table->string ( 'phone' );
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('employees');
    }
}

修改 Factory 檔案

database/factories/EmployeeFactory.php

<?php

namespace Database\Factories;

use App\Models\Employee;
use Illuminate\Database\Eloquent\Factories\Factory;

class EmployeeFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Employee::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'name' => $this->faker->name,
            'phone' => $this->faker->phoneNumber,
        ];
    }
}

修改 Seeder 檔案

database/seeders/EmployeeSeeder.php

<?php

namespace Database\Seeders;

use App\Models\Employee;
use Illuminate\Database\Seeder;

class EmployeeSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        Employee::factory ( 333 )->create();
    }
}

修改 DatabaseSeeder 檔案

database/seeders/DatabaseSeeder.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        // \App\Models\User::factory(10)->create();
        $this->call ( EmployeeSeeder::class );
    }
}

最後,執行一下遷移命令:

php artisan migrate --seed

提示資訊:

Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (57.98ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (49.97ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (49.15ms)
Migrating: 2019_12_14_000001_create_personal_access_tokens_table
Migrated: 2019_12_14_000001_create_personal_access_tokens_table (79.26ms)
Migrating: 2021_10_10_151307_create_employees_table
Migrated: 2021_10_10_151307_create_employees_table (25.63ms)
Seeding: Database\Seeders\EmployeeSeeder
Seeded: Database\Seeders\EmployeeSeeder (128.42ms)
Database seeding completed successfully.

修改 Controller 檔案

app/Controllers/EmployeeController.php

<?php

namespace App\Http\Controllers;

use App\Models\Employee;
use Illuminate\Http\Request;

class EmployeeController extends Controller
{
    public function index ( Request $request )
    {
        if ( $request->ajax() ) {
            $employees = Employee::paginate ( 9 );

            return response()->json ( [
                'data' => $employees,
            ] );
        }

        return view ( 'employee.index' );
    }
}

檢視檔案

resources/views 目錄下新建一個 employee 目錄,然後在 employee 新建 index.blade.php 檔案:

resources/views/index.blade.php

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Employees</title>
    <!-- 引入 CSS 檔案 -->
    <link rel ="stylesheet" href ="//cdn.datatables.net/1.10.25/css/jquery.dataTables.min.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" />
    <link rel="stylesheet" href="//cdn.materialdesignicons.com/5.4.55/css/materialdesignicons.min.css">
</head>
<body>

<div class="container">
     <h3 class="text-center mb-5 mt-5">使用 Laravel8 + Ajax 無限分頁</h3>

     <div class="row" id="app">
        <!-- 由 Ajax 填充 -->
    </div>

    <div class="ajax-load text-center" style="display:none">
        <i class="mdi mdi-48px mdi-spin mdi-loading"></i> 載入中...
    </div>
     <div class="no-data text-center mb-4" style="display:none">
         <b>已經到底啦!</b>
     </div>
</div>

<!-- 引入 JS 檔案 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script src="https://cdn.datatables.net/1.10.25/js/jquery.dataTables.min.js"></script>
<script>
    var pages = 2;
    var currentPage = 0;
    // boolean 是保留字,改程式碼的時候要注意。
    var bool = false;
    var lastPage;

    $(window).scroll ( function () {
        var height = $(document).height();
        if ( $(window).scrollTop() + $(window).height() >= height && bool == false && lastPage > pages - 2 ) {
            bool = true;
            $('.ajax-load').show();
            lazyLoad ( pages ).then ( () => {
                bool = false;
                pages ++;
                if ( pages - 2 == lastPage ) {
                    $('.no-data').show();
                }
            } );
        }
    } );

    function lazyLoad ( page ) {
        return new Promise ( ( resolve, reject ) => {
            $.ajax ( {
                type: 'get',
                url: '?page=' + page,
                beforeSend () {
                    $('.ajax-load').show();
                },
                success: ( response ) => {
                    $('.ajax-load').hide();
                    var html = '';
                    for ( var i = 0; i < response.data.data.length; ++ i ) {
                        html += `
                            <div class="col-md-4 mb-3" >
                                <div class="card">
                                     <div class="card-header">Employee Title</div>
                                    <div class="card-body">
                                        <table class="table">
                                            <tr>
                                                <th>Name</th>
                                                <td>:</td>
                                                <td>` + response.data.data [ i ].name + `</td>
                                            </tr>
                                            <tr>
                                                <th>Phone</th>
                                                <td>:</td>
                                                <td>` + response.data.data [ i ].phone + `</td>
                                            </tr>
                                        </table>
                                    </div>
                                </div>
                            </div>
                        `;
                    }
                    $('#app').append ( html );
                    resolve();
                }
            } );
        } );
    }

    loadData(1);

    function loadData ( page ) {
        $.ajax ( {
            type: 'get',
            url: '?page=' + page,
            beforeSend () {
                $('.ajax-load').show();
            },
            success: ( response ) => {
                $('.ajax-load').hide();
                lastPage = response.data.last_page;
                var html = '';
                for ( var i = 0; i < response.data.data.length; ++ i ) {
                    html += `
                        <div class="col-md-4 mb-3" >
                            <div class="card">
                                <div class="card-header">Employee Title</div>
                                <div class="card-body">
                                    <table class="table">
                                        <tr>
                                            <th>Name</th>
                                            <td>:</td>
                                            <td>` + response.data.data [ i ].name + `</td>
                                        </tr>
                                        <tr>
                                            <th>Phone</th>
                                            <td>:</td>
                                            <td>` + response.data.data [ i ].phone + `</td>
                                        </tr>
                                    </table>
                                </div>
                            </div>
                        </div>
                    `;
                }
                $('#app').html ( html );
            }
        } );
    }
</script>

</body>
</html>

修改路由檔案

web.php 檔案裡面新增一行路由:

routes/web.php

Route::get ( 'employees', [ EmployeeController::class, 'index' ] )->name ( 'employees.index' );

效果

最後在瀏覽器訪問 http://127.0.0.1:8000/employees 就可以看到效果了。

使用 laravel8 + ajax 實現無線滾動
使用 laravel8 + ajax 實現無線滾動
使用 laravel8 + ajax 實現無線滾動

本作品採用《CC 協議》,轉載必須註明作者和本文連結
站在巨人的肩上

相關文章