後端開發者的Vue學習之路(二)

来源:https://www.cnblogs.com/progor/archive/2019/01/20/10293884.html
-Advertisement-
Play Games

[toc] 首發日期:2019 01 20 上篇內容回顧: 上篇內容講了 Vue的介紹:優點,MVVM Vue的靜態導入與安裝,以及hello world 實例可定義的內容:el,data,methods,生命周期鉤子(包括計算屬性,偵聽器也是可以定義在實例中的) 計算屬性 偵聽器 數據綁定 v m ...


目錄

首發日期:2019-01-20


上篇內容回顧:

上篇內容講了

  • Vue的介紹:優點,MVVM
  • Vue的靜態導入與安裝,以及hello world
  • 實例可定義的內容:el,data,methods,生命周期鉤子(包括計算屬性,偵聽器也是可以定義在實例中的)
  • 計算屬性
  • 偵聽器

數據綁定


v-model可以把某個實例的數據與元素的數據綁定。這樣當其中一份數據發生變化時,與之綁定的數據也會發生變化。比如:把示例中的數據(在頁面中用{{}}顯示出來)與輸入框的數據綁定


表單輸入框有value這個值,在表單輸入框里使用v-model會把表單輸入框與實例的數據進行“智能”綁定(為什麼說智能,因為有些輸入框的數據是value屬性,有些不是)。


表單輸入框綁定

你可以用 v-model 指令在表單 <input><textarea><select> 元素上創建雙向數據綁定。它會根據控制項類型自動選取正確的方法來更新元素。儘管有些神奇,但 v-model 本質上不過是語法糖。它負責監聽用戶的輸入事件以更新數據,並對一些極端場景進行一些特殊處理。

v-model 會忽略所有表單元素的 value、checked、selected 特性的初始值而總是將 Vue 實例的數據作為數據來源。如果希望輸入框有初始值,你應該在組件的 data 選項中聲明初始值。


單行文本輸入框

會把單行文本輸入框的value綁定到實例的數據中,因為value的數據就是單行文本輸入框的數據。

    <body>
      <div id="vm">
        <input v-model="message" placeholder="edit me">
        <p>Message is: {{ message }}</p>
        <input type="text" v-bind:value="message">
        <!-- 不能使用普通的value=message,不然會識別不成正確的message,所以第三行用了v-bind -->
      </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var vm = new Vue({
              el: '#vm',
              data:{
                message:"hello world!"
              }
        })
    </script>


多行文本輸入框

會把多行文本元素內的文本綁定到實例的數據中,因為多行文本元素內的文本就是單行文本輸入框的數據。

<body>
  <div id="vm">
    <span>Multiline message is:</span>
    <p style="white-space: pre-line;">{{ message }}</p>
    <br>
    <textarea v-model="message" placeholder="add multiple lines"></textarea>
  </div>
</body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var vm = new Vue({
      el: '#vm',
      data:{
        message:"hello world!"
      }
})
</script>

在文本區域<textarea></textarea>使用插值表達式{{}}來插值並不會生效,應該用 v-model 來代替。


覆選框checkbox

單個覆選框:覆選框也有value,不給定value值的時候value預設是布爾值(被勾選是true,沒有勾選是false)

<body>
  <div id="vm">
    <input type="checkbox" id="checkbox" v-model="checked">
    <label for="checkbox">{{ checked }}</label>
  </div>
</body>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var vm = new Vue({
      el: '#vm',
      data:{
        checked:false
      }
})
</script>


多個覆選框:指定了value之後,實例綁定的數據是對應的value值【由於是多個覆選框綁定到同一個實例上,所以這個實例數據應該是數組類型的。】

<body>
  <div id='example-3'>
  <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
  <label for="jack">Jack</label>
  <input type="checkbox" id="john" value="John" v-model="checkedNames">
  <label for="john">John</label>
  <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
  <label for="mike">Mike</label>
  <br>
  <span>Checked names: {{ checkedNames }}</span>
</div>
</body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var vm = new Vue({
      el: '#example-3',
      data:{
        checkedNames:[] // 值為多個input的value的數組
      }
})
</script>


單選框radio

radio也有value,所以與實例綁定的數據就是value的值

<body>
  <div id="example-4">
    <input type="radio" id="one" value="One" v-model="picked">
    <label for="one">One</label>
    <br>
    <input type="radio" id="two" value="Two" v-model="picked">
    <label for="two">Two</label>
    <br>
    <span>Picked: {{ picked }}</span>
  </div>
</body>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var vm = new Vue({
  el: '#example-4',
  data: {
    picked: ''// picked的值為input的value值
  }
})
</script>


選擇框select

select的值來源與子標簽option。當select 的option沒有value值的時候,預設綁定的數據為option元素的文本值;當有value時,預設綁定的數據為option元素的value值。

    <body>
      <div id="example-5">
        <select v-model="selected">
          <option disabled value="">請選擇</option>
          <option value ='a'>A</option> <!-- 這個用來測試有value的情況-->
          <option>B</option>
          <option>C</option>
        </select>
        <span>Selected: {{ selected }}</span>
      </div>
    </body>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        var vm = new Vue({
      el: '#example-5',
      data: {
        selected: "" // selected 的值為 a/B/C
      }
    })
    </script>


select框允許多選時:那麼這時候實例的數據應該是一個數組,數組元素是option的文本值(無value時)或value

<body>
  <div id="example-5">
    <select multiple style="width: 50px;" v-model="selected">
      <option disabled value="">請選擇</option>
      <option value='a'>A</option>
      <option>B</option>
      <option>C</option>
    </select>
    <span>Selected: {{ selected }}</span>
  </div>
</body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var vm = new Vue({
  el: '#example-5',
  data: {
    selected: [] // 全選時: [ "a", "B", "C" ]
  }
})
</script>


數據綁定的修飾符

.lazy

在預設情況下,v-model 在每次 input 事件觸發後將輸入框的值與數據進行同步 (除了輸入法組合文字時,這時候數據還沒完全輸入到輸入框中)。
你可以添加 lazy 修飾符,從而轉變為使用 change 事件進行同步:

<!-- 在“change”時而非“input”時更新 -->
<input v-model.lazy="msg" >


.number

如果想自動將用戶的輸入值轉為數值類型,可以給 v-model 添加 number 修飾符:

<input v-model.number="age" type="number">
這通常很有用,因為即使在 type="number" 時,HTML 輸入元素的值也總會返回字元串。如果這個值無法被 parseFloat() 解析,則會返回原始的值。


.trim

如果要自動過濾用戶輸入的首尾空白字元,可以給 v-model 添加 trim 修飾符:

<input v-model.trim="msg">



樣式綁定


我們平時也可以使用class='xxx'或style='xxx:xxxx'來綁定樣式。為什麼要選擇轉去使用Vue的樣式綁定?因為在Vue中class或style也可以定義成數據,你可能會想要“發生XXX情況後,某元素變成某樣式”,這個時候你需要定義“行為”來切換樣式了,而這時候如果你使用Vue自己的樣式切換會比較方便(因為首先你要獲取某個元素的class屬性,然後再重新賦值,這個操作可能需要自己定義一些dom操作)。


class綁定

使用v-bind:class來進行class綁定


對象語法:

格式一:傳入的數據格式是{ class名: 布爾數據,.... },布爾數據影響class是否出現在元素的class屬性中。

        <div id="app">
            <div v-bind:class="{ active: isActive }">haha</div>
        </div>
        <!--
       var app = new Vue({
                    el: '#app',
                    data: {
                        isActive: true  // 影響著active這個class是否出現
                    },
                })
         -->
         <!--
            <style>
                .active {
                    color: red;
                }
            </style>
          -->

格式一:傳入的數據格式是對象名,對象的數據格式是{ class名: 布爾數據,.... },布爾值影響class是否出現在元素的class屬性中。

        <div id="app">
            <div v-bind:class="classObject">haha</div>
        </div>
        <!--
       var app = new Vue({
                    el: '#app',
                    data: {
                        classObject: {
                            active: true
                        }
                    },
                })
         -->
         <!--
            <style>
                .active {
                    color: red;
                }
            </style>
          -->


數組語法:

格式一:

        <div id="app">
            <div v-bind:class="[activeClass]">haha</div>
        </div>
        <!--
       var app = new Vue({
                    el: '#app',
                    data: {
                        activeClass:'active'
                    },
                })
         -->
         <!--
            <style>
                .active {
                    color: red;
                }
            </style>
          -->

style綁定

使用v-bind:style來進行style綁定

對象語法:

格式一:傳入的數據格式是{ 樣式名: 實例數據名(樣式值), .... }

        <div id="app">
            <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">haha</div>
        </div>
        <!--
       var app = new Vue({
                    el: '#app',
                    data: {
                        activeColor:'red',
                        fontSize: 14
                    },
                })
         -->

格式二:傳入的數據是一個對象,對象的數據格式是{ 樣式名: 樣式值, .... }

        <div id="app">
            <div v-bind:style="styleObject">haha</div>
        </div>
        <!--
       var app = new Vue({
                    el: '#app',
                    data: {
                        styleObject: {
                            color:'red',
                            fontSize: "14px"
                        }
                    },
                })
         -->


數組語法:

傳入的數據是一個數組,數組的元素是多個對象,對象的數據格式是{ 樣式名: 樣式值, .... }

        <div id="app">
            <div v-bind:style="[styleObject]">haha</div>
        </div>
        <!--
       var app = new Vue({
                    el: '#app',
                    data: {
                        styleObject: {
                            color:'red',
                            fontSize: "14px"
                        }
                    },
                })
         -->

補充:

  • 當 v-bind:style 使用需要添加瀏覽器引擎首碼的 CSS 屬性時,如 transform,Vue.js 會自動偵測並添加相應的首碼。



事件

綁定事件

可以使用v-on:事件類型='函數名'來綁定事件。

        <div id="app">
            <button v-on:click="myclick">點擊事件</button>
            <!-- on:後面跟事件類型 -->
        </div>
        <!-- 
               var app = new Vue({
                  el: '#app',
                  methods: { // 註意:是在methods裡面定義函數
                    myclick:function (){
                        alert("message")
                    }
                  }
                })
        -->


事件修飾符

事件修飾符可以影響事件的運行,事件修飾符使用.跟在事件類型的後面,例如:<a v-on:click.stop="doThis"></a>

  • .prevent 修飾符告訴 v-on 指令對於觸發的事件,調用 event.preventDefault()來阻止預設的元素行為,例如預設點擊a元素時會進行頁面跳轉,如果我們給事件加了prevent修飾符,那麼對應的a元素就不會進行網頁跳轉了v-on:click.prevent='myFunction'
  • .stop 修飾符告訴v-on 指令對於觸發的事件,阻止這個事件的冒泡(冒泡代表這個觸發的事件也會傳遞給父元素這些祖宗元素)
  • .once修飾符告訴v-on 指令對於觸發的事件只會觸發一次。
  • 還有好幾個事件修飾符,有興趣的可以自查。這個還是相對少用的。


    <body>
      <div id="app">
        <a v-on:click.prevent='myFunction' href='#'>aaa</a>
        <!-- 預設情況下,點擊a元素會進行跳轉,
          上面用#來演示,如果url多了一個#說明a的原生事件觸發了,
        而我們現在用prevent來阻止了a元素原始的事件
        -->
      </div>
    </body>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        var vm = new Vue({
          el: '#app',
          methods: {
            myFunction: function () {
              alert('haha')
            }
          }
        })
    </script>


按鍵修飾符

你可能需要監聽鍵盤來觸發事件,比如最常用的就是監聽enter鍵了。
按鍵修飾符也使用.跟在事件類型的後面 ,例如:<input v-on:keyup.enter="submit">

  • .enter代表enter鍵修飾符
  • .up .down .left .right代表四個方向鍵的修飾符。
  • 【上面給出了常見的“按鍵修飾符別名”,是別名,真實的值可能是一個數字】
  • 【這裡對於按鍵修飾符就不說那麼多了,需要用再查吧。】


事件綁定的簡寫

<!-- 完整語法 -->
<a v-on:click="doSomething">...</a>

<!-- 縮寫 -->
<a @click="doSomething">...</a>


補充:

  • 還可以自定義事件【不過目前我做的一些前端項目好像都沒怎麼涉及,有興趣的可以自查】



Vue指令

Vue的指令是以v-開頭的,它們各有各的左右,在前面已經介紹了不少了。現在再彙總一下。


  • v-text:向元素中輸出文本
  • v-html:向元素中輸入html文本
  • v-if:根據條件來判斷是否渲染元素(同類的v-else,v-else-if)
  • v-show:根據條件來判斷是否顯示元素
  • v-for:迴圈渲染元素
  • v-bind:為元素綁定屬性
  • v-model:進行數據的雙向綁定
  • v-on: 為元素綁定事件
  • v-once用來聲明元素只渲染一次。



數組操作


為什麼要特意地說一下數組的操作呢?因為數組是非常常用的數據類型,而在Vue中有些數組操作並不會觸發視圖更新。為了確保數據是“響應式”的,所以特意講一下這個。


下麵的代碼演示了使用普通數組操作方法時“響應失敗”的情況:

    <body>
      <div id="app">
        <p>{{ myArray}}</p>
        <button @click='addValue1'>下標法添加</button>
        <button @click='addValue2'>push法</button>
        <!-- 如果你點了第一個,再點第二個,第一個的添加會在第二個的時候再成功顯示 -->
      </div>
    </body>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        var vm = new Vue({
          el: '#app',
          data: {
            myArray: [1,2,3]
          },
          methods: {
            addValue1: function(){
              this.myArray[1]=333
            },
            addValue2: function(){
              this.myArray.push('999999')
            }
          }
        })
    </script>


下麵這些對數組操作的方法將會觸發視圖更新。

  • push():向數組末尾添加元素
  • pop():從數組末尾取出一個元素
  • shift():數組的第一個元素從其中刪除,並返回第一個元素的值
  • unshift():向數組的開頭添加一個或更多元素,並返回新的長度
  • splice():從數組中添加/刪除項目,然後返回被刪除的項目
  • sort():對數組的元素進行排序
  • reverse():對數組的元素進行逆序排序


官網的話

【官網的話】由於 JavaScript 的限制,Vue 不能檢測以下變動的數組:

  1. 當你利用索引直接設置一個項時,例如:vm.items[indexOfItem] = newValue
  2. 當你修改數組的長度時,例如:vm.items.length = newLength

為瞭解決第一類問題,以下兩種方式都可以實現和 vm.items[indexOfItem] = newValue 相同的效果,同時也將觸髮狀態更新:

Vue.set(vm.items, indexOfItem, newValue)vm.items.splice(indexOfItem, 1, newValue)vm.$set(vm.items, indexOfItem, newValue)
為瞭解決第二類問題,你可以使用 splice:vm.items.splice(newLength)


補充:

  • 還是由於 JavaScript 的限制,Vue 不能檢測對象屬性的添加或刪除:
var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` 現在修改a是響應式的

vm.b = 2
// `vm.b` 不是響應式的


  • 有時,我們想要顯示一個數組的過濾或排序副本,而不實際改變或重置原始數據(不改變原來的數據,代表創建一個副本,而sort會影響源數組,所以我們需要新的數組來存儲)。在這種情況下,可以創建返回過濾或排序數組的計算屬性。【如果你處理數組有多種情況,你可以使用一個 method 方法,用傳參來定義如何處理數組
    <body>
      <div id="app">
        <p>{{ numbers }}</p>
        <ul >
          <li v-for="n in evenNumbers">{{ n }}</li>
        </ul>
      </div>
      
    </body>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        var vm = new Vue({
          el: '#app',
          data: {
            numbers: [ 1, 2, 3, 4, 5 ]
          },
          computed: {
            evenNumbers: function () {
              return this.numbers.filter(function (number) {
                return number % 2 === 0
              })
            }
          }
        })
    </script>



Vue的元素復用問題

Vue 會儘可能高效地渲染元素,通常會復用已有元素而不是從頭開始渲染。這麼做除了使 Vue 變得非常快之外,還有其它一些好處。

數據殘留問題

而因為復用問題,所以可能會導致以下問題。由於輸入框被覆用,所以輸入框的數據殘留了下來。


<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address">
</template>


問題的解決:

Vue 為你提供了一種方式來表達“這兩個元素是完全獨立的,不要復用它們”。只需添加一個具有唯一值的 key 屬性即可(沒有key的label仍然被覆用了):

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>


當 Vue.js 用 v-for 正在更新已渲染過的元素列表時,它預設用“就地復用”策略。如果數據項的順序被改變,Vue 將不會移動 DOM 元素來匹配數據項的順序, 而是簡單復用此處每個元素,並且確保它在特定索引下顯示已被渲染過的每個元素。
這個預設的模式是高效的,但是只適用於不依賴子組件狀態或臨時 DOM 狀態 (例如:表單輸入值) 的列表渲染輸出。
為了給 Vue 一個提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要為每項提供一個唯一 key 屬性。理想的 key 值是每項都有的唯一 id。這個特殊的屬性相當於 Vue 1.x 的 track-by ,但它的工作方式類似於一個屬性,所以你需要用 v-bind 來綁定動態值 (在這裡使用簡寫):

<div v-for="item in items" :key="item.id">
  <!-- 內容 -->
</div>


建議儘可能在使用 v-for 時提供 key,除非遍歷輸出的 DOM 內容非常簡單,或者是刻意依賴預設行為以獲取性能上的提升,因為它是 Vue 識別節點的一個通用機制。




您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Mysql 獲取表設計查詢語句 ...
  • 遇到問題: 嘗試了網上的刪除c:\Users\your_name\AppData\Roaming\pgAdmin 之內的刪除所有文件和文件夾, 然後在C:\Program Files\PostgreSQL\10\pgAdmin 4\web 找到config_distro.py文件, 添加:MINIF ...
  • 1.下載,解壓到自己喜歡的目錄 2.配置環境變數。MYSQL_HOME,值為mysql的根目錄;在path中添加%MYSQL_HOME%/bin目錄。 3.向windows註冊mysql服務。必須用管理員許可權打開命令行,然後切換到mysql的bin目錄下,輸入命令:mysqld.exe --inst ...
  • 自從redis加入了module功能之後,redis的生態就很有意思了,每個領域的大佬都會以插件的形式給redis擴展一些新的功能,比如本篇說到的rediSQL,rebloom。 一:rediSQL 1. 背景 redis雖然是牛逼,但還是有很多人吐槽redis操作性太弱,比如你想要在redis上實 ...
  • 從MySQL 4.1 版本開始,就支持伺服器端的綁定變數,這大大提高了客戶端和伺服器端數據傳輸的效率 ...
  • 問題待解決,求幫助 最近遇到一個:多角色,不同許可權,登入口相同 暫時做法(自己覺得煩瑣): 設計 登入表 login 用戶表 user(id(pk), account(fk)···) 管理員表admin(account(pk),···) 醫生表doctor(account(pk),···) 將use ...
  • 分離資料庫註意事項 要求具有 db_owner 固定資料庫角色中的成員資格。 可以分離資料庫的數據和事務日誌文件,然後將它們重新附加到同一或其他 SQL Server實例。 如果要將資料庫更改到同一電腦的不同 SQL Server 實例或要移動資料庫,分離和附加資料庫會很有用。 分離資料庫是指將數 ...
  • 工具和準備: MYSQL 8.0jar包: 鏈接:https://pan.baidu.com/s/1O3xuB0o1DxmprLPLEQpZxQ 提取碼:grni 使用eclipse開發首先把jar包導入內庫中 首先將jar包複製到項目src下,右擊src點擊build path然後會在Refren ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...