1. 程式人生 > 實用技巧 >Vue 基礎

Vue 基礎

Vue 簡介

  • Vue 是一套用於構建使用者介面的漸進式框架。
  • 與其它大型框架不同的是,Vue 被設計為可以自底向上逐層應用。
  • Vue 的核心庫只關注檢視層,不僅易於上手,還便於與第三方庫或既有專案整合。另一方面,當與現代化的工具鏈以及各種支援類庫結合使用時,Vue 也完全能夠為複雜的單頁應用提供驅動。

# react 是 facebook開發的

# vue 是我們國人開發

vue起步

  • 1. 引包
  • 2. 啟動 new Vue(options);

插值表示式 一定要 雙括號 -> {{ msg }}

Vue指令

v-text和v-html

  • {{ }} 和 v-text 的作用一樣 都是插入值,直接渲染,innerText
  • v-html 既能插入值,又能插入標籤 innerhtml

v-bind繫結

v-bind: 相當於 ' : ' 簡寫

v-on事件處理 監聽dom
v-on 簡寫 ' @ '

v-on
事件修飾符
.once

<!-- 點選事件將只會觸發一次 -->
<a v-on:click.once="doThis"></a>

  


為什麼在 HTML 中監聽事件?

你可能注意到這種事件監聽的方式違背了關注點分離 (separation of concern) 這個長期以來的優良傳統。

但不必擔心,因為所有的 Vue.js 事件處理方法和表示式都嚴格繫結在當前檢視的 ViewModel 上,它不會導致任何維護上的困難。

實際上,使用 v-on 有幾個好處:

  • 1. 掃一眼 HTML 模板便能輕鬆定位在 JavaScript 程式碼裡對應的方法。
  • 2. 因為你無須在 JavaScript 裡手動繫結事件,你的 ViewModel 程式碼可以是非常純粹的邏輯,和 DOM 完全解耦,更易於測試。
  • 3. 當一個 ViewModel 被銷燬時,所有的事件處理器都會自動被刪除。你無須擔心如何清理它們。

v-for列表渲染

當 Vue 正在更新使用 v-for 渲染的元素列表時,它預設使用“就地更新”的策略。

如果資料項的順序被改變,Vue 將不會移動 DOM 元素來匹配資料項的順序,而是就地更新每個元素,並且確保它們在每個索引位置正確渲染。

這個類似 Vue 1.x 的 track-by="$index"。

這個預設的模式是高效的,但是隻適用於不依賴子元件狀態或臨時 DOM 狀態 (例如:表單輸入值) 的列表渲染輸出。

為了給 Vue 一個提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要為每項提供一個唯一 key attribute:

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

建議儘可能在使用 v-for 時提供 key attribute,除非遍歷輸出的 DOM 內容非常簡單,或者是刻意依賴預設行為以獲取效能上的提升。

因為它是 Vue 識別節點的一個通用機制,key 並不僅與 v-for 特別關聯。後面我們將在指南中看到,它還具有其它用途。

不要使用物件或陣列之類的非基本型別值作為 v-for 的 key。請用字串或數值型別的值。

v-model雙向資料繫結

    <p>{{obj.a}} {{obj.b}}</p>

    <input type="text" v-model="obj.a" >

    data:
      obj:{
           num : 0,
           a:1,
           b:"nima"
}


Vue中表單輸入繫結應用

修飾符

.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">

偵聽器watch的用法

<div id="app">
    <h3>{{abc[0].name}}</h3>
    <button @click="abc[0].name='addpapa'">changer</button>
</div>
<script src="./vue.js"></script> <script > var v = new Vue({ el : '#app', data:{ abc:[ {id:1, name:"123"}, {id:2, name:"bb"}, {id:3, name:"cc"}, ], } // 基本的資料型別可以使用watch直接監聽,複雜資料型別object array 要深度監視 watch:{ // key是屬於data 物件的屬性名,value:監聽後的行為,n_v:新值,o_v:舊值 'mmm':function (n_v,o_v) { console.log(n_v, o_v) }, // 深度監視 object | array 物件。陣列 'abc':{ deep:'true', //這是字串 handler:function (new_v) { console.log(new_v[0].name); } } }

計算屬性之computed getter

計算屬性之computed的setter方法

<div id="app">
    {{content}}
</div>

<script src="./vue.js"></script>
<script>
    //  全域性的 過濾器
    Vue.filter("m_reverse",(val) => {
       console.log(this)
       return  val.split("").reverse().join("")
    })
    new Vue({
        el:'#app',
        data:{
            msg:"",
        },
        methods:{
            input_mgs:function (event) {
                const {value} = event.target;
                this.content = value;
            },
            click_mgs:function () {
                console.log(this.content)
            }
        },
    })
</script>

過濾器 filters
為資料新增新東西

<div id="app">
    {{f | my_f("$")}}
    <br>
    {{ff | m_reverse}}
    <br>
    {{content}}
    <input type="text" v-model="content" @input="input_mgs">
    <button @click="click_mgs"  >changer</button>
</div>

<script src="./vue.js"></script>
<script>
    //  全域性的 過濾器
    Vue.filter("m_reverse",(val) => {
       console.log(this)
       return  val.split("").reverse().join("")
    })
    new Vue({
        el:'#app',
        data:{
            msg:"",
            f:123,
            ff:"aadddd",
        },
        methods:{
            input_mgs:function (event) {
                const {value} = event.target;
                this.content = value;
            },
            click_mgs:function () {
                console.log(this.content)
            }
        },
        //   區域性的 過濾器
        filters:{
            my_f:function (f,a) {
                return a+f
            }
        },
        computed:{
            content:{
                set:function (new_v) {
                    this.msg = new_v
                    console.log(new_v)
                },
                get:function () {
                    return this.msg
                }
            },

        },
    })
</script>

音樂播放器

練手專案音樂播放器

<head>
    <meta charset="UTF-8">
    <title>音樂播放器</title>
    <style>
        *{
            padding: 0;
            margin: 0;
        }
        ul {
            list-style: none;
        }
        ul li{
            margin: 30px 30px;
            padding: 20px 10px;
            border-radius: 20px;
        }
        ul li.active{
            background-color: lavender;
        }
    </style>
</head>
<body>
<div id="app">
    <audio :src="get_src" controls autoplay @ended="handleend()" ></audio>
    <ul>
        <li :class="{active:index === dataindex}" v-for='(item, index) in musicData' :key="item.id" @click="handleClick(index)">
            <h3>{{item.id}} 歌名: {{item.name}} </h3>
            <p>作者: {{item.author}}</p>
        </li>
    </ul>
    <button @click="handlenext()">下一首</button>
</div>

<script src="./vue.js" ></script>
<script >
    const musicData = [
        {
            id:0,
            name :'信仰',
            author:'hc',
            src:'./static/信仰.mp3'
    },
        {
            id:1,
            name :'春嬌與志明',
            author:'hc',
            src:'./static/春嬌與志明.m4a'
    },
        {
            id:2,
            name :'暗示分離',
            author:'輝哥',
            src:'./static/暗示分離.mp3'
    },
        {
            id:3,
            name :'突然的自我',
            author:'hc',
            src:'./static/突然的自我.mp3'
    },
        {
            id:4,
            name :'風吹麥浪',
            author:'hc',
            src:'./static/風吹麥浪.m4a'
    }
    ]

    new Vue({
        // 繫結 標籤
        el: "#app",
        data:{
            musicData,
            // src:"./static/信仰.mp3",
            dataindex: 0,
        },
        // vue 的計算屬性
        computed:{
            get_src(){
                return this.musicData[this.dataindex].src
            },
        },
        methods:{
            handleClick(index){
                // this.src = src
                this.dataindex = index
            },
            handleend(){
                this.handlenext();
            },
            handlenext(){
                this.dataindex++
                if (this.dataindex ===this.musicData.length){
                    this.dataindex = 0
                }
                // this.src = this.musicData[this.dataindex].src
            }
        }
    })
</script>

元件


區域性元件的建立和使用

  • App 元件 html+css+js
  • 1. 建立元件
  • 2. 掛載子元件
  • 建,掛,用
  • 注意: 在元件中這個data 必須是一個函式,返回一個物件
<div id="App">
<!--    //  3. 使用子元件-->
    <App></App>
</div>

<script src="../vue.js" ></script>
<script>
    //  以首字母開頭大寫 , 第一個引數是元件名,第二個是 模板
    Vue.component("Vheader",{
        template: `
            <div>我是導航欄 </div>
        `
    })
    Vue.component('Vaside',{
        template:`
            <div> 我是側邊欄 </div>
        `
    })
    // 需要用到的區域性變數,程式碼需要寫在 建立好的子元件前面
    const Vbutton={
        template:`
            <button>區域性按鈕</button>
        `
    }
    // 區域性組價
    const Vcontent={
        data(){
            return{}
        },
        template:`
            <div>
                <div>我是內容欄</div>
                <Vbutton/>
                <Vbutton/>
            </div>
        `,
        components:{
            Vbutton,
        },
    }
    // App 元件  html+css+js
    // 1. 建立元件
    // 2. 掛載子元件
    // 建,掛,用
    // 注意: 在元件中這個data 必須是一個函式,返回一個物件
    const App ={
        data(){
            return {
                msg: "我是App元件"
            }
        },
        <!-- 一定要有一個閉合的標籤 -->
        template:`
            <div>
                <div>
                    <Vheader> </Vheader>
                    <div>
                       <Vaside />
                       <Vcontent/>
                    </div>
                </div>
                <h3>{{msg}}</h3>
                <button @click='handleClick'> 按鈕</button>
            </div>
        `,
        methods:{
            handleClick(){
                this.msg='學習區域性元件';
            }
        },
        components: {
            Vcontent,
        }
    }
    var a = new Vue({
        el:'#App',
        data:{},
        components: {
            //  掛載子元件
            App,
        },
    })
</script>


全域性元件的建立和使用


vue 提供的監聽觸發事件 把輸出的值,通過事件丟擲給父元件

this.$emit('inputHandler',val)

 $on 繫結事件
 $emit 觸發事件

provide 和 inject

<div id="App">
    <!--    //  3. 使用子元件-->
    <App> </App>
</div>
<script src="../vue.js" ></script>
<script>
    // provide
    // inject
    // 父元件 provide 來提供變數, 然後再子元件中通過inject 來注入變數,無論元件巢狀多深
    //  做了箇中間傳遞者的功能  中央事件匯流排
    var c = new Vue
    //  這裡的this  是這個A子元件本身的this
    Vue.component('AA',{
        template:`
            <div>AA 使用provide 和 inject -> : {{msg}}</div>
        `,
        inject:["msg"]

    })
    Vue.component('A',{
        // data(){
        //     return{
        //         msg:"provide + inject ->  A -> AA -> A "
        //     }
        // },
        template: `
            <div>
                <AA></AA>
                <button @click="countNumber">購物車+1</button>
            </div>
        `,
        methods:{
            countNumber(){
                //  $emit   觸發事件
                c.$emit('add',1)
            }
        }
    })
    //  這裡的this  是這個B子元件本身的this
    Vue.component('B',{
        data(){
            return {
                number:0
            }
        },
        template:`
            <div>  {{number}} </div>
        `,
        // 元件建立
        created(){
            //  $on     繫結事件
            //  $emit   觸發事件
            c.$on('add',(n)=>{
                this.number+=n;
            })
        }
    })

    const App ={
        data(){
            return {}
        },
        // 需要繫結一個屬性    ( : 屬性, @ 事件 )
        template:`
                <div>
                    <A></A>
                    <B></B>
                </div>
        `,
    }
    new Vue({
        el:'#App',
        data:{ },
        provide(){
            return {
                msg:"provide + inject -> App-> A -> AA "
            }
        },
        components: {
            //  掛載子元件
            App,
        },
    })
</script>

匿名插槽

<slot></slot>

具名插槽

<slot name="aa"></slot>

作用域插槽
有時讓插槽內容能夠訪問子元件中才有的資料是很有用的

生命週期

  • beforeCreate
  • created
  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • activated 啟用
  • deactivated 停用
  • 需要配合 keep-alive 儲存在記憶體中
  • beforeDestroy
  • destroyed
<div id="App">
    <!--    //  3. 使用子元件-->
    <App></App>
</div>
<script src="../vue.js" ></script>
<script>
    // beforeCreate
    // created
    // beforeMount
    // mounted
    // beforeUpdate
    // updated
    // activated    啟用
    // deactivated  停用
    // 需要配合 keep-alive  儲存在記憶體中
    // beforeDestroy
    // destroyed
    Vue.component('test',{
        data() {
            return {
                msg:"你輝哥哥哥",
                isRed:false
            };
        },
        methods:{
            handleClick(){
                this.msg = "Appyourpapa";
                this.isRed = !this.isRed ;
            }
        },
        template: `
            <div>
                <button @click="handleClick">改變</button>
                <h3 :class='{active:isRed}'>{{msg}}</h3>
            </div>
        `,
        beforeCreate(){
            console.log("元件建立之前 -> beforeCreate",this.$data )
        },
        created(){
            // 非常重要的事情,在此時傳送ajxa 請求後端資料
            console.log("元件建立完成 -> create", this.$data)
        },
        beforeMount(){
            console.log("元件掛載之前 -> beforeMount", document.getElementById("app"))
        },
        mounted(){
            console.log("元件掛載完成 -> Mount", document.getElementById("app"))
        },
        beforeUpdate(){
            console.log("元件更新之前的DOM -> beforeUpdate", )
        },
        updated(){
            console.log("元件更新完成的DOM -> updated", )
        },
        beforeDestroy(){
            console.log("元件銷燬之前的DOM -> beforeDestroy")
        },
        destroyed(){
            console.log("元件銷燬完成的DOM -> destroyed")
        },
        activated(){
            console.log("元件被激活了 -> activated")
        },
        deactivated(){
            console.log("元件被停用了 -> deactivated")
        },
    })
    const App ={
        data(){
            return {
                isShow:true
            }
        },
        methods: {
            clickHandler(){
                this.isShow = !this.isShow;
            },
        },
        // 一定要有一個閉合的標籤 
        // 需要繫結一個屬性    ( : 屬性, @ 事件 )
        template:`
            <div>
                <keep-alive>
                    <test v-if="isShow"></test>
                </keep-alive>
                <button @click="clickHandler">銷燬和建立</button>
            </div>
        `
    }
    new Vue({
        el:'#App',
        data:{ },
        provide(){
            return {
                msg:"provide + inject "
            }
        },
        components: {
            //  掛載子元件
            App,
        },
    })
</script>


非同步元件載入

<script src="../vue.js" ></script>
<script type='module'>

    const App ={
        data(){
            return {
                isShow:false
            }
        },
        methods: {
            clickHandler(){
                this.isShow = !this.isShow;
            },
        },
        components:{
            test:()=>import('./test.js')
        },
        template:`
            <div>
                <test v-if="isShow"></test>
                <button @click="clickHandler">非同步載入</button>
            </div>
        `,
    }
    new Vue({
        el:'#App',
        data:{ },
        provide(){
            return {
                msg:"provide + inject "
            }
        },
        components: {
            App,
        },
    })
</script>

refs的使用

訪問子元件例項或子元素

有的時候你仍可能需要在 JavaScript 裡直接訪問一個子元件。為了達到這個目的,你可以通過ref這個 attribute 為子元件賦予一個 ID 引用。例如:

<base-input ref="usernameInput"></base-input>

現在在你已經定義了這個ref的元件裡,你可以使用:

this.$refs.usernameInput

來訪問這個`<base-input>`例項,以便不時之需。比如程式化地從一個父級元件聚焦這個輸入框。在剛才那個例子中,該<base-input>元件也可以使用一個類似的ref提供對內部這個指定元素的訪問,例如:

<input ref="input">

甚至可以通過其父級元件定義方法:

methods: {
  // 用來從父級元件聚焦輸入框
  focus: function () {
    this.$refs.input.focus()
  }
}

允許父級元件通過下面的程式碼聚焦 `<base-input>`裡的輸入框:

this.$refs.usernameInput.focus()

refv-for一起使用的時候,你得到的 ref 將會是一個包含了對應資料來源的這些子元件的陣列。

nextTick的使用 和應用

    <div id="App">
        <!--    //  3. 使用子元件-->
        <App></App>
    </div>
<script src="../vue.js" ></script>
<script >
// 在頁面上拉取一個介面,這個介面返回一些資料,這些資料是這個頁面的一個浮層元件要依賴的, // 然後我在介面一返回資料就展示了這個浮層元件,展示的同時 // 上報一些資料給後臺(這些資料是父元件從介面拿的) // 這個時候,神奇的事情發生了,雖然拿到了資料,但是浮層展現的時候, // 這些資料還未更新到元件去,上報失敗 const Pop = { data(){ return{ isShow:false, } }, props:{ name : { type: String, default:'', }, }, template:` <div v-if="isShow"> {{name}} </div> `, methods:{ show(){ // 彈窗元件展示 this.isShow = true; console.log(this.name); } } } const App=({ data(){ return{ name :"" } }, created(){ // 模擬非同步請求 setTimeout(()=>{ // 更新資料 this.name = "huige" this.$nextTick(()=>{ this.$refs.pop.show(); }) // this.$refs.pop.show(); },1000); }, components:{ Pop }, template: ` <pop ref="pop" :name="name"></pop> ` }) var vm = new Vue({ el:'#App', components: { App } }) </script>

物件變更檢測注意事項

<div id="App">
    <h3>
        {{user.name}}, {{user.age}}, {{user.phone}}
        <button @click="handlerAdd">新增響應式屬性</button>
    </h3>
</div>
<script src="../vue.js" ></script>
<script >
    //  Vue 不能檢測物件屬性的新增和刪除
    new Vue({
        el:'#App',
        data:{
          user:{}
        },
        methods:{
            handlerAdd(){
                this.user.age = 20
                // 新增響應式屬性, 只有 新增或者刪除 有效
                //  vue 的方法需要都要加 $
                //1.  Vue.$set(object, key, value)
                // this.$set(this.user,"age",20)
                // 2. Object.assign 方法
                this.user = Object.assign({}, this.user,{
                    age:200,
                    phone:110,
                })
            }
        },
        created(){
          setTimeout(()=>{
              this.user={name:"我是你爸爸"}
          },2000)
        },
    })
</script>


mixin混入技術

    // 一個公共的元件
    const mymixin={
        data(){
            return{
                msg:"asd"
            }
        },created(){
            this.hello();
        },
        methods:{
            hello(){
                console.log("hello mixin")
            }
        }
    }
    new Vue({
        el:'#app',
        data(){
        return {
            msg1:"huige"
        }
    },
    created(){
        console.log("aaa")
    },
    //  mixin 來分發Vue 元件中 的可複用 功能!
    mixins:[mymixin],
    })

mixin混入技術應用

<div id="app">  </div>
<script src="../vue.js" ></script>
<script>
// 模態框 和 提示框 邏輯程式的複用 // 全域性的mixin 每個建立的元件都會被呼叫。 // 用法 Vue.mixin({}) const allData={ data() { return { isShow:false } }, methods:{ allData(){ this.isShow= !this.isShow } } } const MoDuleData= { template:` <div v-if='isShow'> <h1> 模態框 </h1> </div> `, mixins:[allData] } const ToolData = { template:` <div v-if='isShow'> <h4> 提示框 </h4> </div> `, mixins:[allData] } new Vue({ el:'#app', data:{}, components:{ MoDuleData, ToolData, }, template:` <div> <button @click="handlemoduel">模態框</button> <button @click="handletool">提示框</button> <MoDuleData ref='modulea'></MoDuleData> <ToolData ref='toola'></ToolData> </div> `, methods: { handlemoduel(){ this.$refs.modulea.allData(); }, handletool(){ this.$refs.toola.allData(); }, } }) </script>