Vue筆記之props驗證

夢裡夢一發表於2018-10-13

前言

工作的時候用到了iview-ui框架,結果發現它的tree樹形控制元件與element-ui根本不是一個套路,它使用了render函式去渲染節點.本來我是應該去官網學render函式的,沒想到被一把按在props上,相關API是有介紹的,是我蠢,之前沒找見,所以轉載別的小夥伴的文章,可那是部落格園的呀,很麻煩!

原文作者連結: www.cnblogs.com/cc11001100/…

我的程式碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
    <!-- Vue 推薦在絕大多數情況下使用 template 來建立你的 HTML。
    然而在一些場景中,你真的需要 JavaScript 的完全程式設計的能力,
    這時你可以用 render 函式,它比 template 更接近編譯器。
    下面是不適合template的一個示例 -->
  <h1>Hello world!</h1>
  <div id="app">
    <!-- 生成錨點標題 (anchored headings)元件 -->
    <anchored-heading :level="1">Hello world!</anchored-heading>
  </div>
  <script type="text/x-template" id="anchored-heading-template">
    <!-- 放在type=”text/x-template”中的內容將不會被瀏覽器解析,
    不被執行,不被顯示,它只是默默地舉根隱身草站在那裡。 -->
    <h1 v-if="level === 1">
      <slot></slot>
    </h1>
    <h2 v-else-if="level === 2">
      <slot></slot>
    </h2>
    <h3 v-else-if="level === 3">
      <slot></slot>
    </h3>
    <h4 v-else-if="level === 4">
      <slot></slot>
    </h4>
    <h5 v-else-if="level === 5">
      <slot></slot>
    </h5>
    <h6 v-else-if="level === 6">
      <slot></slot>
    </h6>
  </script>
  <script>
  Vue.component('anchored-heading', {
      template: '#anchored-heading-template',
      props: {
        //props的一些校驗
        level: {
          type: Number,
          required: true
        }
      }
    })
  let vm = new Vue({
    el: '#app'
  })
  </script>
</body>
</html>
複製程式碼

對方的見解:

使用props

在Vue中父元件向子元件中傳送資料是通過props實現的,一個簡單的使用props的例子:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Vue Study</title>
</head>
<body>
 
    <div id="app">
        <foo-component :foo-message="fooMessage"></foo-component>  
    </div>
 
<script type="text/javascript" src="lib/vue.js"></script>
<script type="text/javascript">
 
    var fooComponent = {
        props: ['fooMessage'],
        template: '<div> {{ fooMessage }} </div>'
    };
 
    var vm = new Vue({
        components: {
            'foo-component': fooComponent
        },
        el: '#app',
        data: {
            fooMessage: 123
        }
    });
 
</script>
</body>
</html>
複製程式碼

為什麼要有props驗證

但是上面這種方式是建立在大家都很遵守約定的情況下的,想象一下當有一個人要使用foo-component元件的時候,他可能對於其要接受的引數有什麼要求並不是很清楚,因此傳入的引數可能會在開發子元件的人的意料之外,程式就會發生錯誤,就像我們在函式呼叫之前先檢查一下函式一樣,props也可以進行一個預先檢查。

平時呼叫函式的時候在函式開頭的地方都是一坨糊糊的引數檢查,這種寫法很不好了,所有後來就有了校驗器模式(別去百度了,我隨口取的名字),校驗器模式就是指把在函式開頭的對引數校驗的部分提取出來作為一個公共的部分來管理,讓一個什麼東西來專門負責校驗,當型別不正確的時候就拋個異常根本不去呼叫這個函式,很多框架設計時都是這麼設計的(Spring MVC、Struts2等等),props也提供了這個功能,想一下如果沒有這個功能的話,為了保證正確性我們可能需要在每次使用props屬性之前都寫一坨程式碼來檢查。校驗器最大的好處就是大多數情況下我們只需要宣告我需要什麼樣的資料,讓校驗器檢查好了再塞給我。

type

可以使用type來宣告這個引數可以接受的資料的型別,當檢查規則只有一個的時候type可以略寫:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Vue Study</title>
</head>
<body>
 
    <div id="app">
        <foo-component :foo-message="fooMessage"></foo-component>  
    </div>
 
<script type="text/javascript" src="lib/vue.js"></script>
<script type="text/javascript">
 
    var fooComponent = {
        props: {
            fooMessage: Number
        },
        template: '<div> {{ fooMessage }} </div>'
    };
 
    var vm = new Vue({
        components: {
            'foo-component': fooComponent
        },
        el: '#app',
        data: {
            fooMessage: 123
        }
    });
 
</script>
</body>
</html>
複製程式碼

當傳入的引數型別不正確的時候Vue會發出提示:

Vue筆記之props驗證

type接受多個型別

當引數可以是多種型別的其中一個的時候,使用陣列來表示。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Vue Study</title>
</head>
<body>
 
    <div id="app">
        <foo-component :foo-message="fooMessage"></foo-component>  
    </div>
 
<script type="text/javascript" src="lib/vue.js"></script>
<script type="text/javascript">
 
    var fooComponent = {
        props: {
            fooMessage: [Number, String]
        },
        template: '<div> {{ fooMessage }} </div>'
    };
 
    var vm = new Vue({
        components: {
            'foo-component': fooComponent
        },
        el: '#app',
        data: {
            fooMessage: 123
        }
    });
 
</script>
</body>
</html>
複製程式碼

type能夠指定的型別

type可以是以下原生型別:

String

Number

Boolean

Function

Object

Array

Symbol

required

可以使用required選項來宣告這個引數是否必須傳入。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Vue Study</title>
</head>
<body>
 
    <div id="app">
        <foo-component :foo-message="fooMessage"></foo-component>  
    </div>
 
<script type="text/javascript" src="lib/vue.js"></script>
<script type="text/javascript">
 
    var fooComponent = {
        props: {
            fooMessage: {
                type: Number,
                required: true
            }
        },
        template: '<div> {{ fooMessage }} </div>'
    };
 
    var vm = new Vue({
        components: {
            'foo-component': fooComponent
        },
        el: '#app',
        data: {
            fooMessage: 256
        }
    });
 
</script>
</body>
</html>
複製程式碼

當未傳入引數時:

Vue筆記之props驗證

default

使用default選項來指定當父元件未傳入引數時props變數的預設值:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Vue Study</title>
</head>
<body>
 
    <div id="app">
        <foo-component></foo-component>
    </div>
 
<script type="text/javascript" src="lib/vue.js"></script>
<script type="text/javascript">
 
    var fooComponent = {
        props: {
            fooMessage: {
                type: Number,
                default: 128
            }
        },
        template: '<div> {{ fooMessage }} </div>'
    };
 
    var vm = new Vue({
        components: {
            'foo-component': fooComponent
        },
        el: '#app',
        data: {
            fooMessage: 256
        }
    });
 
</script>
</body>
</html>
複製程式碼

當父元件未傳入引數時子元件的值是128,當父元件傳入引數時是其指定的引數,比如這裡可以是256。

當type的型別為Array或者Object的時候default必須是一個函式:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Vue Study</title>
</head>
<body>
 
    <div id="app">
        <foo-component></foo-component>
    </div>
 
<script type="text/javascript" src="lib/vue.js"></script>
<script type="text/javascript">
 
    var fooComponent = {
        props: {
            fooMessage: {
                type: Array,
                default: function(){
                    return ['foo', 'bar'];
                }
            }
        },
        template: '<div> {{ fooMessage }} </div>'
    };
 
    var vm = new Vue({
        components: {
            'foo-component': fooComponent
        },
        el: '#app',
        data: {
            fooMessage: ['f', 'o', 'o']
        }
    });
 
</script>
</body>
</html>
複製程式碼

required && default ???

那麼required和default是否能同時出現在一個props變數中呢?

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Vue Study</title>
</head>
<body>
 
    <div id="app">
        <foo-component></foo-component>
    </div>
 
<script type="text/javascript" src="lib/vue.js"></script>
<script type="text/javascript">
 
    var fooComponent = {
        props: {
            fooMessage: {
                type: Number,
                required: true,
                default: 128
            }
        },
        template: '<div> {{ fooMessage }} </div>'
    };
 
    var vm = new Vue({
        components: {
            'foo-component': fooComponent
        },
        el: '#app',
        data: {
            fooMessage: 256
        }
    });
 
</script>
</body>
</html>
複製程式碼

渲染結果:

Vue筆記之props驗證
儘管控制檯上Vue報了錯誤,但是props變數fooMessage還是使用了設定的default值。

事情不會這麼簡單,再測試一下其它的情況,比如當傳入的引數驗證不通過的時候:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Vue Study</title>
</head>
<body>
 
    <div id="app">
        <foo-component :foo-message="fooMessage"></foo-component>  
    </div>
 
<script type="text/javascript" src="lib/vue.js"></script>
<script type="text/javascript">
 
    var fooComponent = {
        props: {
            fooMessage: {
                type: Number
            }
        },
        template: '<div> {{ fooMessage }} </div>'
    };
 
    var vm = new Vue({
        components: {
            'foo-component': fooComponent
        },
        el: '#app',
        data: {
            fooMessage: 'foobar'
        }
    });
 
</script>
</body>
</html>
複製程式碼

渲染結果:

Vue筆記之props驗證
fooMessage要求的型別是Number,傳入了一個String型別的,儘管在控制檯提示報了錯,但是仍然將其渲染了出來。

由此可以得出一個結論:Vue的props校驗只是提供一個參考,並不是強制性的。

validator

當校驗規則很複雜,預設提供的校驗規則無法滿足的時候可以使用自定義函式來校驗。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Vue Study</title>
</head>
<body>
 
    <div id="app">
        <foo-component :foo-message="fooMessage"></foo-component>  
    </div>
 
<script type="text/javascript" src="lib/vue.js"></script>
<script type="text/javascript">
 
    var fooComponent = {
        props: {
            fooMessage: {
                validator: function(value){
                    return value>=0 && value<=128;
                }
            }
        },
        template: '<div> {{ fooMessage }} </div>'
    };
 
    var vm = new Vue({
        components: {
            'foo-component': fooComponent
        },
        el: '#app',
        data: {
            fooMessage: 100
        }
    });
 
</script>
</body>
</html>
複製程式碼

一個綜合的例子

props: {
    // fooA只接受數值型別的引數
    fooA: Number,
    // fooB可以接受字串和數值型別的引數
    fooB: [String, Number],
    // fooC可以接受字串型別的引數,並且這個引數必須傳入
    fooC: {
        type: String,
        required: true
    },
    // fooD接受數值型別的引數,如果不傳入的話預設就是100
    fooD: {
        type: Number,
        default: 100
    },
    // fooE接受物件型別的引數
    fooE: {
        type: Object,
        // 當為物件型別設定預設值時必須使用函式返回
        default: function(){
            return { message: 'Hello, world' }
        }
    },
    // fooF使用一個自定義的驗證器
    fooF: {
        validator: function(value){
            return value>=0 && value<=100;
        }
    }
}
複製程式碼

隔壁家的寫的確實很細緻!已經關注他的github.

相關文章