nuxtjs + vuetifyjs 

安裝 VeeValidate

$ npm install vee-validate --save

nuxt.config.js

  plugins: [
    ...
    '~/plugins/veeValidate'
  ],

plugins\veeValidate.js

import Vue from 'vue'
import { ValidationProviderlocalize } from 'vee-validate/dist/vee-validate.full'
import zh from 'vee-validate/dist/locale/zh_TW.json'
 
// 載入所有檢核條件並指定語系
Vue.component('ValidationProvider'ValidationProvider)
localize('zh_TW'zh)

 

注意 : 預設無法在TypeScript中導入JSON文件,確保有以下設定

jsconfig.json

{
  "compilerOptions": {
    ...
    "resolveJsonModule"true,
    "esModuleInterop"true
  },
}

 

文章標籤

vivian 發表在 痞客邦 留言(0) 人氣()

1. setSmallIcon() 只可以用白色透明組成的圖片,漸層也不行,不然會變成一塊銀灰色的圖

2. 最好使用 android studio (File -> new -> image asset ) 產生各種 Size 的圖,Icon Type 要選 Notification Icons,超方便低

3. 圖示都白白的不好看,用 setColor() 設定圖示顏色,真心覺得多個顏色真的差很多

   a) Android < N 使用此作為圖標的背景顏色。

   b) Android >= N 使用它來為圖標和應用程序名稱著色。

4. 強烈建議一定要在 app/src/main/AndroidManifest.xml 設定 default 值,才不會遇到自動生成的通知,圖示是一塊銀灰色的,或是沒有顏色,看起來就像是BUG對吧~
<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorAccent" />

 

文章標籤

vivian 發表在 痞客邦 留言(0) 人氣()

說到 APP 推播,早期真的比較麻煩,不管是對 APP 端還是後台都是很複雜的工作
由於 APP 端,iOS 和 Android 各走各的路,後台要針對 iOS 和 Android 做設置,還要保存管理載具的 Token
才能做到對所有載具廣播訊息,也可以針對會員載具發送私人訊息

Android 部分早期用 GCM,說實在,改用 FCM (Firebase Cloud Messaging) 真的方便多了
而且 iOS 也可以用 FCM ,麻煩事都交給 Firebase,對後台而言真是個好消息

在 Android 這邊超簡單,以下幾個的步驟就搞定了

1. 下載 google-services.json 檔案移到 Android 應用程式的模組根目錄中(就是 app 資料夾下面)

   a) 建立一個 Firebase 專案,新增 Android 應用程式,註冊完成後,就可以下載  google-services.json

   b) 已有專案和Android 應用程式,就到 [專案設定] 找 Android 應用程式的 [下載最新的設定檔],就可以下載  google-services.json

2. 在模組根目錄中 app/build.gradle 加

apply plugin: 'com.android.application'

android {

  // ...

}

dependencies {

  // ...

  implementation 'com.google.firebase:firebase-messaging:19.0.1'

}

3.  在 app/src/main/AndroidManifest.xml 加

<service
    android:name=".MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

<!-- Set custom default icon. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />

<!-- Set color used with incoming notification messages.  -->
<!-- 不同的Android版本以不同的方式使用此設置:Android < N 使用此作為圖標的背景顏色。 Android >= N 使用它來為圖標和應用程序名稱著色。 -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorAccent" />

<!-- Set default channel -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_channel_id"
    android:value="@string/default_notification_channel_id" />

4. 建立 MyFirebaseMessagingService.java

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    private static final String TAG = "MyFirebaseMsgService";

    /**
     * Called when message is received.
     *
     * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
     */
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

        super.onMessageReceived(remoteMessage);

        //收到 FCM 訊息分為 Notification 和 Data 兩種,取得方式如下

        //Data messages
        String title = remoteMessage.getData().get("title");
        String body = remoteMessage.getData().get("body");
        String badge = remoteMessage.getData().get("badge");
        int badgeCount = 0;

        if (badge.length() > 0 && TextUtils.isDigitsOnly(badge)) {
            badgeCount = Integer.parseInt(badge);
        }

        //Notification messages
        //String title = remoteMessage.getNotification().getTitle();
        //String body = remoteMessage.getNotification().getBody();
        
        //根據收到 FCM 訊息生成自己的通知
        sendNotification(title, body, badgeCount);

    }


    /**
     * Create and show a simple notification containing the received FCM message.
     *
     * @param messageTitle FCM message Title received.
     * @param messageBody FCM message body received.
     * @param badgeCount
     */
    private void sendNotification(String messageTitle, String messageBody, String badgeCount) {

        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);

        String channelId = getString(R.string.default_notification_channel_id);
        Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder =
                new NotificationCompat.Builder(this, channelId)
                        .setSmallIcon(R.drawable.ic_stat_ic_notification)
                        .setContentTitle(messageTitle)
                        .setContentText(messageBody)
                        .setAutoCancel(true)
                        .setSound(defaultSoundUri)
                        .setContentIntent(pendingIntent)//效果:按下訊息,打開APP
                        .setNumber(badgeCount);


        //設置訊息數量(ShortcutBadger 會在部分廠牌手機的圖示上顯示數字)
        ShortcutBadger.applyCount(context, badgeCount); //for 1.1.4+

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        //Android 8.0 Oreo 一定要實作 通知頻道(Notification channels)
        //Android 7.1或之前的舊版本Android手機中執行,它會以舊的通知方式展示,也就是沒有通知頻道的效果。
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channelId,
                    "Channel human readable title",
                    NotificationManager.IMPORTANCE_DEFAULT);
            notificationManager.createNotificationChannel(channel);
        }

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }
}


Firebase 官方文件:  https://firebase.google.com/docs/cloud-messaging/android/client?authuser=0


完成以上步驟,基本上已經可以收到推播訊息了

值得注意的是

訊息發送端(後台)使用的推播訊息類型分為 Data messages 和 Notification messages 兩種

1. Data messages : 
    a) 無論 APP 處於 [前台執行] 還是 [背景執行],都會呼叫 onMessageReceived()
    b) 傳統的 GCM 就是用這種 

2. Notification messages : 
    a) 若 APP 處於 [前台執行] 才會呼叫 onMessageReceived()
    b) 若 APP 處於 [背景執行] 會顯示自動生成的通知。按下訊息,就會打開應用程式(真貼心!)

所以訊息發送端(後台)使用 Notification messages 時,APP 是處於 [背景執行] 還是 [前台執行] 狀態,通知是由不同對象處理的
這時記得去 AndroidManifest.xml 設定 FCM 用的 default icon , color , channel id ,就是跟 onMessageReceived() 設置的一樣就可以囉~

但是問題來了,如果在 onMessageReceived() 自訂訊息顯示樣式不只是 icon , color , channel id 和按下訊息就會打開應用程式這些呢!
例如: 按下訊息後,跳去某個指定畫面或是需要設置 Badge Count ...

這時,訊息發送端(後台)需強迫使用 Data messages,也就是不管 APP 是處於什麼狀態,保證呼叫 onMessageReceived() 生成自訂的通知樣式

文章標籤

vivian 發表在 痞客邦 留言(0) 人氣()

經過這麼多年,早已經忘記還有這個地方

看著以前寫的技術文章,很陌生(真的是我寫的嗎?),那些生活瑣事的紀錄,倒是讓我想起不少往事

回想這幾年,經歷很多,也平淡很多,現在的我,似乎不像年輕的我心中期許的我

以前的我一定沒想到我會搬到台中

人生真的意外很多,每個當下,每個決定,造就現在的自己

恩恩~我想我不是不滿意,只是還在習慣現在的自己

 

vivian 發表在 痞客邦 留言(0) 人氣()

自定物件 - 是可變的,由建立空白物件後,再加入功能

建立自定物件的方法(1)物件實字語法 (2)自訂建構式

物件實字語法 - var dog = { name:"名字", getname:function{ return name;} };

 

避免用物件建構式 new Object() 建立自己的物件,原因有...

1. 效能較差

2. Object 建構式可傳一個參數,會影響產生出物件的型別,如: new Object(3) => Number

 

自訂建構式 ( 命名慣例 - 手字母大寫 )

var Person = function ( name ) {

    //var this = Object.create(Person.prototype); //背後的動作

    this.name = name;

    this.say = function () {

        return "I am " + this.name ;

    };

    //return this; //背後的動作

    //如果沒有 return 任一物件 , 背後會自動 return this , 如果 return 非物件 ( string , number , boolean ... ) 雖然不會發生錯誤 , 還是會 return this;

};

var vivian = new Person ("vivian"); //用自定建構式建立自定物件

vivian.say; // I am vivian

使用自定建構式一定要用 new MyObject() , 如果忘記 new , 在建構式中的 this 就會指向全域物件

也就是在瀏覽器中, this 就指向 window , 為了避免就種問題 , 可以改成

var Person = function ( name ) {

    var that = {};

    that.name = name;

    that.say = function () {

        return "I am " + that.name ;

    };

    return that;

    //that 只是慣例 , 也可以用 self , me ...

};

還是有缺點, 這樣會失去與原型之間的連結

最好(建議)的方式

function Person ( arg ) {

    if ( ! ( this instanceof arguments.callee ) ) { // 當函式被呼叫時 , 會產生 arguments

        return new arguments.callee( arg );

    }

    //意思是 , 如果 this 的實體不是被呼叫者 ( 呼叫者忘了 new) , 就自動 new

    //做點什麼事...

}

 

vivian 發表在 痞客邦 留言(0) 人氣()

再認真的人,也比不上沉迷的人

當沉迷某件事,在別人眼裡,做的好不好已經不重要了

重要的是過程得到的快樂

認真的人在過程中需要回饋,不然就會感到挫折

對沉迷的人而言,過程就是回饋,只要可以繼續做就會開心

vivian 發表在 痞客邦 留言(0) 人氣()

console.log( parseInt( "017" ) ); // 15
console.log( parseInt( "08" ) ); // 0

為什麼?? 因為 parseInt 的傳入值開頭是 "0" 就會當成 8 進位處理 ("0x" 是 16 進位)

"017" >>> 8 + 7 = 15
"08" >>> 因為超過 8 進位範圍 , 結果為 0

為了避免矛盾和意外的結果,最好指定基數參數。

console.log( parseInt( "017" , 10 ) ); // 17

或是改用以下方法將字串變數字 , 而且效能優於 parseInt()

+"08" // 結果是 8
Number("08") // 8

vivian 發表在 痞客邦 留言(0) 人氣()

少用 eval(),使用 eval() 有安全疑慮,因為被執行的代碼(例如從網絡來)可能已被篡改。

同樣重要的是要記住,給 setInterval()、setTimeout() 和 Function() 構造函數傳遞字符串,大部分情況下,與使用 eval() 是類似的,因此要避免。在幕後,JavaScript 仍需要評估和執行你給程序傳遞的字符串:

// 反面示例
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);

// 更好的
setTimeout(myFunc, 1000);
setTimeout(function () {
   myFunc(1, 2, 3);
}, 1000);

若在 eval() 中宣告變數 , 會視為全域變數 , 建議改用 new Function()

eval( "var un = 1; console.log(un);"); // logs "1" <<< 不建議

new Function("var deux = 2; console.log(deux);")(); // logs "2"

(function () {
   eval( "var trois = 3; console.log(trois);");
}()); // logs "3"

console.log(typeof un); // number
console.log(typeof deux); // "undefined"
console.log(typeof trois); // "undefined"

使用 eval() 可以直接使用外部的變數,而使用 Function() 不行

(function () {
   var local = 1;
   eval("local = 3; console.log(local)"); // logs "3"
   console.log(local); // logs "3"
   Function("console.log(typeof local);")(); // logs undefined
}());

vivian 發表在 痞客邦 留言(0) 人氣()

JavaScript的變量在比較的時候會隱式類型轉換。這就是為什麼一些諸如:false == 0 或 「」 == 0 返回的結果是true。為避免引起混亂的隱含類型轉換,在你比較值和表達式類型的時候始終使用===和!==操作符。

var zero = 0;
if (zero === false) {
// 不執行,因為zero為0, 而不是false
}

// 反面示例
if (zero == false) {
// 執行了...
}

還有另外一種思想觀點認為==就足夠了===是多餘的。
例如,當你使用typeof你就知道它會返回一個字符串,所以沒有使用嚴格相等的理由。
然而,JSLint要求嚴格相等,它使代碼看上去更有一致性,可以降低代碼閱讀時的精力消耗。
(「==是故意的還是一個疏漏?」)

vivian 發表在 痞客邦 留言(0) 人氣()

每個JavaScript環境有一個全局對象,當你在任意的函數外面使用 this 的時候可以訪問到。你創建的每一個變數都成了這個全局對象的屬性。在瀏覽器中,方便起見,該全局對象有個附加屬性叫做window,此window(通常)指向該全局對象本身。下面的代碼片段顯示了如何在瀏覽器環境中創建和訪問的全局變量:

var myglobal = "hello";//宣告變數,而 window.myglobal , window["myglobal"] , this.myglobal 都是指 myglobal


JavaScript通過函數管理作用域。在函數內宣告的變數只可在這個函數內使用,函數外面不可用,反之,全域變數就是在任何函數外面宣告的或是 在任何地方未宣告直接簡單使用的。當程序的兩個不同部分定義同名但不同作用的全局變量的時候,命名衝突在所難免,所以應該盡量少用全域變數。這裡要注意, 只有在函數內用 var 宣告才是區域變數,其餘的都會當做全域變數

var aa = 1; // 全域變數
bb = 2; // 全域變數 , 不推薦
function () {
   var cc = 3; //區域變數
   dd = 4; // 全域變數 , 不推薦
}


常犯的錯誤

function foo() {
   var a = b = 0; // 等同於 var a = (b = 0);
   // ...
}

這樣的寫法 , 無疑 a 是區域變數 , 但 b 沒有被宣告 , 所以 b 是全域變數 , 跟想像中不一樣吧!!
下面的寫法就好多了

function foo() {
   var a, b;
   a = b = 0; // 兩個都是區域變數
}


另一個疑問 - 全域變數有沒有宣告都一樣嗎?

隱式全域變數和明確定義的全域變數間有些小的差異,就是通過 delete 指令讓變量未定義的能力。

  • 通過 var 創建的全局變量(任何函數之外的程序中創建)是不能被刪除的。
  • 無 var 創建的隱式全局變量(無視是否在函數中創建)是能被刪除的。


這表明,在技術上,隱式全域變數並不是真正的全域變數,但它們是全局對象的屬性。屬性是可以通過 delete 指令刪除的,而變數是不能刪除的。

// 定義三個全局變量
var global_var = 1;
global_novar = 2; //  全域變數 , 不推薦
(function () {
   global_fromfunc = 3; //  全域變數 , 不推薦
}());

// 是否為全局對象的屬性
console.log("global_var : " + Object.prototype.hasOwnProperty.call(this, "global_var"));// true
console.log("global_novar : " + Object.prototype.hasOwnProperty.call(this, "global_novar"));// true
console.log("global_fromfunc : " + Object.prototype.hasOwnProperty.call(this, "global_fromfunc"));// true

// 試圖刪除
console.log("delete global_var : " + delete global_var); // false
console.log("delete global_novar : " + delete global_novar); // true
console.log("delete global_fromfunc : " + delete global_fromfunc); // true

// 測試該刪除
console.log("typeof global_var : " + typeof global_var); // "number"
console.log("typeof global_novar : " + typeof global_novar); // "undefined"
console.log("typeof global_fromfunc : " + typeof global_fromfunc); // "undefined"

vivian 發表在 痞客邦 留言(0) 人氣()

一般會用 for-in 取得物件的屬性,但是物件有函數的話就會造成問題了

這時可以用hasOwnProperty()過濾原型屬性

// the object
var man = {
    hands: 2,
    legs: 2,
    heads: 1
};
// somewhere else in the code
// a method was added to all objects
if (typeof Object.prototype.clone === "undefined") {
    Object.prototype.clone = function () {};
}

for (var key in man) {
   if (man.hasOwnProperty(key)) { // 過濾
      console.log(key, ":", man[key]);
   }
}


/* 控制台顯示結果
hands : 2
legs : 2
heads : 1
*/


不用hasOwnProperty()過濾的話

for (var key in man) {
   console.log(key, ":", man[key]);
}


/*控制台顯示結果
hands : 2
legs : 2
heads : 1
clone: function()
*/


另外一種使用方法如下:

for (var key in man) {
    if (Object.prototype.hasOwnProperty.call(man, key)) { // filter
        console.log(key, ":", man[key]);
    }
}

這樣寫的好處是可以防止man重新定義了hasOwnProperty方法導致的衝突
如果不想寫這麼長的一串,你也可以這樣:


var key, hasOwn = Object.prototype.hasOwnProperty;
for (key in man) {
    if (hasOwn.call(man, key)) { // filter
        console.log(key, ":", man[key]);
    }
}

 

 

 

vivian 發表在 痞客邦 留言(0) 人氣()

變數/函式宣告將被提至該生命區塊的開端(hoisting)

var str = "global"; //全域變數
function f () { //全域函式
    return "global function";
}

function hoistMe(){
    alert(str); //undefined
    alert(f()); //local function
    var str = "local"; //宣告 hoist
    function f(){ //宣告&實做 都 hoist
        return "local function";
    }
}

hoistMe();


你可能會以為第一個alert彈出的是"global",第二個彈出"global function"

事實上...第一個alert會彈出"undefined",第二個彈出"local function"
是因為變數/函式宣告將被提至該生命區塊的開端,實際運作如下:

function hoistMe(){

    var str;//宣告 hoist
    function f(){ //宣告&實做 都 hoist
        return "local function";
    }
    
    alert(str); //undefined
    alert(f()); //local function
    
    str = "local";
    // f() hoist 到上面去了/...
}

因此,為了避免這種混亂,最好是預先宣告你想使用的全部變數/函式。

vivian 發表在 痞客邦 留言(0) 人氣()

原來現在大部分的瀏覽器都支援console.log(),還有其他幫助開發者除錯的功能,以後javascript除錯比較方便了^^

怎麼把瀏覽器的除錯工具叫出來咧??

IE9:工具列->[工具]->[F12開發者工具]或直接按F12

FireFox:工具列->[網頁開發者]

Chrome:工具列->[工具]->[開發者工具]或網頁右鍵->[檢查元素]

 

在javascript中可以直接使用console.log()

console.log("ABC");

vivian 發表在 痞客邦 留言(0) 人氣()

看了 套件 mchain.js 的原始碼

其中開頭結尾看不懂以及為什麼在 script 中可以直接使用 mchain

所以了解一下這是什麼樣的寫法...

( function(_global){
  //程式碼
  _global.mchain = new _global.mchainClass();

} ) ( this );
 
  這裡的 this 其實會是 window 物件
  上面的程式碼就是在 window 物件加一個 mchain 屬性
  然後 在 script 中可以直接使用 mchain (等於是 window.mchain)

 

簡單說...

JavaScript 可以直接用一組小括號 "()" 包覆一個匿名函式,然後後面再接一組小括號 "()" 表示呼叫這個匿名函式

而第二組小括號中就可以放置這個匿名函式的參數

(
  匿名函式
) (匿名函式的參數) //網頁 load 時 就執行

var  a1 = "123" , a2 = "456";
(function(b1,b2){
  alert("我在裡面:"+b1+b2) 
})(a1,a2);
alert("我在外面:"+a1+a2)

另外~

因為這種寫法很特殊,用的是小括號 "()" 開始的

如果上一行程式碼沒有分號 ";" 結尾就會出問題,難保引用一些縮減後套件,沒有最後的分號 ";"

所以養成小習慣,前面多加一個分號 ";" ,會安全一點

;(
  匿名函式
) (匿名函式的參數) //網頁 load 時 就執行

 

 

vivian 發表在 痞客邦 留言(0) 人氣()

 

積木 (國)
作曲 /監製︰陳小霞 作詞︰姚若龍 編曲︰Keith Chan

先是奶精沒了 後來糖也沒了 就開始習慣 喝黑咖啡了
想像力豐富 是好還是壞呢 怎麼覺得苦澀有點甜甜的

先是沉默長了 後來吻也停了 就慢慢一邊愛一邊哭著
好朋友太多 是好還是壞呢 怎麼說的全是我不想聽的

我們的關係 多像積木啊 不堪一擊 卻又千變萬化
用盡了心思蓋得多像家 下一秒鐘 也可能倒塌

幸福的期待 真像積木啊 多會幻想 就能堆多漂亮
可惜 感情從來就不聽話 從愛出發 卻通往複雜

vivian 發表在 痞客邦 留言(0) 人氣()

那天吹著涼涼的海風,耳邊就是寶貝

vivian 發表在 痞客邦 留言(0) 人氣()

「花樣年華」

花樣年華 

身處遙遠的異國,周慕雲仍無法忘記過去與蘇麗珍之間的種種。如果當天她真的答應跟他走,他們現在會不會還在一起?抑或註定分離,各分東西?

vivian 發表在 痞客邦 留言(0) 人氣()

「阿飛正傳」

阿飛正傳  

一開始就讓我很著迷

「十六號,四月十六號。一九六零年四月十六號下午三點之前的一分鐘你和我在一起,因為你我會記住這一分鐘。從現在開始我們就是一分鐘的朋友,這是事實,你改變不了,因為已經過去了。」

哇~這種把妹招數,超殺的~

他自比為「無足鳥」,有一種小鳥生下來就沒有腳,它們一生都在飛翔,無法著地,它們一生中唯一著地的一次就是它們死亡的時候

他對愛情瀟灑自若,「我這生都不知道還會喜歡多少個女人,不到最後我是不知哪個才是我最喜歡的」

vivian 發表在 痞客邦 留言(0) 人氣()

因為在人群中,多看了你一眼,再也忘不了你

我一直在你身旁,沒有走遠

是緣分也好,是巧合也好

希望現在你能明白,這是我的真心~

vivian 發表在 痞客邦 留言(0) 人氣()

甜蜜好聽,我都相信

vivian 發表在 痞客邦 留言(0) 人氣()

1 2