jsonデータをソートしたりレコード選択する
CMSやフレームワークを使えない状態で詳細ページ同士でリンクをつなげる必要があって、フロントで何とかしたメモ。
SEOやデータ追加更新時のリソースを考えると、フロント対処というところにツッコミがありますが
かなりのレアケースとは思いますが、せっかくなので記事にします。
こういうjsonがあったとして
[ { "name": "1月", "page": "sample1.html", "category": 2 }, { "name": "2月", "page": "sample2.html", "category": 1 }, { "name": "3月", "page": "sample3.html", "category": 3 }, { "name": "4月", "page": "sample4.html", "category": 1 }, { "name": "5月", "page": "sample5.html", "category": 1 }, { "name": "6月", "page": "sample6.html", "category": 2 }, { "name": "7月", "page": "sample7.html", "category": 3 }, { "name": "8月", "page": "sample8.html", "category": 3 }, { "name": "9月", "page": "sample9.html", "category": 2 } ]
カテゴリーが数値なのでちょっとわかりにくいかもしれません。
月別データだけど月によって違うカテゴリーになっていて、
今見ているページのカテゴリーと同じ月を優先的に表示したいとします。
// 変数jsonにjsonデータが代入されている想定 // 今のページを取得 const href = location.href; // jsonデータから、表示中のページレコードを検索 const now = json.filter(function (obj) { return (href.indexOf(obj.page) != -1); }).shift(); let list = json.filter(function(element) { // 表示中のページは含めない return (now.page != element.page); }).sort(function(a, b){ // 表示中のページと同じカテゴリーは最優先で表示 a.category = (now.category === a.category) ? 0 : a.category; b.category = (now.category === b.category) ? 0 : b.category; return a.category - b.category; });
これでlistをforEachなど使うとソート済みのデータで回せます。
素のJSでスムーズスクロール
自分用メモ
様々なサイトで用意されている「ページ最上部へ戻る」ボタンを、jQueryやライブラリを使わずに素のJSで実装するコードです。
<!-- htmlのbutton --> <button id="scroll">ページ最上部へ</button>
「ページ最上部へ」ボタンをクリックしたら少しずつスクロール位置を戻し、小刻みに繰り返してアニメーションのように見せています。
スクロールスピードはscrollTimerで調整するようになっています。scrollTimerの値が小さいほど速くスクロールします。
document.getElementById('scroll').addEventListener("click", function() { let height = window.pageYOffset; let scrollTimer = 15; let scrollBase = height / scrollTimer; const scrollPageTop =()=> { height = window.pageYOffset; scrollTo(0, height - scrollBase); // 最上部になっていなかったらスクロールを繰り返す if (height != 0) { setTimeout(scrollPageTop, scrollTimer); } }; scrollPageTop(); });
ページが長いと時間かかるかもしれません。
【CakePHP3.6】 一覧データをログイン中ユーザーのものに限定したいとき
自分用メモです。
個別のユーザーがusersテーブルに登録されていて、bookmarksテーブルがuser_idを持つ形で紐づいている場合
bakeしたコード↓
/** * Index method * * @return \Cake\Http\Response|void */ public function index() { $this->paginate = [ 'contain' => ['Users'] ]; $bookmarks = $this->paginate($this->Bookmarks); $this->set(compact('bookmarks')); }
↑これを↓のようにすると、ログイン中ユーザーのidに紐づく一覧データのみを表示します。
/** * Index method * * @return \Cake\Http\Response|void */ public function index() { $this->paginate = [ 'contain' => ['Users'], 'conditions' => ['user_id' => $this->Auth->user('id')], ]; $bookmarks = $this->paginate($this->Bookmarks); $this->set(compact('bookmarks')); }
↑これを更に↓のようにconditionsを設定すると、特定のユーザーのときはユーザー自身の一覧のみ、それ以外は全ユーザーの一覧が表示されます。
/** * Index method * * @return \Cake\Http\Response|void */ public function index() { $this->paginate = [ 'contain' => ['Users'] ]; // 一般ユーザーのときは表示する一覧データをユーザー自身のものに限定する if ($this->Auth->user('role') === 0) // 適宜、一般ユーザー判定など { $this->paginate['conditions'] = [ 'user_id' => $this->Auth->user('id') ]; } $bookmarks = $this->paginate($this->Bookmarks); $this->set(compact('bookmarks')); }
【CakePHP3.6】ログイン後の遷移先設定
自分用メモです。
ログインしたときに、元のページまたは指定のページに遷移させる方法。
UsersControllerのloginメソッドなどでも対応できますが、個人の好みとAuthコンポーネントの管理コストを考えるとこの書き方が便利だと思いました。 (ついでにログアウト後の遷移先も設定)
// src/Controller/AppController.php の中で namespace App\Controller; use Cake\Controller\Controller; class AppController extends Controller { public function initialize() { // 既存のコード $this->loadComponent('Auth', [ 'authenticate' => [ 'Form' => [ 'fields' => [ 'username' => 'email', 'password' => 'password' ] ] ], 'loginAction' => [ 'controller' => 'Users', 'action' => 'login' ], // ログイン後リダイレクト先 'loginRedirect' => [ 'controller' => 'Articles', 'action' => 'index' ], // ログアウト後リダイレクト先 'logoutRedirect' => [ 'controller' => 'Users', 'action' => 'login' ], // コントローラーで isAuthorized を使用します 'authorize' => ['Controller'], // 未認証の場合、直前のページに戻します 'unauthorizedRedirect' => $this->referer() ]); // display アクションを許可して、PagesController が引き続き // 動作するようにします。また、読み取り専用のアクションを有効にします。 $this->Auth->allow(['display', 'view', 'index']); } }
UsersControllerからでも出来なくはありませんが、↑の方がコードも簡潔なので特に事情がない限りはAppControllerのAuthコンポーネントでまとめると良いと思います。
loginメソッド内で設定する必要があるときは、公式チュートリアルのリダイレクトのところを設定します。
// src/Controller/UsersController.php の中で public function login() { if ($this->request->is('post')) { $user = $this->Auth->identify(); if ($user) { $this->Auth->setUser($user); // ↓これの引数を指定しても実装はできる return $this->redirect($this->Auth->redirectUrl()); } $this->Flash->error('ユーザー名またはパスワードが不正です。'); } }
参考にしたページ https://book.cakephp.org/3.0/ja/tutorials-and-examples/cms/authentication.html
GitLab Pagesで静的サイトを公開する
ちょっとしたサンプルなどを公開するときにも使える、GitLab Pagesを使ったページの公開方法のメモ。
masterブランチに公開したい静的サイトのデータと、.gitlab-ci.ymlをコミットしてプッシュする。
↓.gitlab-ci.ymlの内容
image: python:2.7 pages: stage: deploy script: - mkdir .public - cp -r * .public - mv .public public artifacts: paths: - public only: - master
すぐには公開されないので、しばらく時間を置く。
GitLabプロジェクトのCI/CDで「passed」になっていることを確認。
公開先のURLはhttps://ユーザー名.gitlab.io/プロジェクト名/
になる。
ユーザー名はGitLabのプロフィールURLのサブディレクトリの名前、私の場合は
https://gitlab.com/riya3
のriya3
もしくはhttps://gitlab.com/profile/account
のChange usernameから確認できる。
マウスオーバーでふわふわ動く旗
タイトルのままですが、マウスをのっけると上下にふわふわ動く日本国旗です。 こんな感じ
html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>floating</title> <link href="https://fonts.googleapis.com/css?family=Noto+Serif+JP&display=swap" rel="stylesheet"> <link href="css/base.css" rel="stylesheet" type="text/css"> </head> <body> <div class="flag"> <div class="reiwa"> 令和 </div> </div> <script src="js/base.js"></script> </body> </html>
CSS
htmlのhead内で読み込んでいるcss/base.cssの記述内容です。 今回はreset系のCSSは使っていません。
html { font-size: 62.5%; } body { background: #efefef; font-size: 1.6em; display: flex; align-items: center; justify-content: center; min-height: 100vh; } .flag { background: #fff; display: flex; align-items: center; justify-content: center; width: 21rem; height: 14rem; position: relative; cursor: pointer; } .jump { animation: jump-anime 1s ease-in-out infinite; } @keyframes jump-anime{ 0% { bottom: 0; } 50% { bottom: 2rem; } 100% { bottom: 0; } } .reiwa { background: #F20000; border-radius: 50%; color: #fff; font-family: 'Noto Serif JP', serif; font-size: 2.3rem; line-height: 1; margin: 0 auto; padding: 1.9rem 3.05rem; writing-mode: vertical-rl; }
JavaScript
htmlの下の方で読み込んでいるjs/base.jsの記述内容です。
const flag = document.getElementsByClassName('flag')[0]; flag.addEventListener('mouseover', () => { flag.classList.add('jump'); }) flag.addEventListener('mouseout', () => { flag.classList.remove('jump'); });
ちょっとだけコードの説明
bodyの子要素の国旗をflexboxで中央に指定しています。 (他に要素もないのでbodyに設定しましたが、普通のサイトではbodyに書くケースはあまりないと思います)
flagクラスが国旗部分、reiwaクラスが「令和」の文字部分と国旗中央の赤いところです。 赤の指定は公式には「紅色」なのですが、好みの赤を指定しました。 赤い丸も国旗の位置指定と同様にflexboxで中央にしています。 writing-modeにvertical-rlを指定することで文字を縦書きにします。
htmlでは使っていませんが、jumpクラスをつけると上下にふわふわ動くアニメーションを設定します。
そのjumpクラスをjavascriptでマウスオーバーイベントで追加、マウスアウトで削除させています。
今回の動きだけならjsを使わずに実装できますが、jsを使えば更にバッジつけたりウィンドウ出したりやりやすいので、どちらかといえばこちらが好みです。
画面最上部の横並びナビゲーション
よくあるサイトデザインの1つ、ページ一番上の横並びメニューの書き方例です。
こういうの
今回の横並びはflexboxを使っています。
まずhtml
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>flex-box</title> <link rel="stylesheet" type="text/css" href="css/reset.css"> <link rel="stylesheet" type="text/css" href="css/base.css"> </head> <body> <header> <nav> <ul class="g-nav-lists"> <li> <a href="#">項目1</a> </li> <li> <a href="#">項目2</a> </li> <li> <a href="#">項目3</a> </li> <li> <a href="#">項目4</a> </li> <li> <a href="#">項目5</a> </li> </ul> </nav> </header> <main> メインコンテンツ </main> </body> </html>
このサンプルの場合はフッターや別のナビゲーションがないので<nav>
と<ul>
の構造が変に見えるかもしれませんが、フッターなどで似たようなデザインのナビゲーションを使うときにul単位で記述を共通化できるので私はけっこう好きです。
headerではreset.cssとbase.cssを読み込んでいます。
reset.cssはこちらを使用しています。
古いCSSリセットからはもう卒業!モダンブラウザに適した新しいCSSリセット -A Modern CSS Reset | コリス
CSSはこちらです。
作業内容を見やすくする目的でborderやmin-heightなど書いていますが、実際のページを作るときは不要かもしれません。
html { font-size: 62.5%; } body { font-family: Quicksand, 游ゴシック体, "Yu Gothic", YuGothic, "ヒラギノ角ゴシック Pro", "Hiragino Kaku Gothic Pro", メイリオ, Meiryo, Osaka, "MS Pゴシック", "MS PGothic", sans-serif; font-size: 1.6em; line-height: 2; } .g-nav-lists { display: flex; justify-content: center; list-style-type: none; background: #ccc; } .g-nav-lists li a { color: #222; text-decoration: none; padding: .8rem 1.5rem; display: block; } .g-nav-lists li a:hover { background: #555; color: #fff; } main { border-right: 1px solid #ccc; border-left: 1px solid #ccc; min-height: calc(100vh - 4.8rem); margin: 0 auto; max-width: 80rem; padding: 2rem; }
今回はheader要素とmain要素の幅を分けています。
headerはアイキャッチ画像を使う場合もページ横幅いっぱいまで簡単に設定でき、mainは読みやすい幅で最大値を指定しています。