フリーランス 技術調査ブログ

フリーランス/エンジニア Ruby Python Nodejs Vuejs React Dockerなどの調査技術調査の備忘録

CSSヘッダー&フッターを固定化する

 はじめに

  • normalizeを利用してヘッダー&フッターが常に上下に固定化されているページを作成する necolas.github.io

CSS

  • stylesheetは下記のように記述する
html,
body {
  margin: 0; /* 余白の削除 */
  padding: 0; /* 余白の削除 */
  width: 100%;
  height: 100%;
}

.header__div {
  position: fixed; /* 固定 */
  top: 0; /* 一番上に表示 */
  width: 100%; /* 中央に表示 */
  border: solid red;
  background-color: gray;
}

.container__div {
  min-height: 90vh;
  width: 100%;
  overflow-x: hidden !important;
  border: solid rebeccapurple;
  overflow: auto;
}

.footer__div {
  position: fixed; /* 固定 */
  bottom: 0; /* 一番下に表示 */
  width: 100%; /* 中央に表示 */
  border: solid blue;
  background-color: gray;
}

HTML

<template>
  <div>
    <div class="header__div">
      ヘッダー
    </div>
    <div class="container__div">
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>
        テストテストテストテストテストテストテストテストテストテストテストテスト<br>

    </div>
    <div class="footer__div">
      フッター
    </div>
  </div>
</template>

<script>
export default {}
</script>

<style>
</style>

結果

f:id:PX-WING:20210107082819p:plain

NativeScript-Vueで操作イベントを取得して画面に表示する

参考ページ

docs.nativescript.org

 サンプルコード

  • タップイベントなどを取得して画面に表示するシンプルなアプリ
<template>
    <Page class="page">
        <ActionBar title="操作イベント" class="action-bar"></ActionBar>
        <GridLayout rows="auto, auto, *">
            <Label row="0" class="target" text="Target Area" @tap="onTap"
                @doubleTap="onDoubleTap" @longPress="onLongPress"
                @swipe="onSwipe" @pan="onPan" @pinch="onPinch"
                @rotation="onRotation">
            </Label>
            <ListView row="2" class="list-group" for="entry in log">
                <v-template>
                    <Label class="m-20" :text="entry.text"></Label>
                </v-template>
            </ListView>
        </GridLayout>
    </Page>
</template>

<script>
    const SwipeDirection = require("tns-core-modules/ui/gestures")
        .SwipeDirection;
    export default {
        data: () => {
            return {
                log: []
            };
        },

        methods: {
            onTap() {
                this.log.unshift({
                    text: "タップイベント"
                });
            },

            onDoubleTap() {
                this.log.unshift({
                    text: "ダブルタップ"
                });
            },

            onLongPress() {
                this.log.unshift({
                    text: "ロングプレス"
                });
            },

            onSwipe(args) {
                let direction =
                    args.direction == SwipeDirection.down ?
                    "下" :
                    args.direction == SwipeDirection.up ?
                    "上" :
                    args.direction == SwipeDirection.left ?
                    "左" :
                    "右";
                this.log.unshift({
                    text: direction + " のスワイプ"
                });
            },
            onPinch() {
                this.log.unshift({
                    text: "ピッチ"
                });
            },

            onRotation() {
                this.log.unshift({
                    text: "2本の指を使用して画面に触れてから、それらを同時に左または右に回転させます。"
                });
            }
        }
    };
</script>

画面

f:id:PX-WING:20210108001502p:plain

nativescriptで端末情報を取得する

参考URL

docs.nativescript.org

コード

<template>
    <Page>
        <ActionBar title="Home" />
        <ScrollView>
            <StackLayout class="home-panel">
                <!--Add your page content here-->
                <Label textWrap="true" class="h2 description-label">
                    {{uuid}}
                </Label>
                <Label textWrap="true" class="h2 description-label">
                    {{os}}
                </Label>
                <Label textWrap="true" class="h2 description-label">
                    {{osVersion}}
                </Label>
            </StackLayout>
        </ScrollView>
    </Page>
</template>

<script>
    import {
        isAndroid,
        isIOS,
        device,
        screen
    } from "tns-core-modules/platform";

    export default {
        data() {
            return {
                uuid: "",
                os: "",
                osVersion: ""
            };
        },
        created: function() {
            console.log("created");
            this.uuid = device.uuid;
            this.os = device.os;
            this.osVersion = device.osVersion;
            console.log(isAndroid);
            console.log(isIOS);
            console.log(device.uuid);
            console.log(device.os);
            console.log(device.deviceType);
            console.log(device.osVersion);
            console.log(device.mode);
        }
    };
</script>

<style scoped>
    .home-panel {
        vertical-align: center;
        font-size: 20;
        margin: 15;
    }

    .description-label {
        margin-bottom: 15;
    }
</style>

実行結果

f:id:PX-WING:20210107065338p:plain

nativescriptでカメラ起動する

インストール

tns plugin add nativescript-camera

market.nativescript.org

 コード

<template>
    <Page>
        <ActionBar>
            <Label text="カメラ起動サンプル"/>
        </ActionBar>        
        <Button @tap="onButtonTap" text="カメラ起動7" class="-outline"></Button>
    </Page>
</template>

<script>
import * as camera from "nativescript-camera";
import { Image } from "tns-core-modules/ui/image";


  export default {
    mounted () {
      // カメラが利用できるかの確認
      var isAvailable = camera.isAvailable(); 
      console.log("############################")
      console.log(isAvailable)
    },
    methods: {
      onButtonTap() {
        // カメラ起動
        //var options = { width: 300, height: 300, keepAspectRatio: false, saveToGallery: true };
        camera.takePicture().
            then((imageAsset) => {
                console.log("Result is an image asset instance");
                var image = new Image();
                image.src = imageAsset;
                //console.log("Size: " + imageAsset.options.width + "x" + imageAsset.options.height);
                //console.log("keepAspectRatio: " + imageAsset.options.keepAspectRatio);
                //console.log("Photo saved in Photos/Gallery for Android or in Camera Roll for iOS");
            }).catch((err) => {
                console.log("Error22 -> " + err.message);
            });        
      }
    }
  };
</script>

<style scoped lang="scss">
    @import '~@nativescript/theme/scss/variables/blue';

    // Custom styles
    .fas {
        @include colorize($color: accent);
    }

    .info {
        font-size: 20;
        horizontal-align: center;
        vertical-align: center;
    }
</style>

マニフェストの設定

  • /App_Resources/Android/src/main/AndroidManifest.xmlを参照しandroid:requestLegacyExternalStorage="true"を追記する
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="__PACKAGE__"
        android:versionCode="10000"
        android:versionName="1.0">

        <supports-screens
                android:smallScreens="true"
                android:normalScreens="true"
                android:largeScreens="true"
                android:xlargeScreens="true"/>

        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        <uses-permission android:name="android.permission.INTERNET"/>

        <application
                android:name="com.tns.NativeScriptApplication"
                android:allowBackup="true"
                android:icon="@drawable/icon"
                android:label="@string/app_name"
                android:requestLegacyExternalStorage="true"
                android:theme="@style/AppTheme">

                <activity
                        android:name="com.tns.NativeScriptActivity"
                        android:label="@string/title_activity_kimera"
                        android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|uiMode"
                        android:theme="@style/LaunchScreenTheme">

                        <meta-data android:name="SET_THEME_ON_LAUNCH" android:resource="@style/AppTheme" />

                        <intent-filter>
                                <action android:name="android.intent.action.MAIN" />
                                <category android:name="android.intent.category.LAUNCHER" />
                        </intent-filter>
                </activity>
                <activity android:name="com.tns.ErrorReportActivity"/>
        </application>
</manifest>

結果

  • エラー処理が走ってしまい写真を保存することができなかった。カメラは起動しました。
LOG from device AQUOS sense3 basic: '############################'
LOG from device AQUOS sense3 basic: true
LOG from device AQUOS sense3 basic: 'Error22 -> cancelled'

vee-validateでレイアウトが崩れる時の対処

はじめに

  • vee-validateで覚えたことを下記にまとめる
  • <validation-provider>タグを利用するとレイアウトが崩れる現象に遭遇したので、その時のメモ。

レイアウトが崩れるコード

  • <validation-provider>を埋め込むとdivタグが自動で生成されるため、レイアウトが崩れていた。
      <validation-provider rules="required|nameKanji:@姓,@名" name="姓" >
          <div class="hogehoge">
             <p class="inputform_input-title">
              姓
             </p>
             <input v-model="sei" name="sei" type="text" class="hogehoge" placeholder="やまだ">
          </div>
      </validation-provider>
      <validation-provider rules="required|nameKanji:@姓,@名" name="名">
          <div class="hogehoge">
             <p class="inputform_input-title">
              名
            </p>
            <input  v-model="mei" name="mei" type="text" class="hogehoge" placeholder="たろう">
          </div>
      </validation-provider>

レイアウトが崩れないコード

  • <validation-provider>タグにtag属性とレイアウトに必要なclass属性を指定することでレイアウトを崩れずに対応できました。
      <validation-provider rules="required|nameKanji:@姓,@名" tag="div" name="姓" class="hogehoge">
          <p class="inputform_input-title">
            姓
          </p>
          <input v-model="sei" name="sei" type="text" class="hogehoge" placeholder="やまだ">
      </validation-provider>
      <validation-provider rules="required|nameKanji:@姓,@名"  tag="div"  name="名" class="hogehoge">
          <p class="inputform_input-title">
            名
          </p>
          <input  v-model="mei" name="mei" type="text" class="hogehoge" placeholder="たろう">
      </validation-provider>

 参考ページ

vee-validate.logaretm.com

NativeScript 動作検証

はじめに

  • 前回、nativescriptの環境を構築したので、実機での動作確認する方法を確認する

実行確認方法

  • 作成したプロジェクト内でtns preview --bundleのコマンドを実行する
$ cd my-app
$ tns preview --bundle

QRコードを読み込む

検証用に利用したコード

<template>
    <Page>
        <ActionBar>
            <Label text="Home"/>
        </ActionBar>
        <GridLayout columns="200, 200" rows="200, 200">
            <Label text="0,0" row="0" col="0" backgroundColor="#43b883"/>
            <Label text="0,1" row="0" col="1" backgroundColor="#1c6b48"/>
            <Label text="1,0" row="1" col="0" backgroundColor="#289062"/>
            <Label text="1,1" row="1" col="1" backgroundColor="#43b883"/>
            <Button text="Tap Me" @tap="onButtonTap" col="0" row="2"/>
            <Label class="info" col="0" row="0">
                <FormattedString>
                    <Span class="fas" text.decode="&#xf135; "/>
                    <Span :text="message"/>
                </FormattedString>                
            </Label>
        </GridLayout>
    </Page>
</template>

<script>
  export default {
    computed: {
      message() {
        return "Blank {N}-Vue app2";
      }
    },
    methods: {
      onButtonTap() {
        console.log("You tapped the button!");
      }
    }
  };
</script>

<style scoped lang="scss">
    @import '~@nativescript/theme/scss/variables/blue';

    // Custom styles
    .fas {
        @include colorize($color: accent);
    }

    .info {
        font-size: 20;
        horizontal-align: center;
        vertical-align: center;
    }
</style>

実機で確認

f:id:PX-WING:20210101074007p:plain

NativeScriptのインストールとプロジェクトの作成

インストール

  • nodejsが入っている状態で下記のコマンドを実行する
$ npm install -g nativescript
  • インストール時に下記の2つの質問を聞かれる。2つともNを指定する
Do you want to help us improve NativeScript by automatically sending anonymous usage statistics? We will not use this information to identify or contact you. You can read our official Privacy Policy at
(匿名の使用統計を自動的に送信することで、NativeScriptの改善を支援しますか?この情報を使用して、お客様を特定したり連絡したりすることはありません。あなたは私たちの公式プライバシーポリシーを読むことができます)
? http://www.telerik.com/company/privacy-policy › (y/N)
bashまたはzshを使用している場合は、コマンドライン補完を有効にできます。
If you are using bash or zsh, you can enable command-line completion.

インストール確認

  • 下記のコマンドが実行できたら正しくインストールされた事になる。
$ nativescript -v
7.1.1
$ tns --version
7.1.1

プロジェクト作成

  • 下記のコマンドでプロジェクトを作成できる
$ tns create hello-world
  • どのスタイルで開発をするか選択する
? First, which style of NativeScript project would you like to use: › - Use arrow-keys. Return to submit.
    Angular
    React
    Vue.js
    Svelte
    Plain TypeScript
❯   Plain JavaScript - Use NativeScript without any framework
  • どのスタイルを選択しても下記のエラーが発生した
Cannot read property 'value' of undefined
  • 下記のコマンドでプロジェクトを作成したら正しくプロジェクトを作成できました。
$ tns create hello-world --template vue

コードの確認

  • vueファイルのファイルが作成されていることを確認できた。
<template>
    <Page>
        <ActionBar>
            <Label text="Home"/>
        </ActionBar>

        <GridLayout>
            <Label class="info">
                <FormattedString>
                    <Span class="fas" text.decode="&#xf135; "/>
                    <Span :text="message"/>
                </FormattedString>
            </Label>
        </GridLayout>
    </Page>
</template>

<script>
  export default {
    computed: {
      message() {
        return "Hello World";
      }
    }
  };
</script>

<style scoped lang="scss">
    @import '~@nativescript/theme/scss/variables/blue';

    // Custom styles
    .fas {
        @include colorize($color: accent);
    }

    .info {
        font-size: 20;
        horizontal-align: center;
        vertical-align: center;
    }
</style>