Vue 框架使用以及面试点

Vue 框架使用


前言

本章节讲解了Vue的基本使用、组件使用、高级特性以及Vuex 和 Vue-router 的使用。


一、Vue 基本使用的知识点

1.插值、插值

  • 插值、表达式
  • 指令、动态属性
  • v-html:会有XSS风险,会覆盖子组件

代码演示

<template>
    <div>
        <p>文本插值 {{message}}</p>
        <p>JS 表达式 {{ flag ? 'yes' : 'no' }} (只能是表达式,不能是 js 语句)</p>

        <p :id="dynamicId">动态属性 id</p>

        <hr/>
        <p v-html="rawHtml">
            <span>有 xss 风险</span>
            <span>【注意】使用 v-html 之后,将会覆盖子元素</span>
        </p>
    </div>
</template>

<script>
export default {
    data() {
        return {
            message: 'hello vue',
            flag: true,
            rawHtml: '指令 - 原始 html <b>加粗</b> <i>斜体</i>',
            dynamicId: `id-${Date.now()}`
        }
    }
}
</script>

2.computed 和 watch

  • computed有缓存,data不变则不会重新计算
  • watch监听引用类型,拿不到oldVal
  • watch如何深度监听?

代码演示:

 watch: {
        info: {
            handler(oldVal, val) {
                console.log('watch info', oldVal, val) // 引用类型,拿不到 oldVal 。因为指针相同,此时已经指向了新的 val
            },
            deep: true // 深度监听
        }
    }

3.class 和 style

  • 使用动态属性
  • 使用驼峰式写法

代码演示:

<template>
    <div>
        <p :class="{ black: isBlack, yellow: isYellow }">使用 class</p>
        <p :class="[black, yellow]">使用 class (数组)</p>
        <p :style="styleData">使用 style</p>
    </div>
</template>

<script>
export default {
    data() {
        return {
            isBlack: true,
            isYellow: true,

            black: 'black',
            yellow: 'yellow',

            styleData: {
                fontSize: '40px', // 转换为驼峰式
                color: 'red',
                backgroundColor: '#ccc' // 转换为驼峰式
            }
        }
    }
}
</script>
<style>
    .black {
        background-color: #999;
    }
    .yellow {
        color: yellow;
    }
</style>

4.条件渲染

  • v-if v-else的用法,可使用变量,也可以使用===表达式
  • v-if和v-show的区别以及使用场景?

v-if指令是直接销毁和重建DOM达到让元素显示和隐藏的效果;
v-show指令是通过修改元素的display的CSS属性让其显示或者隐藏;
使用v-show会更加节省性能上的开销;当只需要少次显示或隐藏时,使用v-if更加合理。

代码演示:

<template>
    <div>
        <p v-if="type === 'a'">A</p>
        <p v-else-if="type === 'b'">B</p>
        <p v-else>other</p>

        <p v-show="type === 'a'">A by v-show</p>
        <p v-show="type === 'b'">B by v-show</p>
    </div>
</template>
<script>
export default {
    data() {
        return {
            type: 'a'
        }
    }
}
</script>

5.循环(列表)渲染

  • 如何遍历对象?—— 也可以使用 v-for
  • key的重要性。key不能乱写(如random或者index)

循环对象一般用对象的 key 作为 key;
循环数组一般使用业务主键作为 key;

  • 避免v-if和v-for一起使用

操作和实现起来都没有什么问题,页面也会正常展示。但是会带来不必要的性能消耗;
vue2.x版本中,当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级;
vue3.x版本中,当 v-if 与 v-for 一起使用时,v-if 具有比 v-for 更高的优先级;
官网明确指出:避免 v-if 和 v-for 一起使用,永远不要在一个元素上同时使用 v-if 和 v-for。
可以先对数据在计算数据中进行过滤,然后再进行遍历渲染;

代码演示:

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

6.事件

  • event 参数,自定义参数

代码演示:

<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 对象
            console.log(event.target)
            console.log(event.currentTarget) // 注意,事件是被注册到当前元素的,和 React 不一样
            this.num++

            // 1. event 是原生的
            // 2. 事件被挂载到当前元素
            // 和 DOM 事件一样
        },
        increment2(val, event) {
            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>
  • 事件修饰符,按键修饰符

事件修饰符

<!--阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!--提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!--修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!--只有修饰符-->
<form v-on:submit.prevent></form>
<!--添加事件监听器时使用事件捕获模式-->
<!--即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!--只当在event,target是当前元素自身时触发处理函数 -->
<!--即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>

按键修饰符

<!--即使ctrl或Shift被一同按下时也会触发-->
<button @click.ctrl="onclick">A</button>
<!--有且只有Ctr1被按下的时候才触发-->
<button @click.ctrl.exact="onCtrlclick">A</button>
<!--没有任何系统修饰符被按下的时候才触发-->
<button @click.exact="onclick">A</button>

7.表单

  • v-model
  • 常见表单项textarea checkbox radio select
  • 修饰符lazy number trim

代码演示:

<template>
    <div>
        <p>输入框: {{name}}</p>
        <input type="text" v-model.trim="name"/>
        <input type="text" v-model.lazy="name"/>
        <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: 24,
            desc: '一个爱烹饪的程序员',

            checked: true,
            checkedNames: [],

            gender: 'male',

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

二、Vue 组件使用的知识点

1.父子组件如何通讯

  • props / $emit

父组件传递值,子组件通过props接收。
子组件向父组件传值,子组件通过$emit发送。

// 父组件
<template>
  <div id="app">
  	<Child :users="users" @change="change"></Child>// 将父组件的data传到子组件,将子组件中的change方法接收
    <a @click="add">点击添加成员</a>
  </div>
</template>

<script>
import Child from "./components/Users"
export default {
  name: 'App',
  data(){
    return{
      users:["a","b","c"]
    }
  },
  components:{
    Child
  },
  methods:{
  	change:function(reslut){
  		console.log(reslut)
  	}
  }
}

// Child子组件
<template>
  <div class="hello">
    <ul>
      <li v-for="item in userList">{{item}}</li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'child',
  //子组件通过props来接收父组件传递来的方法
  //props:['users']             //不对接收的值做处理
  props:{    					//对接收的值做处理
    users:{
      type:Array,
      required:true
    }
  },
  data(){
     userList: users
   },
  methods:{
  	add:function(){
       userList.pusth('d');
       this.$emit('change', userList); //自定义事件,通过$emit发送事件,同时传递参数值。     }
  }
}
</script>


  • $refs

ref 加在子组件上,用this.$refs.ref值,获取到的是组件实例,可以使用组件的所有方法。在使用方法时直接this. $refs.ref值.方法()就可以使用了。

 // 父组件
<template>
  <div id="app">
  	<Child ref='childRef'></Child>// 父组件中通过ref来使用子组件中的方法
  	<button @click='ParentMethod'></button>// 点击按钮时触发子组件中的childMethod方法
  </div>
</template>

<script>
import Child from "./components/Users"
export default {
  name: 'App',
  components:{
    Child
  },
  methods:{
  	ParentMethod(){
  		this.$refs.childRef.childMethod()   //输出'我是子组件中的方法'
  	}
  }
}

//子组件
<template>
  <div class="hello">
  </div>
</template>

<script>
export default {
  name: 'child',
  methods:{
  	childMethod(){
  		console.log('我是子组件中的方法')
  	}
  }
}
</script>

  • provide / inject

这对选项需要一起使用,以允许一个祖先组件(provider)向其所有子孙后代(inject)注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

 // A.vue
export default {
  provide: {
    name: '可乐'
  }
}
// B.vue
export default {
  inject: ['name'],
  mounted () {
    console.log(this.name);  // 可乐
  }
}

// 需要注意的是:provide和 inject绑定并不是可响应的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的
// 所以,上面 A.vue 的 name 如果改变了,B.vue 的 this.name是不会改变的,仍然是 可乐。
  • $parent / $children

this.parent 可以直接访问该组件的父实例或组件;父组件也可以通过 this.parent 可以直接访问该组件的父实例或组件;
父组件也可以通过this.parent可以直接访问该组件的父实例或组件;父组件也可以通过this.children 访问它所有的子组件;

需要注意 $children 并不保证顺序,也不是响应式的。

//父组件
<template>
<div>
  <testVue></testVue> 
  <button @click="clickChild">$children方式获取子组件值</button>
</div>
</template>
<script>
import testVue from './test'
export default {
  data(){
    return {
      total: 108
    }
  },
  components: {
    testVue  
  },
  methods: {
    funa(e){
        console.log("index",e)
    },
    clickChild(){
        console.log(this.$children[0].msg);        //通过$children获取子组件的data
    }
  }
}
</script>

//子组件
<template>
<div>
  <button @click="parentClick">点击访问父组件</button>
</div>
</template>
<script>
export default {
  data(){
    return {
      msg:"我是子组件中的data"
    }
  },
  methods: {
    parentClick(){
       this.$parent.funa("我在子组件中调用父组件的方法")		//通过$parent获取父组件的方法
       console.log(this.$parent.total);				//通过$parent获取父组件的data
    }
  }
}
</script>

2.如何用自定义事件进行通讯

先 new 个 vue 实例

import Vue from 'vue'

export default new Vue()

调用方法

import event from './event'
methods: {
        print() {
            // 调用自定义事件
            event.$emit('print', '我被打印出来了')
        }
    }
mounted() {
        // 绑定自定义事件
        event.$on('print', (content)=>{
			console.log(content) // 我被打印出来了
		})
    }
beforeDestroy() {
        // 及时销毁,否则可能造成内存泄露
        event.$off('print')
    }

3.vue父子组件生命周期调用顺序

挂载阶段

Created with Raphaël 2.2.0 父beforeCreate 父created 父beforeMount 子beforeCreate 子created 子beforeMount 子mounted 父mounted

更新阶段

Created with Raphaël 2.2.0 父beforeUpdate 子beforeUpdate 子updated 父updated

销毁阶段

Created with Raphaël 2.2.0 父beforeDestroy 子beforeDestroy 子destroyed 父destroyed

三、Vue 高级使用的知识点

1.自定义 v-model

代码演示:

<template>
    <!-- 例如:vue 颜色选择 -->
    <input type="text"
        :value="text1"
        @input="$emit('change1', $event.target.value)"
    >
    <!--
        1. 上面的 input 使用了 :value 而不是 v-model
        2. 上面的 change1 和 model.event1 要对应起来
        3. text1 属性对应起来
    -->
</template>

<script>
export default {
    model: {
        prop: 'text1', // 对应 props text1
        event: 'change1'
    },
    props: {
        text1: String,
        default() {
            return ''
        }
    }
}
</script>

2.$nextTick

Vue 是异步渲染(原理后面详细讲解
data 改变之后,DOM 不会立刻渲染
$nextTick 会在 DOM 渲染之后被触发,以获取最新 DOM 节点

3.slot

  • 基本使用
 <template>
    <a :href="url">
        <slot>
            默认内容,即父组件没设置内容时,这里显示
        </slot>
    </a>
</template>

<script>
export default {
    props: ['url'],
    data() {
        return {}
    }
}
</script>
  • 作用域插槽
<!--子组件-->
<template>
    <a :href="url">
        <slot :slotData="website">
            {{website.subTitle}} <!-- 默认值显示 subTitle ,即父组件不传内容时 -->
        </slot>
    </a>
</template>

<script>
export default {
    props: ['url'],
    data() {
        return {
            website: {
                url: 'https://www.csdn.net/',
                title: 'CSDN',
                subTitle: '专业开发者社区'
            }
        }
    }
}
</script>


<!--父组件-->
<ScopedSlotDemo :url="‘https://www.csdn.net/’">
    <template v-slot="slotProps">
        {{slotProps.slotData.title}}
   </template>
</ScopedSlotDemo> 
  • 具名插槽
<!--子组件-->
<template>
	<div><slot></slot></div>
    <div><slot name="test"></slot></div>
</template>
<!--父组件-->
<NamedSlot>
 	<template v-slot:test>
        将插入 test slot 中
   </template>
   <p>将插入未命名的 slot 中</p>
</NamedSlot>

4.动态、异步组件

  • 动态组件

用法: :is= “component-name”
需要根据数据,动态渲染的场景。即组件类型不确定。

<template>
 <component :is="NextTickName"/>
</template>
<script>

export default {
    data() {
        return {
            NextTickName:"component-test"  // 可以动态改变组件名 根据不通的组件名显示不通的组件
        }
    }
}
</script>
  • 异步组件

import() 函数;
按需加载,异步加载;
什么时候用,就什么时候加载,如果不用就不用加载,不会在首屏加载的时候直接加载出来。

<script>
export default {
    components: {
         demo: () => import('./demo')
    }
}
</script>

5.keep-alive

缓存组件;
频繁切换,不需要重复渲染;
它会将组件生成 DOM 缓存起来,下次再重建时直接拿来使用。关键就是,将组件渲染的结果缓存起来,不用再重新创建、重新渲染。

<template>
    <div>
        <button @click="changeState('A')">A</button>
        <button @click="changeState('B')">B</button>
        <button @click="changeState('C')">C</button>

        <keep-alive> <!-- tab 切换 -->
            <KeepAliveStageA v-if="state === 'A'"/> <!-- v-show -->
            <KeepAliveStageB v-if="state === 'B'"/>
            <KeepAliveStageC v-if="state === 'C'"/>
        </keep-alive>
    </div>
</template>

<script>
import KeepAliveStageA from './KeepAliveStateA'
import KeepAliveStageB from './KeepAliveStateB'
import KeepAliveStageC from './KeepAliveStateC'

export default {
    components: {
        KeepAliveStageA,
        KeepAliveStageB,
        KeepAliveStageC
    },
    data() {
        return {
            state: 'A'
        }
    },
    methods: {
        changeState(state) {
            this.state = state
        }
    }
}
</script>

6.mixin

四、Vuex 和 Vue-router 相关面试题

总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值