Vue組件基礎(chǔ)

通過Vue在項目中的應(yīng)用氛堕,我發(fā)現(xiàn)它的雙向綁定機制對于表單異步請求十分頻繁的項目十分受用馏臭,因為相當(dāng)于輸入綁定在了變量域中,可以直接對它的data域進行提取讼稚。而且如果將Ajax請求設(shè)為同步的括儒,之后可以直接使用請求完畢的數(shù)據(jù)設(shè)為Vue實例的data域,還是十分方便的锐想。但是過程中也發(fā)現(xiàn)了帮寻,在Vue實例中,有時想嵌入其他的Vue實例赠摇,卻是做不到固逗,就想趁著不忙了把組件這塊補上浅蚪。

組件的定義
如下

    Vue.component('button-counter', {
        data: function () {
            return {
                count: 0
            }
        },
        template: '<button v-on:click="count++">You clicked me {{ count }} times. </button>'
    });

可以看到組件的基本結(jié)構(gòu)分為data和template兩種膝昆,類似于一個完整的Vue實例(只不過沒有el這個屬性)痊土,但是其中的data返回的是一個函數(shù)曹步,如果不寫成函數(shù)的話剃执,則JS引擎每次初始化一個組件蜓萄,他們的data域就會指向同一個引用幻赚,造成事實上的耦合甩栈。

而template則類似于React的JSX代碼伙窃,使用HTML文本片來書寫組件真實的模板HTML代碼饿这,配合合適的IDE浊伙,在其中也可以做到自動補全。

我們來實例化一個Vue對象长捧。

    <div id="components-demo">
        <button-counter></button-counter>
        <button-counter></button-counter>
        <button-counter></button-counter>
<!--        組件可以復(fù)用多次嚣鄙,每次復(fù)用代表創(chuàng)建一個新的Vue實例-->
    </div>
    var vm1 = new Vue({
        el: '#components-demo'
    });
最終的效果圖,點擊按鈕之間的數(shù)據(jù)互不影響

頗有一絲XML的味道串结,目前小程序中稀奇古怪的標記語言也是基于XML構(gòu)建的哑子,在此不再贅述,在Vue實例裝載后肌割,會在渲染“button-counter”這個標記之前在Vue全局對象綁定的組件中找到對應(yīng)的組件卧蜓,如果沒有,則會拋出一個異常把敞,否則則會按照實例對象和組件中的data進行virtual dom的渲染弥奸。

組件的屬性
說白了類似于對函數(shù)的調(diào)用,傳入的參數(shù)奋早。這里的“參數(shù)”可以不止一個(方括號)盛霎,其中的字符串代表“參數(shù)名”。

    // 為組件聲明屬性列表
    Vue.component('blog-post', {
        props: ['title'],
        template: '<h3>{{ title }}</h3>'
    });

不同的是耽装,標記語言元素的參數(shù)是以屬性給出的愤炸,可以猜想Vue其中封裝了一個高性能的XML解析器?

    <div id="property-demo">
        <blog-post title="hello"></blog-post>
        <blog-post title="thank you"></blog-post>
        <blog-post title="thank you very much"></blog-post>
    </div>

實例化Vue對象掉奄。

    var vm2 = new Vue({
        el: '#property-demo'
    });

效果也還不錯规个。


效果

深入探討組件屬性

可能經(jīng)歷過HTML4時代的前端開發(fā)者,對于一些h4中的標記姓建,比如<font></font>之類的是深惡痛絕诞仓,雖然極大的降低了學(xué)習(xí)成本,但是一旦接手對于該項目的重構(gòu)速兔,改完可能手都要抽筋了

HTML元素可以使用v-bind綁定數(shù)據(jù)和屬性狂芋,自然組件也可以。

    var vm3 = new Vue({
        el: '#property-demo2',
        data: {
            posts: [
                { id: 1, title: 'My journey with Vue' },
                { id: 2, title: 'Blogging with Vue' },
                { id: 3, title: 'Why Vue is so fun' }
            ]
        }
    });

復(fù)用剛才的組件

    <div id="property-demo2">
        <blog-post v-for="post in posts"
                   v-bind:key="post.id"
                   v-bind:title="post.title"
        ></blog-post>
    </div>

結(jié)果是類似的憨栽,但內(nèi)容不同。


結(jié)果

再聯(lián)想到剛才我提到的可以使用Ajax初始化Vue實例的data域,是不是又有了新的想法呢#手動滑稽屑柔。

與此同時屡萤,搭配v-html屬性,可以使模板的用法更加豐富掸宛。

    Vue.component('blog-posture', {
        props: ['post'],
        template:
        "<div class='blog-post'>" +
            "<h3>{{ post.title }}</h3>" +
            "<div v-html='post.content'></div>" +
            "</div>"
    })

    var vm4 = new Vue({
        el: '#property-demo3',
        data: {
            posts: [
                { id: 1, title: 'My journey with Vue' , content: '<div>123</div><p>4949494</p>'},
                { id: 2, title: 'Blogging with Vue' , content: '<img src=x onerror="javaScript:alert(1)>'},
                { id: 3, title: 'Why Vue is so fun' , content: '<textarea>1231231223123</textarea>'}
            ]
        }
    });

我們在posts數(shù)組中的數(shù)據(jù)里死陆,定義了一個content用來盛放html代碼(注意其中id為2的代碼,它并不會執(zhí)行)唧瘾,這樣content的內(nèi)容最終會渲染到template的div中措译。
HTML代碼:

    <div id="property-demo3">
        <blog-posture v-for="post in posts"
                   v-bind:key="post.id"
                   v-bind:title="post.title"
                      v-bind:post="post"
        ></blog-posture>
    </div>

最終結(jié)果是這樣的。


v-html渲染結(jié)果

但是其中的xss代碼并沒有被執(zhí)行饰序,或者說那個img元素领虹,壓根沒被渲染。


XSS攻擊失敗

控制臺中的結(jié)果證明了這個結(jié)論求豫。

組件的雙向綁定
首先這個讓我想起了v-model這個指令塌衰。

<input v-model="searchText">

它實質(zhì)上是一個語法糖,包含了v-bind和v-on:兩條指令的搭配蝠嘉,在處理輸入的雙向綁定的時候最疆,它等效于這兩個屬性的組合:

<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value"
>

基于這個原理,我們也可以使用組件自定義輸入框(畢竟原生的確實是很丑)

    Vue.component('custom-input', {
        props: ['value'],
        template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
    });

注意

1.組件必須向外提供value屬性蚤告,且HTML代碼必須提供該屬性
2.在組件的template內(nèi)部努酸,使用v-bind和v-on組合的方式,將組件的value屬性綁定到template中輸入框的value屬性中杜恰,并且處理好v-on中的input事件获诈。

于是Vue實例就可以使用v-model來綁定實例中的數(shù)據(jù)。

    var vm6 = new Vue({
        el: '#component-input',
        data: {
            searchText: ""
        }
    })

    <div id="component-input">
        <custom-input
                v-model="searchText"
        ></custom-input>
    </div>
組件雙向綁定

組件-實例通信

組件可以共享實例的全局變量箫章。

    Vue.component('blog-position', {
        props: ['post'],
        template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <button v-on:click="$emit('enlarge-text')">
        Enlarge text
      </button>
      <div v-html="post.content"></div>
    </div>
  `
    });


    var vm5 = new Vue({
        el: '#blog-posts-events-demo',
        data: {
            posts: [
                { id: 1, title: 'My journey with Vue' , content: '<div>123</div><p>4949494</p>'},
                { id: 2, title: 'Blogging with Vue' , content: '<img src=x onerror="javaScript:alert(1)>'},
                { id: 3, title: 'Why Vue is so fun' , content: '<textarea>1231231223123</textarea>'}
            ],
            postFontSize: 1
        }
    })
    vlist.push(vm5);

這里我們還用到了$emit方法烙荷,是處理自定義事件的。

    <div id="blog-posts-events-demo">
        <div :style="{ fontSize: postFontSize + 'em' }">
            <blog-position
                    v-for="post in posts"
                    v-bind:key="post.id"
                    v-bind:post="post"
                    v-on:enlarge-text="postFontSize += 0.1"
            ></blog-position>
        </div>
    </div>

最終的結(jié)果如圖:


點擊中間的按鈕

點擊下方的按鈕
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末檬寂,一起剝皮案震驚了整個濱河市终抽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌桶至,老刑警劉巖昼伴,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異镣屹,居然都是意外死亡圃郊,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門女蜈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來持舆,“玉大人色瘩,你說我怎么就攤上這事∫菰ⅲ” “怎么了居兆?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長竹伸。 經(jīng)常有香客問我泥栖,道長,這世上最難降的妖魔是什么勋篓? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任吧享,我火速辦了婚禮,結(jié)果婚禮上譬嚣,老公的妹妹穿的比我還像新娘钢颂。我一直安慰自己,他們只是感情好孤荣,可當(dāng)我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布甸陌。 她就那樣靜靜地躺著,像睡著了一般盐股。 火紅的嫁衣襯著肌膚如雪钱豁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天疯汁,我揣著相機與錄音牲尺,去河邊找鬼。 笑死幌蚊,一個胖子當(dāng)著我的面吹牛谤碳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播溢豆,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼蜒简,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了漩仙?” 一聲冷哼從身側(cè)響起搓茬,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎队他,沒想到半個月后卷仑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡麸折,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年锡凝,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垢啼。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡窜锯,死狀恐怖张肾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情衬浑,我是刑警寧澤捌浩,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站工秩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏进统。R本人自食惡果不足惜助币,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望螟碎。 院中可真熱鬧眉菱,春花似錦、人聲如沸掉分。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽酥郭。三九已至华坦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間不从,已是汗流浹背惜姐。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留椿息,地道東北人歹袁。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像寝优,于是被迫代替她去往敵國和親条舔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,697評論 2 351