banner
genkaim

genkaim

Darkmode,yes \q(≧▽≦q) 主题来自@birdgg

velaOS快應用快速入門

cover
查看原文
最近摸索了一下小米 vela 快應用的編寫,寫個教程順便做個歸納 蹭個 hyperOS 的熱度。

本文章使用初學者 畢竟我也是。

概述#

在介紹之前,需要了解一個 vela app 基本的架構。

項目結構#

基本架構:

├── manifest.json
├── app.ux
├── pages
│   ├── index
|   |   ├── index.ux
|   |   ├── index.css
|   |   └── index.js
│   └── detail
|       ├── detail.ux
|       ├── detail.css
|       └── detail.js
├── i18n
|   ├── defaults.json
|   ├── zh-CN.json
|   └── en-US.json
└── common
    ├── style.css
    ├── utils.js
    └── logo.png

其中,

  1. manifest.json記錄 app 的基本信息

    例如以下屬性依次是:

    package: 包名,自己命名。

    name: app 名稱,會在手錶上顯示。

    versionName: 版本名稱,自己命名。

    minPlatformVersion: 最低 api 版本。

    icon: 圖標文件路徑

    {% hideToggle 資源和文件訪問規則 %}

    資源和文件訪問規則

    應用資源路徑分為絕對路徑和相對路徑,以 "/" 開頭的路徑表示絕對路徑,比如 /common/a.png,不以 "/" 開頭的路徑是相對路徑,比如 a.png 和 ../common/a.png 等。

    應用資源文件分為代碼文件和資源文件,代碼文件是指 .js/.css/.ux 等包含代碼的文件,其他文件則是資源文件,這類文件一般只當作數據來使用,比如圖片、視頻等。

    1. 在代碼文件中,導入其他代碼文件時,使用相對路徑,比如:../common/component.ux;
    2. 在代碼文件中,引用資源文件 (如:圖片、視頻等) 時,一般情況下使用相對路徑,比如: ./abc.png;
    3. 當代碼文件需要被導入時,如果導入文件與被導入文件在同一個目錄,被導入文件引用資源文件時可以使用相對路徑,但如果不在同一目錄,必須使用絕對路徑,因為被導入文件編譯時會被複製到導入文件中,編譯後目錄會發生變化。比如 a.css 文件被 b.ux 導入,如果 a.css 與 b.ux 在同一個目錄,a.css 引用資源文件時可以寫相對路徑:abc.png,如果不在同一個目錄,必須寫絕對路徑:/common/abc.png,再比如當 a.ux 文件被 b.ux 文件導入時,如果 a.ux 與 b.ux 在同一個目錄,a.ux 引用資源文件時可以寫相對路徑:a.png,如果不在同一目錄,a.ux 引用資源必須寫絕對路徑:/common/abc.png;
    4. 在 CSS 中,與前端開發一致,使用 url (PATH) 的方式訪問資源文件,如:url (/common/abc.png)。

    {% endhideToggle %}

    features: 調用的接口聲明,有些敏感接口只有聲明才可使用。

    designWidth: 設計稿的尺寸,具體看頁面樣式與佈局

    router: app 中每個頁面的定義。

    {
      "package": "com.genkaim.muyu",
      "name": "電子木魚",
      "versionName": "1.1.0",
      "versionCode": 4,
      "minPlatformVersion": 1000,
      "icon": "/common/logo.png",
      "deviceTypeList": [
        "watch"
      ],
      "features": [
        { "name": "system.storage" },
        { "name": "system.file" },
        { "name": "system.prompt" },
        { "name": "system.vibrator" }
      ],
      "config": {
        "logLevel": "log",
        "designWidth": 600 
      },
      "router": {
        "entry": "pages/index",
        "pages": {
          "pages/index": {
            "component": "index"
          },
          "pages/settings": {
            "component": "settings"
          },
          "pages/confirm": {
            "component": "confirm"
          },
          "pages/about": {
            "component": "about"
          }
        }
      }
    }
    
  2. app.ux為 app 基本的 js 語法例如生命週期中,app 的 onCreate、onDestroy 在這調用

    在下面的代碼中,會在 app 打開時和退出時分別 log “onCreate” 和 "onDestroy"。

    <script>
    export default {
      data: {
          a: 1
      },
      onCreate() { 
    	console.log("onCreate")
      },
      onDestroy() {
       	console.log("onDestroy")
      }
    }
    </script>
    
    
  3. pages下每個文件夾為當前頁面的資源文件,包含.ux等等。

  4. i18n語言文件。

  5. common存放公用資源文件,比如 logo。

生命週期#

這裡借用一下官方的圖。

簡單來說,app 生命週期就是當打開 app 時,一次進行下面步驟,頁面 onShow 前,先經歷 onInit 和 onReady 兩個階段(這在 export default 中是具體的兩個函數)。

當 app 退出時,為 onDestroy。

生命週期

ux文件的基本認識#

下面是一個簡單的.ux文件的內容:

<template>
  <div class="page">
    <text class="title">確定要清除所有功德嗎</text>
    <input class="yes" type="button" value="確認" onclick="clearData" />
    <input class="no" type="button" value="取消" onclick="goBack" />
  </div>
</template>

<script>
  import prompt from '@system.prompt'
  export default {
    goBack(event) {
      router.back()
    },
    clearData(event) {
      router.back()
    }
  }
</script>

<style>
.yes, .no {
  width: 500px;
  height: 150px;
  color: white;
  font-size: 40px;
  font-weight: bold;
  margin-top: 60px;
}
.page {
  position: absolute;
  background-color: black;
  display: flex;
  flex-direction: column;
  display: flex;
  justify-content: center; /* 水平居中 */
  align-items: center; /* 垂直居中 */
}
.back {
  position: absolute;
  left: 0px;
  top: 10px;
  background-color: black;
  color: white;
  font-size: 80px;
  font-weight: bold;
  background-image: url('/common/icon-back.png');
}
.yes {
  margin-top: 50px;
  background-color: rgb(44, 44, 44);
}
.no {
  margin-top: 30px;
}
.title {
  color: white;
  font-size: 50px;
  font-weight: bold;
  top: 5px;
}
</style>

  1. template 標籤 類似於 HTML 的語言,vela 提供多種組件。例如這裡出現兩種不同的組件:

​ text 和 input,分別會被渲染為文本塊和按鈕。

其中:

​ 1.1 class 為自己定義的類名 type 為組件類型,這裡為按鈕。

​ 1.2 button 標籤的 value 值為按鈕上顯示的文字。

​ 1.3 onclick 為事件綁定,意思為滿足” 點按 “這一條件時,會調用指定函數,函數在 export default 定義。

為什麼要在 template 下再包一層 div 呢?

因為 template 下只允許存在一個根節點,必須先創建一個節點,內部再放並列節點。

  1. script 腳本 支持 ES5 / ES6 語法,這裡的 export default 中,引用了一個模塊來實現返回的功能。
  2. **style 層疊樣式表:** 用選擇器選擇並設置屬性即可。

簡單示例:電子木魚基本功能實現#

基本功能:#

  1. 頁面元素:電子木魚(圖片),顯示功德數值功能,” 功德 + 1“動畫。

  2. 實現點按木魚計數功能。

muyu

頁面資源:單擊下載

頁面佈局#

  1. 放置木魚圖片可以用 img 組件或者 css 實現,這裡使用的前者。

​ 因為需要實現點按反饋的功能,所以需要綁定 onclick 事件。

      <img class="muyu" src="muyu.png" onclick="rpPlusPlus()" />
  1. 計數功能可以通過 text 組件顯示,這裡注意,動態的數據(變量)可以通過大括號的方式顯示,例如下面的代碼可以實現顯示功德計數(變量在下文)。
      <text class="cnt" >功德 {{localCnt}}</text>
  1. 而動畫的實現則是通過 text 組件 +if 條件渲染+ 綁定動畫(下文)實現的。

if 條件渲染指 if 內表達式的值為 true 時,會渲染當前元素。

    <text if="{{plus}}" class="showPlus">功德+1</text>

腳本#

  1. 數據處理:

​ 在上文中,需要幾個變量:localCnt (int) 用於計數功德,plus (bool) 用於指示消息的顯示。

​ 定義變量需要這麼寫:

​ 其中,

屬性類型描述
publicObject頁面級組件的數據模型,影響傳入數據的覆蓋機制:public 內定義的屬性允許被傳入的數據覆蓋,如果外部傳入數據的某個屬性未被聲明,在 public 中不會新增這個屬性
protectedObject頁面級組件的數據模型,影響傳入數據的覆蓋機制:protected 內定義的屬性,允許被應用內部頁面請求傳遞的數據覆蓋,不允許被應用外部請求傳遞的數據覆蓋
privateObject頁面級組件的數據模型,影響傳入數據的覆蓋機制:private 內定義的屬性不允許被覆蓋
  <script>
  export default {
    public: {
      localCnt: 0,
      plus: false
    }
  }
  </script>
  1. 在上文中,需要定義 rpPlusPlus 函數實現功德 + 1

​ 其中:

​ 通過 this.Name 訪問當前頁面數據對象。

​ 並設置 plus 為 true,在 400ms 後設置為 false,即讓其顯示 400ms,因為它綁定了動畫(下文),看起來的效果就是文字向上移動然後消失。

  rpPlusPlus(event) {
      this.plus = true;
      this.localCnt++;
      setTimeout(() => {
          this.plus = false;
      }, 400);
    }

css#

  1. 綁定動畫:

​ 上文已經定義了 class 為 showPlus,所以通過.showPlus選擇元素:

 .showPlus {
    position: absolute;/*定位*/
    right: 70px;
    top: 210px;
    color: white;/*字體顏色*/
    font-weight: bold;/*字體粗細*/
    animation-name: moveUp;/*字體綁定動畫*/
    animation-delay: 0s;/*動畫延遲時間*/
    animation-duration: 200ms;/*動畫持續時間*/
    animation-iteration-count: 1;/*動畫持續次數*/
  }
  @keyframes moveUp {/*定義動畫*/
    0% {
      transform: translateY(0);
    }
    99% {
      transform: translateY(-40px);
    }
    100% {
      visibility: hidden;
    }
  }

  1. cnt、page 和 muyu 元素:
 .muyu {
    position: absolute;/*定位*/
    height: 350px;
    top: 250px;
    background-color: transparent;/*背景顏色*/
    width: 450px;/*大小*/
  }
  .cnt {
    position: absolute;
    bottom: 100px;/*定位*/
    font-size: 70px;/*字體大小*/
    color: white;/*字體顏色*/
  }
   .page {
    background-color: black;/*背景顏色*/
    display: flex;
    flex-direction: column;
    justify-content: center; /* 水平居中 */
    align-items: center; /* 垂直居中 */
    height: 100%; /* 確保容器佔滿整個視窗 */
  }

完整代碼:

<template>
  <div class="page">
    <img class="muyu" src="muyu.png" onclick="rpPlusPlus()" />
    <text if="{{plus}}" class="showPlus">功德+1</text>
    <text class="cnt" >功德 {{localCnt}}</text>
  </div>
</template>

<script>
  export default {
    public: {
      localCnt: 0,
      plus: false
    },
  rpPlusPlus(event) {
      this.plus = true;
      this.localCnt++;
      setTimeout(() => {
          this.plus = false;
      }, 400);
    }
  }
</script>

<style>
   .page {
    background-color: black;/*背景顏色*/
    display: flex;
    flex-direction: column;
    justify-content: center; /* 水平居中 */
    align-items: center; /* 垂直居中 */
    height: 100%; /* 確保容器佔滿整個視窗 */
  }
 .showPlus {
    position: absolute;/*定位*/
    right: 70px;
    top: 210px;
    color: white;/*字體顏色*/
    font-weight: bold;/*字體粗細*/
    animation-name: moveUp;/*字體綁定動畫*/
    animation-delay: 0s;/*動畫延遲時間*/
    animation-duration: 200ms;/*動畫持續時間*/
    animation-iteration-count: 1;/*動畫持續次數*/
  }
  @keyframes moveUp {/*定義動畫*/
    0% {
      transform: translateY(0);
    }
    99% {
      transform: translateY(-40px);
    }
    100% {
      visibility: hidden;
    }
  }
  .muyu {
    position: absolute;/*定位*/
    height: 350px;
    top: 250px;
    background-color: transparent;/*背景顏色*/
    width: 450px;/*大小*/
  }
  .cnt {
    font-size: 70px;/*字體大小*/
    bottom: 100px;/*定位*/
    position: absolute;
    color: white;
  }
</style>

如有錯誤,歡迎指出。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。