父子组件传值
父组件向子组件传值
父组件使用子组件时传值,在子组件中声明props使用即可
<!-- 父组件给子组件传值的父组件 -->
<template>
<div>
<h2>父组件</h2>
<button @click="changeNum">change parent num</button>
<!-- vue属性 加冒号的说明后面的是一个变量或者表达式;没加冒号的后面就是对应的字符串字面值 -->
<Children :num="num" name="name" />
</div>
</template>
<script>
import Children from './Children';
export default {
name: 'Parent',
components: {
Children
},
data() {
return {
num: 1,
name: 'dyx'
}
},
methods: {
changeNum() {
this.num += 1;
},
},
}
</script>
<style>
</style>
<!-- 父组件给子组件传值的子组件 -->
<template>
<div>
<h2>子组件</h2>
<span>父组件传递的值 num:{{num}} name: {{name}}</span>
</div>
</template>
<script>
export default {
name: 'Children',
props: {
num: {
type: Number,
default: 0,
},
name: {
type: String,
default: 'douyaxing',
},
}
}
</script>
<style>
</style>
子组件向父组件传值
父组件使用子组件时传一个方法,在子组件中使用this.$emit调用父组件传递的方法即可
<!-- 子组件给父组件传值的父组件 -->
<template>
<div>
<h2>父组件</h2>
<div>子组件传递给父组件的值{{childNum}}</div>
<Children @childChange="childChange" />
</div>
</template>
<script>
import Children from './Children';
export default {
name: 'Parent',
components: {
Children
},
data() {
return {
childNum: '',
}
},
methods: {
childChange(childValue) {
this.childNum = childValue;
},
},
}
</script>
<style>
</style>
<!-- 子组件给父组件传值的子组件 -->
<template>
<div>
<h2>子组件</h2>
<span>{{num}}</span><button @click="addNum">add num</button>
<div>
<button @click="toParent">将值传给父组件</button>
</div>
</div>
</template>
<script>
export default {
name: 'Children',
data() {
return {
num: 1,
}
},
methods: {
addNum() {
this.num += 1;
},
toParent() {
// 调用父组件传给子组件的方法将要传递给父组件的值最为方法的参数
this.$emit('childChange', this.num)
}
}
}
</script>
<style>
</style>
method
methods是方法,只要调用,方法就会执行;如果只有事件对象一个参数,调用时不用显示传递;如果有多个参数,将事件对象的参数放在其它参数后面。
<template>
<div>
<div style="font-size: 24px">{{num}}</div>
<div @click="changeNum">change to 2</div>
<div @click="changeNumToAny(5, $event)">change to 5</div>
<div @click="() => changeNumToAny(10)">change to 10</div>
<div style="font-size: 24px">{{num1}}</div>
<div @click="changeNum1">num1</div>
<div>
{{renderSomeThing()}}
</div>
</div>
</template>
<script>
export default {
name: 'MethodDemo',
data() {
return {
num: 0,
num1: 10,
}
},
methods: {
changeNum(e) {
// 如果只有事件对象一个参数,调用时不用显示传递
console.log(e.target);
this.num = 2;
},
changeNumToAny(newNum, e) {
// 如果有多个参数,将事件对象的参数放在其它参数后
console.log(newNum, e.target);
this.num = newNum;
// 改变后最新的值
console.log(this.num);
},
changeNum1() {
this.num1 += 1;
},
// 当在模板中直接调用时只要render一次就会调用一次
renderSomeThing() {
return this.num + 1;
}
}
}
</script>
<style>
</style>
computed
computed是计算属性, 作用是依赖其他属性得出想要的结果,可以获取值也可以手动修改值。如果依赖项没有变化多次访问计算属性,计算属性会立即返回之前的计算结果,不需要再次执行函数,可以有多个数据依赖。
默认的使用(只用get)获取值
依赖项发生变化时,获取最新的计算值
<!--只有get的使用 -->
<template>
<div>
<div style="font-size: 24px">{{num}}</div>
<div @click="addNum">add</div>
<div style="font-size: 24px">{{num1}}</div>
<div @click="addNum1">add1</div>
<div>
{{renderSomeThing}}
</div>
</div>
</template>
<script>
export default {
name: 'ComputedGetDemo',
data() {
return {
num: 0,
num1: 10,
}
},
methods: {
addNum() {
this.num += 1;
},
addNum1() {
this.num1 += 1;
},
},
computed: {
renderSomeThing() {
// 只有第一次或者this.num改变才会重新触发
return this.num + 1;
}
}
}
</script>
<style>
</style>
set的使用
当计算属性被认为的修改值时,会触发set方法
<!--有set的使用 -->
<template>
<div>
<div style="font-size: 24px">{{num}}</div>
<div @click="addNum">add</div>
<div style="font-size: 24px">{{num1}}</div>
<div @click="setComputed">setComputed</div>
<div>
{{renderSomeThing}}
</div>
</div>
</template>
<script>
export default {
name: 'ComputedGetDemo',
data() {
return {
num: 0,
num1: 10,
}
},
methods: {
addNum() {
this.num += 1;
},
setComputed() {
this.renderSomeThing = this.num + 20;
},
},
computed: {
renderSomeThing: {
get() {
return this.num + this.num1 + 1;
},
// 当修改对应computed的值时才会触发set
set(value) {
console.log(value, 'set');
this.num1 = value;
}
}
}
}
</script>
<style>
</style>
watch
watch是侦听器,监听某一个值的变化执行对应的操作。回调方法里面会传入监听属性的新旧值,可以根据需要进行相关判断。只能有一个依赖, 当侦听数据变化时需要进行异步操作或者计算量较大的操作时可以使用watch。除了监听data中的数据 还可以监听 props 、emit 、computed。
<template>
<div>
<div style="font-size: 24px">{{num}}</div>
<div @click="addNum">add</div>
<div style="font-size: 24px">{{info}}</div>
<div @click="changeInfo">changeInfo</div>
</div>
</template>
<script>
export default {
name: 'WatchDemo',
data() {
return {
num: 0,
info: {
name: 'dyx',
age: 23,
},
}
},
methods: {
addNum() {
this.num += 1;
},
changeInfo() {
// watch 直接监听监听不到对象属性的变化,需要添加deep 属性
this.info.name = "豆亚星";
},
},
watch: {
// 监听一些值的变化 当改变时触发此函数,第一次不会执行
num(newNum, oldNum) {
console.log(this.num); // 改变之后最新的值
console.log(newNum, oldNum); // 新的值和旧的值
},
info: {
handler(newInfo, oldInfo) {
// 监听引用类型数据时前后的数据相同,都是最新的值
console.log(newInfo);
console.log(oldInfo);
},
deep: true,
immediate: true // 加上此参数后第一次会执行
},
}
}
</script>
<style>
</style>
$nextTick
data数据的改变是同步的,更改之后可以获取到最新的改变后的值,但是和data联动的Dom的变化是异步的,如果想要获取data更改之后最新的Dom,需要使用$nextTick;在created钩子函数执行的时候如果有对DOM的操作一定要将DOM操作的代码放进Vue.nextTick()的回调函数中,因为此时的DOM并没有挂载和渲染。mounted钩子函数执行时所有的DOM挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题。
<template>
<div>
<div style="font-size: 24px" ref="numDom">{{num}}</div>
<div @click="addNum">add</div>
</div>
</template>
<script>
export default {
name: 'NextTickDemo',
data() {
return {
num: 0,
}
},
methods: {
addNum() {
this.num += 1;
// <div style="font-size: 24px">1</div>
console.log(this.$refs.numDom);
// 0
console.log(this.$refs.numDom.innerHTML);
this.$nextTick(() => {
// 1 可以获取到异步更新的最新dom数据
console.log(this.$refs.numDom.innerHTML, 'nextTick');
})
},
},
}
</script>
<style>
</style>
v-model
v-model 的值只能是一个变量 不能是一个表达式
- .lazy修饰符修改了我们的v-model,所以它只在更改事件之后同步。这减少了v-model试图与Vue实例同步的次数,在某些情况下,还可以提高性能
- .number修饰符 确保将我们的值作为数字处理
- .trim修饰符在返回值之前删除开头或结尾的空白
自定义组件使用v-model
组件上使用 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,model 选项可以可以改变prop和事件
- model 选项的使用
// 父组件
<template>
<div>
<children v-model="value" />
<p> Value: {{ value }} </p>
</div>
</template>
<script>
import Children from './Children.vue'
export default {
name: 'Parent',
components: {
Children,
},
data() {
return {
value: 'dyx',
}
}
}
</script>
// 子组件
<template>
<div>
<label>name-children</label>
<input
type='text'
:value='value'
placeholder='Input'
@input='$emit("changeValue", $event.target.value)'
/>
</div>
</template>
<script>
export default {
name: 'Children',
props: {
value: String
},
model: {
prop: 'value',
event: 'changeValue'
},
}
</script>
- 默认的使用
// 父组件
<template>
<div>
<children v-model="value" />
<p> Value: {{ value }} </p>
</div>
</template>
<script>
import Children from './Children.vue'
export default {
name: 'Parent',
components: {
Children,
},
data() {
return {
value: 'dyx',
}
}
}
</script>
// 子组件
<template>
<div>
<label>name-children</label>
<input
type='text'
:value='value'
placeholder='Input'
@input='$emit("input", $event.target.value)'
/>
</div>
</template>
<script>
export default {
name: 'Children1',
props: {
value: String
},
}
</script>
生命周期
父子组件生命周期执行顺序
- 加载渲染过程:父 beforeCreate ->created ->beforeMount ->子 beforeCreate ->created ->beforeMount ->mounted ->父 mounted
- 更新过程:父 beforeUpdate->子 beforeUpdate->updated->父 updated
- 销毁过程:父 beforeDestroy->子 beforeDestroy->destroyed->父 destroyed
keep-alive专属
- activated keep-alive专属,组件被激活时调用 第一次激活也会触发
- deactivated keep-alive专属,组件被销毁时调用
ref
通过ref获取Dom
<!-- 通过ref获取dom元素 -->
<template>
<div>
<div ref="refDom">dom元素</div>
<div @click="getDom">获取dom</div>
</div>
</template>
<script>
export default {
name: 'DomDemo',
methods: {
getDom() {
// dom 元素
console.log(this.$refs.refDom.innerHTML);
},
},
}
</script>
<style>
</style>
通过ref获取组件实例
<!-- 通过ref获取子组件实例demo的父组件 -->
<template>
<div>
<h2>父组件</h2>
<button @click="getChildrenCom">获取子组件实例</button>
<Children ref="childrenCom" />
</div>
</template>
<script>
import Children from './Children';
export default {
name: 'Parent',
components: {
Children
},
methods: {
getChildrenCom() {
// 调用子组件的方法
this.$refs.childrenCom.addNum();
// 获取子组件的data(更新后的值)
console.log(this.$refs.childrenCom.num);
},
},
}
</script>
<style>
</style>
<!-- 通过ref获取子组件实例demo的子组件 -->
<template>
<div>
<h2>子组件</h2>
<span>{{num}}</span>
</div>
</template>
<script>
export default {
name: 'Children',
data() {
return {
num: 0,
}
},
methods: {
addNum() {
this.num = 2;
},
},
}
</script>
<style>
</style>
Switch Component 动态渲染不同的组件
通过
<component />组件和 :is属性实现
动态渲染组件的销毁形式
已经渲染过的组件的内部数据改变之后在销毁之后不会保留,再次渲染组件将会使用组件的初始数据
<!-- 动态组件的销毁形式 -->
<template>
<div>
<!-- 切换组件之后组件会重新渲染不会保留原来的数据 -->
<button @click="changeCom('DemoOne')">显示组件1</button>
<button @click="changeCom('DemoTwo')">显示组件2</button>
<component :is="currentCom" />
</div>
</template>
<script>
import DemoOne from './DemoOne';
import DemoTwo from './DemoTwo';
export default {
name: 'DestoryDemo',
data() {
return {
currentCom: 'DemoOne',
}
},
methods: {
changeCom(com) {
this.currentCom = com;
}
},
components: {
DemoOne,
DemoTwo,
},
}
</script>
<style>
</style>
<!-- 动态组件的销毁形式Demo1 -->
<template>
<div>
<h1>{{num}}</h1>
<button @click="addNum">destoryNumOne+1</button>
</div>
</template>
<script>
export default {
name: 'DemoOne',
data() {
return {
num: 1,
}
},
methods: {
addNum() {
this.num += 1;
}
},
}
</script>
<style>
</style>
<!-- 动态组件的销毁形式Demo2 -->
<template>
<div>
<h1>{{num}}</h1>
<button @click="addNum">destoryNumTwo+1</button>
</div>
</template>
<script>
export default {
name: 'DemoTwo',
data() {
return {
num: 1,
}
},
methods: {
addNum() {
this.num += 1;
}
},
}
</script>
<style>
</style>
动态组件的缓存形式
已经渲染过的组件的内部数据改变之后在销毁之后会保留,再次渲染组件将会使用上次渲染改变后的数据,借助
<keep-alive>组件实现。
<!-- 动态组件的缓存形式 -->
<template>
<div>
<button @click="changeCom('DemoOne')">显示组件1</button>
<button @click="changeCom('DemoTwo')">显示组件2</button>
<!-- 切换组件后失活的组件会被缓存,上次渲染时的数据等保留 -->
<keep-alive>
<component :is="currentCom" />
</keep-alive>
</div>
</template>
<script>
import DemoOne from './DemoOne';
import DemoTwo from './DemoTwo';
export default {
name: 'AliveDemo',
data() {
return {
currentCom: 'DemoOne',
}
},
methods: {
changeCom(com) {
this.currentCom = com;
}
},
components: {
DemoOne,
DemoTwo,
},
}
</script>
<style>
</style>
<!-- 动态组件的缓存形式Demo1 -->
<template>
<div>
<h1>{{num}}</h1>
<button @click="addNum">aliveNumOne+1</button>
</div>
</template>
<script>
export default {
name: 'DemoOne',
data() {
return {
num: 1,
}
},
methods: {
addNum() {
this.num += 1;
}
},
}
</script>
<style>
</style>
<!-- 动态组件的缓存形式Demo2 -->
<template>
<div>
<h1>{{num}}</h1>
<button @click="addNum">aliveNumTwo+1</button>
</div>
</template>
<script>
export default {
name: 'DemoTwo',
data() {
return {
num: 1,
}
},
methods: {
addNum() {
this.num += 1;
}
},
}
</script>
<style>
</style>
子组件改变父组件的数据
非简写形式
父组件给子组件传递方法,传递的方法中改变父组件的数据
<!-- 子组件改变父组件数据的父组件 -->
<template>
<div>
<h2>父组件{{num}}</h2>
<button @click="toggleShow(true)">父组件中显示子组件</button>
<!-- @childChange 也可以使用 @update:isShow 的形式代替 -->
<Children v-if="isShow" @childChange="toggleShow" @update:num="changeNum" />
</div>
</template>
<script>
import Children from './Children';
export default {
name: 'Parent',
components: {
Children
},
data() {
return {
isShow: false,
num: 0,
}
},
methods: {
toggleShow(show) {
this.isShow = show;
},
changeNum(newNum) {
this.num = newNum;
}
},
}
</script>
<style>
</style>
<!-- 子组件改变父组件数据的子组件 -->
<template>
<div>
<h2>子组件</h2>
<div>
<button @click="changeVisible">在子组件内部修改父组件的值从而控制子组件的显示</button>
<button @click="changeNum">在子组件内部修改父组件中num的值</button>
</div>
</div>
</template>
<script>
export default {
name: 'Children',
methods: {
changeVisible() {
this.$emit('childChange', false);
},
changeNum() {
this.$emit('update:num', Math.random());
},
}
}
</script>
<style>
</style>
使用.sync语法糖
使用.sync操作符之后不用再单独传递此属性
<!-- 使用sync修饰符子组件改变父组件数据的父组件 -->
<template>
<div>
<h2>父组件{{num}}</h2>
<button @click="toggleShow(true)">父组件中显示子组件 sync</button>
<!-- 可以将 isShow.sync 理解为语法糖 用于在子组件中修改isShow的值 -->
<Children v-if="isShow" @update:num="changeNum" :isShow.sync="isShow" />
</div>
</template>
<script>
import Children from './Children';
export default {
name: 'Parent',
components: {
Children
},
data() {
return {
isShow: false,
num: 0,
}
},
methods: {
toggleShow(show) {
this.isShow = show;
},
changeNum(newNum) {
this.num = newNum;
},
},
}
</script>
<style>
</style>
<!-- 使用sync修饰符子组件改变父组件数据的子组件 -->
<template>
<div>
<h2>子组件</h2>
<div>
<button @click="changeVisible">在子组件内部修改父组件的值从而控制子组件的显示</button>
<button @click="changeNum">在子组件内部修改子组件的num值</button>
</div>
</div>
</template>
<script>
export default {
name: 'Children',
data() {
return {
num: 1,
}
},
methods: {
changeVisible() {
this.$emit("update:isShow", false)
},
changeNum() {
this.$emit('update:num', Math.random());
},
}
}
</script>
<style>
</style>
slot
简单使用
父组件希望控制子组件额外显示的内容可以通过slot实现
<!-- slot简单使用的父组件 -->
<template>
<div>
父组件
<Children>
<p>父组件给子组件的插槽内容</p>
</Children>
</div>
</template>
<script>
import Children from './Children';
export default {
name: 'Parent',
components: {
Children
},
}
</script>
<style>
</style>
<!-- slot简单使用的子组件 -->
<template>
<div class="slotOne">
<div>我是子组件</div>
<!-- 显示的内容就是父组件中使用子组件中的组件间的内容 -->
<slot></slot>
</div>
</template>
<script>
export default {
name: 'Children',
}
</script>
<style>
</style>
默认值的使用
如果父组件使用时没有定义内容则使用子组件定义的默认值
<!-- slot的默认值的使用的父组件 -->
<template>
<div>
父组件
<!-- 传值 -->
<!-- <Children>
<p>父组件给子组件的插槽内容</p>
</Children> -->
<!-- 不传值 -->
<Children />
</div>
</template>
<script>
import Children from './Children';
export default {
name: 'Parent',
components: {
Children
},
}
</script>
<style>
</style>
<!-- slot的默认值的简单使用的子组件 -->
<template>
<div class="slotOne">
<div>我是子组件</div>
<!-- 父组件有传值的话使用父组件传的,没有传值的话使用自己默认的 -->
<slot>父组件使用没有传值的时候使用此默认值</slot>
</div>
</template>
<script>
export default {
name: 'Children',
}
</script>
<style>
</style>
具名插槽
有名字的使用父组件中标准slot对应的内容,没有名字的使用父组件中没有标注slot的所有
<!-- 有名字的slot的使用的父组件 -->
<template>
<div>
我是父组件
<Children>
<p>没有名字的1</p>
<template slot="header">
<p>我是name为header的slot</p>
</template>
<p slot="footer">我是name为footer的slot</p>
<p>没有名字的2</p>
</Children>
</div>
</template>
<script>
import Children from './Children';
export default {
name: 'Parent',
components: {
Children
},
}
</script>
<style>
</style>
<!-- 有名字的slot的使用的子组件 -->
<template>
<div>
<div>我是子组件</div>
<!-- 使用父组件中slot="header" 的template标签的子元素 -->
<slot name="header"></slot>
<!-- 使用父组件中 Children 标签中 没有标注slot的内容进行显示 -->
<slot></slot>
<!-- 使用父组件中slot="footer" 的template标签的子元素 -->
<slot name="footer"></slot>
</div>
</template>
<script>
export default {
name: 'Children',
}
</script>
<style>
</style>
编译作用域
父组件定义的slot的内容使用到的data是当前父组件的数据
<!-- slot编译作用域的父组件 -->
<template>
<div>
我是父组件
<Children>
<!-- 使用的数据是父组件中定义的数据并非子组件的 -->
<p>{{name}}</p>
</Children>
</div>
</template>
<script>
import Children from './Children';
export default {
name: 'Parent',
data() {
return {
name: 'dyx'
}
},
components: {
Children
},
}
</script>
<style>
</style>
<!-- slot编译作用域的子组件 -->
<template>
<div>
<slot></slot>
{{name}}
</div>
</template>
<script>
export default {
name: 'Children',
data() {
return {
name: 'douyaxing'
}
}
}
</script>
<style>
</style>
作用域插槽
父组件定义的slot的内容使用子组件的数据
<!-- 作用域插槽的父组件 -->
<template>
<div>
我是作用域插槽父组件
<Children>
<!-- 在父组件上使用slot-scope属性,user.data就是子组件传过来的值 -->
<template slot-scope="user">
<div v-for="(item, index) in user.data" :key="index">
{{item}}
</div>
</template>
</Children>
</div>
</template>
<script>
import Children from './Children';
export default {
name: 'Parent',
components: {
Children
},
}
</script>
<style>
</style>
<!-- 作用域插槽的子组件 -->
<template>
<div>
作用域插槽的子组件
<!-- 在子组件的slot标签上绑定需要的值 -->
<slot :data="user"></slot>
</div>
</template>
<script>
export default {
name: 'Children',
data() {
return {
user: [
{ name: 'dyx' },
{ name: 'douyaxing' },
]
}
}
}
</script>
<style>
</style>
props的类型检验
对象或数组默认值必须通过一个函数返回
props: {
disabled: {
type: Boolean, // 类型
default: false, // 默认值
required: true, // 是否必选
},
defaultValues: {
type: Array,
default: () => [], // 对象或数组默认值必须通过一个函数返回
},
}
scoped
- 给HTML的节点加一个不重复data属性来表示节点的唯一性,在每句css选择器的末尾(编译后的生成的css语句)加一个当前组件的data属性选择器来私有化样式,如果组件内部包含有其他组件,只会给其他组件的最外层标签加上当前组件的data属性
- scoped 样式中的一个选择器能够作用得“更深”,例如影响子组件, 可以使用 >>> 操作符 或者使用 /deep/ 操作符
<span data-v-5bebb5b4="" class="title">text</span>
.title[data-v-5bebb5b4] {
font-size: 16px;
color: #1b2733;
}
antd vue的使用记录
- optionLabelProp select的使用必选在option上加上使用的属性
- table 中浮层的滚动问题
// table的浮层渲染问题
:get-popup-container="triggerNode => $refs.table.$el"
- table的自定义渲染
// 名称列自定义title
<span slot="customName" @click="toggleSort('name')">
名称<a-icon type="arrow-down" />
</span>
// 渲染自定义(text时对应的dataIndex的属性值, record是整条数据)
<div slot="name" slot-scope="text, record">
{{ text || '-' }}
</div>
{
slots: { title: 'customName' }, // title自定义
dataIndex: 'name',
scopedSlots: { customRender: 'name' }, // 显示内容自定义
},
- table的单元格显示省略,设置了ellipsis 属性 如果需要自定义渲染该列,自定义渲染的标签使用行内标签才可正常显示
- tree组件拖拽时 onDrop 方法的数据中 dropToGap属性值 为true 表示 拖拽到目标节点下方 值为false 表示拖拽到目标节点内部,拖拽后的数据要处理这两种形式
使用方法动态渲染元素
- 如果直接在template中使用方法只能在方法中返回纯文本显示
- 如果在v-html指令使用可以返回标准html元素,但不能返回UI组件
脚手架搭建项目
// 全局安装
npm install -g vue-cli
// 查看安装情况 大写V
vue -V
// 基于webpack的项目初始化
vue init webpack
细节记录
- vue 属性中 加冒号的,说明后面的是一个变量或者表达式;没加冒号的后面就是对应的字符串字面量
- data方法可以不写但是不能不返回内容
- vue不能再没有定义data或者props时直接在template中使用
- vue的data改变不是异步的可以在改变之后获取到最新的数据,但是与data关联的dom变化是异步的
- this.$createElement 可以在vue中动态创建元素以及UI组件
- created生命周期中可以获取到props和data中的数据
- 可以在created生命周期中将一个method方法处理成debounce形式的方法
created() {
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
},
methods: {
getAnswer() {
}
}
- 使用国际化传递参数
$t是挂到了Vue.prototype上的一个方法,接受一个字符串作为参数
// 取值就是解构 数组同理
"new_name": "新的{n}名字",
{{ $t('new_name', { n: '1-2' }) }}
- 相同路由下跳转的报错修复
// 解决相同路由下跳转的报错
const originalPush = Router.prototype.push;
Router.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}