お問い合わせ

ブログ

これまでに経験してきたプロジェクトで気になる技術の情報を紹介していきます。

新人研修で作成したホームページ

horiuchi Horiuchi 10 months
新人研修で作成したホームページ

初めまして、新入社員の堀内です。

新人研修の一環で作成したホームページについて書きます。 ホームページは以下のリンクから確認できます。

[http://study.aska-ltd.jp/]

私は主にフロントエンドの開発を行いました。 PHPやLaravelはまだ慣れていなくて、また、HTML,CSS,JavaSCriptとあまり使ったことのない言語を使うことも多く、なかなか苦戦しました。特に、JavaScriptでスムーズスクロール機能を実装するのが難しく、スクロールはするがスムーズじゃないなどいろいろ問題もありましたが、最終的にはこのコードでうまくいきました。

// DOMが完全に読み込まれた後に実行されるイベントリスナーを追加
document.addEventListener('DOMContentLoaded', function() {
    // モバイルメニュー内のリンクとヘッダーメニューのリンクを取得
    const mobileMenuLinks = document.querySelectorAll('.mobile-menu a');
    const headerMenuLinks = document.querySelectorAll('.header__menu a');
    // モバイルメニューのコンテナを取得
    const mobileMenuContainer = document.querySelector('.mobile-menu');

    // 指定されたIDの要素までスムーズにスクロールする関数
    function scrollToElement(targetId) {
        // 対象の要素をIDで取得
        const targetElement = document.getElementById(targetId);
        if (targetElement) {
            // スムーズスクロールを実行
            window.scrollTo({
                top: targetElement.getBoundingClientRect().top + window.pageYOffset - document.querySelector('.header').offsetHeight,
                behavior: 'smooth'
            });
        }
    }

    // リンクにスクロール機能を追加する関数
    function addScrollToLinks(links) {
        links.forEach(function(link) {
            link.addEventListener('click', function(event) {
                // リンクにハッシュ(#)が含まれている場合
                if (link.hash) {
                    event.preventDefault(); // デフォルトの動作を阻止
                    mobileMenuContainer.style.display = 'none'; // モバイルメニューを非表示に設定
                    if (window.location.pathname !== '/home' && window.location.pathname !== '/') {
                        // 現在のページがホームページでない場合、スクロール先のIDをセッションストレージに保存し、ホームページにリダイレクト
                        sessionStorage.setItem('scrollToId', link.hash.substring(1));
                        window.location.href = '/home';
                    } else {
                        // 現在のページがホームページの場合、指定されたIDの要素までスムーズスクロール
                        scrollToElement(link.hash.substring(1));
                        mobileMenuContainer.style.display = 'none'; // モバイルメニューを非表示に設定
                    }
                }
            });
        });
    }

    // モバイルメニューとヘッダーメニューのリンクにスクロール機能を追加
    addScrollToLinks(mobileMenuLinks);
    addScrollToLinks(headerMenuLinks);

    // ページ読み込み時にセッションストレージからスクロール先のIDを取得し、スクロール実行
    const savedId = sessionStorage.getItem('scrollToId');
    if (savedId) {
        scrollToElement(savedId); // スクロール実行
        sessionStorage.removeItem('scrollToId'); // 使用済みのスクロール情報を削除
        mobileMenuContainer.style.display = 'none'; // モバイルメニューを非表示に設定
    }

    // ハンバーガーメニューの動作を制御
    var hamburger = document.querySelector('.hamburger');
    var mobileMenu = document.getElementById('mobile-menu');
    hamburger.addEventListener('click', function() {
        // ハンバーガーメニューがクリックされたとき、モバイルメニューの表示状態を切り替える
        mobileMenu.style.display = mobileMenu.style.display === 'block' ? 'none' : 'block';
    });
});

ほかに検索機能も難航しましたが、以下のコードで実装できました。

/**
     * search
     *
     * ユーザーからのリクエストを受けてブログを検索し、結果をページネーション付きで表示するメソッド。
     * - 検索入力が空の場合は、前のページにリダイレクトします。
     * - 全角スペースは半角スペースに置換され、検索キーワードはスペースで分割されます。
     * - ハイフン(-)で始まるキーワードは否定的検索(除外キーワード)として扱われます。
     * - チェックボックス(checkA, checkB, check1, check2, check3)に基づいて、AND/OR条件で検索クエリを構築します。
     * - 検索結果は5件ごとにページネーションされ、ビューに渡されます。
     *
     * @param  Request $request ユーザーからのリクエストデータ
     * @return \Illuminate\Http\Response ビューに検索結果と関連データを渡してレンダリング
     */
    public function search(Request $request)
    {
        $searchInput = $request->input("search");
        $checkA = $request->input("checkA");
        $checkB = $request->input("checkB");
        $check1 = $request->input("check1");
        $check2 = $request->input("check2");
        $check3 = $request->input("check3");

        if (!$searchInput) {
            return redirect()->back();
        }

        $searchInput = str_replace(" ", " ", $searchInput);
        $keywords = array_filter(array_map('trim', explode(' ', $searchInput)));
        $query = Blog::query();

        foreach ($keywords as $keyword) {
            $isNegative = false;

            if (strpos($keyword, '-') === 0) {
                $isNegative = true;
                $keyword = substr($keyword, 1);
            }

            if ($keyword) {
                if ($checkA) {
                    $query->where(function ($subQuery) use ($keyword, $check1, $check2, $check3, $isNegative) {
                        $this->applyConditions($subQuery, $keyword, $check1, $check2, $check3, 'where', $isNegative);
                    });
                } elseif ($checkB) {
                    $query->orWhere(function ($subQuery) use ($keyword, $check1, $check2, $check3, $isNegative) {
                        $this->applyConditions($subQuery, $keyword, $check1, $check2, $check3, 'orWhere', $isNegative);
                    });
                } else {
                    $this->applyConditions($query, $keyword, $check1, $check2, $check3, 'where', $isNegative);
                }
            }
        }

        $blogs = $query->orderBy('id','desc')->with('user', 'categories')->paginate(5)->appends(request()->except('page'));
        $categories = Category::withCount('blogs')->get();

        return view("pages.frontend.blog-list", compact("blogs", "categories", "searchInput"));
    }

    /**
     * applyConditions
     *
     * 指定されたクエリに検索条件を適用するメソッド。
     * - キーワードに基づいて 'title', 'content', またはユーザーの 'name' フィールドで検索を行います。
     * - $isNegative が true の場合、否定的検索(指定されたキーワードを含まないレコードを検索)を行います。
     *   この場合、条件タイプは常に 'where' に固定されます。
     * - $method は、否定的検索でない場合のクエリの条件タイプ ('where', 'orWhere') を指定します。
     * - $check1, $check2, $check3 は、それぞれユーザー名、タイトル、コンテンツに対する検索を指定します。
     *   これらのうちいずれかが true の場合、対応するフィールドに対して検索条件が適用されます。
     *   これらがすべて false の場合、デフォルトで 'title' フィールドに対する条件のみが適用されます。
     *
     * @param \Illuminate\Database\Eloquent\Builder $query 検索を行うクエリビルダー
     * @param string $keyword 検索するキーワード
     * @param boolean $check1 ユーザー名に対する検索を行うかどうか
     * @param boolean $check2 タイトルに対する検索を行うかどうか
     * @param boolean $check3 コンテンツに対する検索を行うかどうか
     * @param string $method クエリの条件タイプ ('where', 'orWhere')
     * @param boolean $isNegative 否定的検索を行うかどうか
     * @return void
     */
    protected function applyConditions($query, $keyword, $check1, $check2, $check3, $method, $isNegative = false)
    {
        $likeOperator = $isNegative ? 'not like' : 'like';
        $method = $isNegative ? 'where' : $method;

        if ($check1 || $check2 || $check3) {
            $query->$method(function ($subQuery) use ($keyword, $check1, $check2, $check3, $likeOperator) {
                if ($check1) {
                    $subQuery->whereHas('user', function ($query) use ($keyword, $likeOperator) {
                        $query->where('name', $likeOperator, '%' . $keyword . '%');
                    });
                }
                if ($check2) {
                    $subQuery->Where('title', $likeOperator, '%' . $keyword . '%');
                }
                if ($check3) {
                    $subQuery->Where('content', $likeOperator, '%' . $keyword . '%');
                }
            });
        } else {
            $query->$method('title', $likeOperator, '%' . $keyword . '%');
        }
    }

今回のホームページ作成はなかなか大変でしたが、自分にとっていい経験になったと思います。特に、Laravelを使用した開発についてだいぶ理解できたかなと思っております。今回の経験を活かして今後も頑張っていきたいと考えております。

以上です、ここまでお読みくださりありがとうございました。

新人研修で作成したホームページ 2024-02-05 11:46:37

コメントはありません。

4824

お気軽に
お問い合わせください。

お問い合わせ
gomibako@aska-ltd.jp