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父子组件生命周期调用顺序
挂载阶段
更新阶段
销毁阶段
三、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提供了大量能使我们快速便捷地处理数据的函数和方法。