先為什么要引入prop這個東西,因為如果要向組件里面傳遞信息,在沒有prop之前,是無法傳遞值到組件里面,因此引入了prop進行傳遞值。
1,Prop的大小寫
官方文檔,HTML對于attribute(屬性)名的大小寫是不敏感的,瀏覽器會把所有的大寫字母,都解釋為小寫字母,因此使用DOM模板(就是原先寫在html中,一打開就會被瀏覽器解析的代碼)時,camelCase(駝峰命名法)的prop名需要使用等價的kebab-case( xx- xxx )命名:
Vue.component('blog-post', {
// 在 JavaScript 中是 camelCase 的props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'})
<!-- 在 HTML 中是 kebab-case 的 -->
<blog-post post-title="hello!"></blog-post>
2,Prop類型
可以在定義prop時,指定值類型,如代碼:
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
3,傳遞靜態或者動態的Prop
傳入靜態值:
<blog-posttitle="My journey with Vue"></blog-post>
傳入動態值:
<!-- 動態賦予一個變量的值 -->
<blog-postv-bind:title="post.title">
</blog-post>
<!-- 動態賦予一個復雜表達式的值 -->
<blog-postv-bind:title="post.title + ' by ' + post.author.name"></blog-post>
傳入數字
<!-- 即便 `42` 是靜態的,我們仍然需要 `v-bind` 來告訴 Vue -->
<!-- 這是一個 JavaScript 表達式而不是一個字符串。-->
<blog-postv-bind:likes="42"></blog-post>
<!-- 用一個變量進行動態賦值。-->
<blog-postv-bind:likes="post.likes"></blog-post>
傳入布爾值
<!-- 包含該 prop 沒有值的情況在內,都意味著 `true`。-->
<blog-postis-published></blog-post>
<!-- 即便 `false` 是靜態的,我們仍然需要 `v-bind` 來告訴 Vue -->
<!-- 這是一個 JavaScript 表達式而不是一個字符串。-->
<blog-postv-bind:is-published="false"></blog-post>
<!-- 用一個變量進行動態賦值。-->
<blog-postv-bind:is-published="post.isPublished"></blog-post>
傳入數組
<!-- 即便數組是靜態的,我們仍然需要 `v-bind` 來告訴 Vue -->
<!-- 這是一個 JavaScript 表達式而不是一個字符串。-->
<blog-postv-bind:comment-ids="[234, 266, 273]"></blog-post>
<!-- 用一個變量進行動態賦值。-->
<blog-postv-bind:comment-ids="post.commentIds"></blog-post>
傳入一個對象
<!-- 即便對象是靜態的,我們仍然需要 `v-bind` 來告訴 Vue -->
<!-- 這是一個 JavaScript 表達式而不是一個字符串。-->
<blog-postv-bind:author="{
name: 'Veronica',
company: 'Veridian Dynamics'
}">
</blog-post> <!-- 用一個變量進行動態賦值。--> <blog-postv-bind:author="post.author"></blog-post>
傳入一個對象中的所有property
一個對象post
post: {
id: 1,
title: 'My Journey with Vue'}
下面的模板:
<blog-postv-bind="post"></blog-post>
等價于:
<blog-postv-bind:id="post.id"v-bind:title="post.title"></blog-post>
4,單向數據流
所有的prop使得其父子prop之間形成了單向下行綁定,父級prop的更新會向下流動到子組件中,但是反過來是不行的。
在JavaScript中對象和數組是通過引用傳入的,對于一個數組或者對象類型的prop來說,子組件中改變變更這個對象或者數組本身將會影響到父組件的狀態。
5,Prop驗證
為了實現驗證prop,可以為prop中的值提供一個帶有驗證需求的對象。
Vue.component('my-component', {
props: {
// 基礎的類型檢查 (`null` 和 `undefined` 會通過任何類型驗證)
propA: Number,
// 多個可能的類型
propB: [String, Number],
// 必填的字符串
propC: { type: String, required: true },
// 帶有默認值的數字
propD: { type: Number, default: 100 },
// 帶有默認值的對象 propE: {
type: Object,
// 對象或數組默認值必須從一個工廠函數獲取
default: function() {
return { message: 'hello' } } },
// 自定義驗證函數 propF: { validator: function(value) {
// 這個值必須匹配下列字符串中的一個
return ['success', 'warning', 'danger'].indexOf(value) !==-1 } } } })
當prop驗證失敗的時候,vue會產生一個控制臺警告。
類型檢查時,type可以是原生構造函數的其中一個,比如
也可以是自定義的構造函數
functionPerson(firstName, lastName) {
this.firstName=firstName
this.lastName=lastName
}
你可以使用:
Vue.component('blog-post', {
props: {
author: Person
}
})
6,非Prop的Attribute
一個非prop的attribute是指傳向一個組件,但該組件并沒有想要的prop定義的attribute。
顯示定義的prop適用于向一個子組件傳入信息,然后組件庫的作者并不總能預見組件會被用于怎樣的場景。這也是組件為什么可以接受任意的attribute,而這些attribute會被添加到這個組件的根元素上。
例如,想象一下你通過一個 Bootstrap 插件使用了一個第三方的 <bootstrap-date-input> 組件,這個插件需要在其 <input> 上用到一個 data-date-picker attribute。我們可以將這個 attribute 添加到你的組件實例上:
<bootstrap-date-inputdata-date-picker="activated"></bootstrap-date-input>
然后這個 data-date-picker="activated" attribute 就會自動添加到 <bootstrap-date-input> 的根元素上。
替換/合并已有的attribute
如何組件中的class不同,會被合并起來,style也是如此。
想象一下 <bootstrap-date-input> 的模板是這樣的:
<inputtype="date"class="form-control">
為了給我們的日期選擇器插件定制一個主題,我們可能需要像這樣添加一個特別的類名:
<bootstrap-date-inputdata-date-picker="activated"class="date-picker-theme-dark">
</bootstrap-date-input>
慶幸的是,class 和 style attribute 會稍微智能一些,即兩邊的值會被合并起來,從而得到最終的值:form-control date-picker-theme-dark。
禁用attribute繼承
如果你不希望組件的根元素繼承 attribute,你可以在組件的選項中設置 inheritAttrs: false。例如:
rop
基本用法
Prop的基本用法很簡單,只需要在子組件的Vue實例中定義該屬性并把值設為目標屬性的數組即可
Vue.component('child', { ... // 接收message props: ['message'] ... })
tips:由于HTML中的屬性是不區分大小寫的,所以當使用DOM中的模板(HTML中)時,駝峰寫法需要轉化為短橫線寫法。但是,如果使用字符串模板(JS中)時,不受限制,可以為所欲為。
Prop中的靜態和動態值
在正常情況下,一般在父組件中通過v-bind定義一個動態值,子組件通過Prop接收該值,所以,很多人認為,Prop只能接收動態值。但是,其實Prop可以接受靜態屬性。
示例:
/* 父組件 */ <child type="video"></child> /* 子組件 */ Vue.component('child', { ... // 成功接收 props: ['type'] ... })
在示例中,父組件在子組件標簽上定義了靜態屬性type,子組件依然通過Prop拿到了靜態屬性type。
單向數據流
所有的 prop 都使得其父子 prop 之間形成了一個單向下行綁定:父組件的 Prop 的更新會向下流動到子組件中,但是反過來則不行。這樣會防止從子組件意外改變父組件以及同級子組件的狀態,從而導致你的應用的數據流向難以理解。
另外,每次父組件發生更新時,子組件中所有的Prop都將刷新為最新的值。這意味著你不應該在子組件內部改變Prop,如果你這樣做了,Vue會在控制臺拋出一個警告。
一般來說,如果子組件需要操作Prop中的值,需要將Prop中的值賦值給本地定義的屬性:
... props: ['message'], data () { return { mes: this.message } } ...
非Prop特性
非Props特性是指在組件上定義了屬性,而又沒有使用Prop接受屬性。此時,子組件內不可使用該屬性值,該屬性會直接添加到子組件的根節點上。
比如,在一個只含有一個div的子組件上,如果我向子組件傳了一個content屬性,但是子組件不使用Prop接收content屬性,則渲染結果為:
<div id="root"> <div content="hello"></div> </div>
Prop校驗
子組件用Props接收父組件傳來的消息有多種形式:
1.數組形式
props: [data1, data2]
數組形式相當于直接接收消息,不做任何校驗,一般來說,不太建議使用數組形式。
2.簡單對象形式
props: { data1: String, data2: Array }
簡單對象形式對父組件傳遞的值進行了類型校驗,如果傳過來的值類型不一致,控制臺會報錯。
3.復雜對象形式
props: { data1: { type: String, required: true, default: 'default value', validator (value) { return (value.length < 5) } }, data2: { type: Array, required: true, default: ()=> ['', '', ''] } }
復雜對象形式的情況下,作為對象屬性的參數可以寫為對象形式,參數對象含有4個屬性,type、required、default、validator。
type:設定參數類型,當傳入參數類型與type不相符時,控制臺會報錯
required:設定參數是否是必傳,當設為true時,不傳該參數會報錯
default:設定默認值,當參數類型為復雜類型時,需使用工廠模式生成默認值,否則Vue會在控制臺拋出警告。如圖所示,就通過工廠模式生成了一個長度為3的空數組。
validator:校驗器,是一個函數,擁有一個代表傳入值的形參,可以自定義各種校驗,當返回false時,會報錯,表示沒通過校驗。
對前端的技術,架構技術感興趣的同學關注我的頭條號,并在后臺私信發送關鍵字:“前端”即可獲取免費的架構師學習資料
知識體系已整理好,歡迎免費領取。還有面試視頻分享可以免費獲取。關注我,可以獲得沒有的架構經驗哦!!
比Python,JavaScript才是更適合寫爬蟲的語言。原因有如下三個方面:
一、任務:爬取用戶在Github上的repo信息
通過實例的方式學習爬蟲是最好的方法,先定一個小目標:爬取github repo信息。入口URL如下,我們只需要一直點擊next按鈕就能夠遍歷到用戶的所有repo。
https://github.com/{{username}}?tab=repositories
獲取repo之后,可以做什么?
二、爬蟲雙股劍:axios和jQuery
axios是JavaScript中很常用的異步網絡請求庫,相比jQuery,它更輕量、更專業。既能夠用于瀏覽器端,也可以用于Node。它的語法風格是promise形式的。在本任務中,只需要了解如下用法就足夠了:
axios.get(url).then((resp)=> { 請求成功,處理resp.data中的html數據 }).catch((err)=> { 請求失敗,錯誤處理 })
請求之后需要處理回復結果,處理回復結果的庫當然是用jQuery。實際上,我們有更好的選擇:cheerio。
在node下,使用jQuery,需要使用jsdom庫模擬一個window對象,這種方法效率較低,四個字形容就是:笨重穩妥。
如下代碼使用jQuery解析haha.html文件
fs=require("fs") jquery=require('jquery') jsdom=require('jsdom') //fs.readFileSync()返回結果是一個buffer,相當于byte[] html=fs.readFileSync('haha.html').toString('utf8') dom=new jsdom.JSDOM(html) $=jquery(dom.window) console.log($('h1'))
cheerio只實現了jQuery中的DOM部分,相當于jQuery的一個子集。cheerio的語法和jQuery完全一致,在使用cheerio時,幾乎感覺不到它和jQuery的差異。在解析HTML方面,毫無疑問,cheerio是更好的選擇。如下代碼使用cheerio解析haha.html文件。
cheerio=require('cheerio') html=require('fs').readFileSync("haha.html").toString('utf8') $=cheerio.load(html) console.log($('h1'))
只需20余行,便可實現簡單的github爬蟲,此爬蟲只爬取了一頁repo列表。
var axios=require("axios") var cheerio=require("cheerio") axios.get("https://github.com/weiyinfu?tab=repositories").then(resp=> { var $=cheerio.load(resp.data) var lis=$("#user-repositories-list li") var repos=[] for (var i=0; i < lis.length; i++) { var li=lis.eq(i) var repo={ repoName: li.find("h3").text().trim(), repoUrl: li.find("h3 a").attr("href").trim(), repoDesc: li.find("p").text().trim(), language: li.find("[itemprop=programmingLanguage]").text().trim(), star: li.find(".muted-link.mr-3").eq(0).text().trim(), fork: li.find(".muted-link.mr-3").eq(1).text().trim(), forkedFrom: li.find(".f6.text-gray.mb-1 a").text().trim() } repos.push(repo) } console.log(repos) })
三、更豐富的功能
爬蟲不是目的,而是達成目的的一種手段。獲取數據也不是目的,從數據中提取統計信息并呈現給人才是最終目的。
在github爬蟲的基礎上,我們可以擴展出更加豐富的功能:使用echarts等圖表展示結果。
要想讓更多人使用此爬蟲工具獲取自己的github統計信息,就需要將做成一個網站的形式,通過搜索頁面輸入用戶名,啟動爬蟲立即爬取github信息,然后使用echarts進行統計展示。網站肯定也要用js作為后端,這樣才能和js爬蟲無縫銜接,不然還要考慮跨語言調用。js后端有兩大web框架express和koa,二者API非常相似,并無優劣之分,但express更加流行。
如上設計有一處用戶體驗不佳的地方:當啟動爬蟲爬取github信息時,用戶可能需要等待好幾秒,這個過程不能讓用戶干等著。一種解決思路是:讓用戶看到爬蟲爬取的進度或者爬取過程。可以通過websocket向用戶推送爬取過程信息并在前端進行展示。展示時,使用類似控制臺的界面進行展示。
如何存儲爬取到的數據呢?使用MongoDB或者文件都可以,最好實現兩種存儲方式,讓系統的存儲方式變得可配置。使用MongoDB時,用到js中的連接池框架generic-pool。
整個項目用到的庫包括:
試用地址:
https://weiyinfu.cn/githubstatistic/search.html?
案例地址:https://github.com/weiyinfu/GithubStatistic
原文鏈接:https://zhuanlan.zhihu.com/p/53763115
*請認真填寫需求信息,我們會在24小時內與您取得聯系。