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は読みやすい幅で最大値を指定しています。