vue面試(一)


1.watch如何深度監聽,watch監聽引用類型數據,拿不到oldVal

<template>
    <div>
        <input v-model="name"/>
        <input v-model="info.city"/>
    </div>
</template>

<script>
export default {
    data() {
        return {
            name: '雙越',
            info: {
                city: '北京'
            }
        }
    },
    watch: {
        name(oldVal, val) {
            // eslint-disable-next-line
            console.log('watch name', oldVal, val) // 值類型,可正常拿到 oldVal 和 val
        },
        info: {
            handler(oldVal, val) {
                // eslint-disable-next-line
                console.log('watch info', oldVal, val) // 引用類型,拿不到 oldVal 。因為指針相同,此時已經指向了新的 val
            },
            deep: true // 深度監聽,可以監聽到引用類型中的屬性city。
        }
    }
}
</script>

 

 

2. v-if和v-show

跟新不是很頻繁,用v-if,

跟新很頻繁,用v-show,利用的display:none

3,v-for 循環遍歷,key的重要性,v-for 和v-if是不能一起使用

加了key(一定要具有唯一性),vue中列表循環需加:key="唯一標識" 唯一標識可以是item里面id index等,因為vue組件高度復用增加Key可以標識組件的唯一性,為了更好地區別各個組件 key的作用主要是為了高效的更新虛擬DOM

<template>
    <div>
        <p>遍歷數組</p>
        <ul>
            <li v-for="(item, index) in listArr" :key="item.id">
                {{index}} - {{item.id}} - {{item.title}}
            </li>
        </ul>

        <p>遍歷對象</p>
        
        <ul  v-if="flag">
            <!-- v-if不能和v-for在同一個標簽使用,v-for渲染模板的優先級比v-if高,遍歷一遍v-if判斷一次,效率不高,在 在父級容器加個v-if判斷即可 -->
            <li v-for="(val, key, index) in listObj" :key="key">
                {{index}} - {{key}} -  {{val.title}}
            </li>
        </ul>
    </div>
</template>

<script>
export default {
    data() {
        return {
            
            flag: false,
            listArr: [
                { id: 'a', title: '標題1' }, // 數據結構中,最好有 id ,方便使用 key
                { id: 'b', title: '標題2' },
                { id: 'c', title: '標題3' }
            ],
            listObj: {
                a: { title: '標題1' },
                b: { title: '標題2' },
                c: { title: '標題3' },
            }
        }
    }
}
</script>

 

4. 事件, event, 事件修飾符, 事件綁定到哪里 

 在Vue中,事件修飾符處理了許多DOM事件的細節,讓我們不再需要花大量的時間去處理這些煩惱的事情,而能有更多的精力專注於程序的邏輯處理。在Vue中事件修飾符主要有:

.stop:等同於JavaScript中的event.stopPropagation(),防止事件冒泡
.prevent:等同於JavaScript中的event.preventDefault(),防止執行預設的行為(如果事件可取消,則取消該事件,而不停止事件的進一步傳播)
.capture:與事件冒泡的方向相反,事件捕獲由外到內
.self:只會觸發自己范圍內的事件,不包含子元素
.once:只會觸發一次

 

 

 

 

 

<template>
    <div>
        <p>{{num}}</p>
        <button @click="increment1">+1</button>
        <button @click="increment2(2, $event)">+2</button>
    </div>
</template>

<script>
export default {
    data() {
        return {
            num: 0
        }
    },
    methods: {
        increment1(event) {
           
            console.log('event', event, event.__proto__.constructor) // 是原生的 event 對象
      
            //event.target 事件掛載到那個節點上
            console.log(event.target)
       
            console.log(event.currentTarget) // 注意,事件是被注冊到當前元素的,和 React 不一樣
            this.num++

            // 1. event 是原生的
            // 2. 事件被掛載到當前元素
            // 和 DOM 事件一樣
        },
        increment2(val, event) {
            // eslint-disable-next-line
            console.log(event.target)
            this.num = this.num + val
        },
        loadHandler() {
            // do some thing
        }
    },
    mounted() {
        window.addEventListener('load', this.loadHandler)
    },
    beforeDestroy() {
        //【注意】用 vue 綁定的事件,組建銷毀時會自動被解綁 // 自己綁定的事件,需要自己銷毀!!!
        window.removeEventListener('load', this.loadHandler)
    }
}
</script>

 

5. v-model,常見表單項, textarear checkbox, radio, select,

修飾符, lazy number trim

<template>
    <div>
        <p>輸入框: {{name}}</p>
        <!-- 修飾符trim,清除前后空格 -->
        <input type="text" v-model.trim="name"/>
        <!-- 修飾符lazy,只有在input輸入框發生一個blur時才觸發 -->
        <input type="text" v-model.lazy="name"/>
        <!-- 修飾符number, 將用戶輸入的字符串轉換成number -->
        <input type="text" v-model.number="age"/>

        <p>多行文本: {{desc}}</p>
        <textarea v-model="desc"></textarea>
        <!-- 注意,<textarea>{{desc}}</textarea> 是不允許的!!! -->

        <p>復選框 {{checked}}</p>
        <input type="checkbox" v-model="checked"/>

        <p>多個復選框 {{checkedNames}}</p>
        <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>

        <p>單選 {{gender}}</p>
        <input type="radio" id="male" value="male" v-model="gender"/>
        <label for="male">男</label>
        <input type="radio" id="female" value="female" v-model="gender"/>
        <label for="female">女</label>

        <p>下拉列表選擇 {{selected}}</p>
        <select v-model="selected">
            <option disabled value="">請選擇</option>
            <option>A</option>
            <option>B</option>
            <option>C</option>
        </select>

        <p>下拉列表選擇(多選) {{selectedList}}</p>
        <select v-model="selectedList" multiple>
            <option disabled value="">請選擇</option>
            <option>A</option>
            <option>B</option>
            <option>C</option>
        </select>
    </div>
</template>

<script>
export default {
    data() {
        return {
            name: '雙越',
            age: 18,
            desc: '自我介紹',

            checked: true,
            checkedNames: [],

            gender: 'male',

            selected: '',
            selectedList: []
        }
    }
}
</script>

 

6.props, $emit, 組件通訊,自定義事件

父子傳遞,自定義事件

Vue兄弟組件之間通信 eventBus

新建event.js,兄弟組件映入該組件,兄弟組件通過event.$on, 或者event.$emit來通信

import Vue from 'vue'

export default new Vue()

或者在main.js中設置全局事件總線,然后兄弟組件this.$bus.$on,  this.$bus.$emit來通信

// new Vue()實例化了一個Vue的實例化對象
//因為只有組件對象或者Vue的實例化對象才能調用$on和$emit

//想要成為事件總線的條件:
//1、所有的組件對象必須都能看得到這個總線對象,因此我們把這個對象放在了Vue原型
//2、這個事件總線對象必須能調用$on和$emit方法(總線對象必須是Vue的實例化對象或者是組件對象)


new Vue({
  beforeCreate(){ Vue.prototype.$bus = this },
  el:'#root',
  render: h => h(App)
})

 

父組件

<template>
    <div>
        <Input @add="addHandler"/>
        <List :list="list" @delete="deleteHandler"/>
    </div>
</template>

<script>
import Input from './Input'
import List from './List'

export default {
    components: {
        Input,
        List
    },
    data() {
        return {
            list: [
                {
                    id: 'id-1',
                    title: '標題1'
                },
                {
                    id: 'id-2',
                    title: '標題2'
                }
            ]
        }
    },
    methods: {
        addHandler(title) {
            this.list.push({
                id: `id-${Date.now()}`,
                title
            })
        },
        deleteHandler(id) {
            this.list = this.list.filter(item => item.id !== id)
        }
    },
    created() { // eslint-disable-next-line
        console.log('index created')
    },
    mounted() {
        // eslint-disable-next-line
        console.log('index mounted')
    },
    beforeUpdate() {
        // eslint-disable-next-line
        console.log('index before update')
    },
    updated() {
        // eslint-disable-next-line
        console.log('index updated')
    },
}
</script>

子組件input

<template>
    <div>
        <input type="text" v-model="title"/>
        <button @click="addTitle">add</button>
    </div>
</template>

<script> import event from './event'

export default {
    data() {
        return {
            title: ''
        }
    },
    methods: {
        addTitle() {
            // 調用父組件的事件
            this.$emit('add', this.title)

            // 調用自定義事件
            event.$emit('onAddTitle', this.title) this.title = ''
        }
    }
}
</script>

子組件List

<template>
    <div>
        <ul>
            <li v-for="item in list" :key="item.id">
                {{item.title}}

                <button @click="deleteItem(item.id)">刪除</button>
            </li>
        </ul>
    </div>
</template>

<script> import event from './event'

export default {
    // props: ['list']
    props: {
        // prop 類型和默認值
 list: { type: Array, default() { return [] }
        }
    },
    data() {
        return {

        }
    },
    methods: {
        deleteItem(id) {
            this.$emit('delete', id)
        },
        addTitleHandler(title) { // eslint-disable-next-line
            console.log('on add title', title)
        }
    },
    created() {
        // eslint-disable-next-line
        console.log('list created')
    },
    mounted() {
        // eslint-disable-next-line
        console.log('list mounted')

        // 綁定自定義事件
        event.$on('onAddTitle', this.addTitleHandler)
    },
    beforeUpdate() {
        // eslint-disable-next-line
        console.log('list before update')
    },
    updated() {
        // eslint-disable-next-line
        console.log('list updated')
    },
    beforeDestroy() {
        // 及時銷毀,否則可能造成內存泄露
        event.$off('onAddTitle', this.addTitleHandler)
    }
}
</script>

 父子組件生命周期的順序, 父組件created創建了實例,子組件list也創建了實例,並且mounted渲染了模板,然后父組件才mounted渲染模板

子組件更新完,父組件才會更新完

生命周期過程;https://www.cnblogs.com/fsg6/p/14468597.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM