获取当前组件
vue3提供了一个getCurrentInstance方法用来获取当前组件的实例
<template>
<div class="parent">
{{ msg }}
</div>
</template>
<script lang="ts">
import { defineComponent, getCurrentInstance } from "vue";
export default defineComponent({
setup() {
const instance = getCurrentInstance();
console.log(instance);
let msg = "我是父组件";
return { msg };
},
});
</script>
<style scoped>
.parent {
color: rgb(233, 35, 0);
position: relative;
font-size: 30px;
}
</style>
调用子组件的方法
setup的第二个参数上有一个expose 属性,这是vue3.2+才出现的内容,通过expose 可以将该组件内部的一些方法等对外进行暴露
<template>
<div class="children">
<h2>我是子组件</h2>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
setup(props, { expose }) {
let counter = ref(0);
const setCounter = (count: number) => {
counter.value = count;
};
expose({
setCounter,
});
return { counter };
},
});
</script>
然后父组件通过ref绑定子组件之后,就可以调用子组件暴露出来的setCounter函数了
<template>
<div class="parent">
<Children ref="childrenRef"></Children>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, ref } from "vue";
import Children from "./Children.vue";
export default defineComponent({
components: {
Children,
},
setup() {
const childrenRef = ref(null);
onMounted(() => {
childrenRef.value.setCounter(2);
});
return { childrenRef };
},
});
</script>
再来看一个例子
假如有这么一个需求,需要你将Children以插槽的方式传进Parent组件,
<template>
<div class="parent">
<slot></slot>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
setup() {
return {};
},
});
</script>
并且Parent组件内部要对插槽的内容进行校验,必须是Children组件。再创建一个test.vue
// test.vue
<template>
<div>
<Parent>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
</Parent>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import Parent from "./components/Parent.vue";
import Children from "./components/Children.vue";
export default defineComponent({
components: {
Parent,
Children,
},
setup() {
return {};
},
});
</script>
需求的意思就是Parent组件内部要进行校验,总不可能将Parent内部的直接子元素一一绑定ref吧?这样太过冗余,如果传入了上百个Children组件呢?更麻烦了。
所以还是要来说说setup的参数了,setup第二个参数context上有一个属性slots,slots上又有一个方法default,该方法的返回值就是一个插槽内容的数组
<template>
<div class="parent">
<slot></slot>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
setup(props, context) {
console.log(context);
const defaults = context.slots.default()
console.log(defaults);
return {};
},
});
</script>
接下来在Parent.vue中导入Children组件,并在test.vue的Parent组件中添加一个div
<Parent>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<div>我是div</div>
</Parent>
然后Parent组件内部进行判断
<template>
<div class="parent">
<slot></slot>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import Children from "./Children.vue";
export default defineComponent({
setup(props, context) {
const defaults = context.slots.default();
defaults.forEach((item) => {
console.log(item.type === Children);
});
return {};
},
});
</script>
props的.sync在vue3中被移除
- vue2中写法:
组件内部:
定义
props:{name: String}
更新:$emit('update:name', 'xxxxx')
调用组件时::name.sync="name"
- vue3中:
组件内部:
定义:
props:{name: String},emits:['update:name'],
更新:$emit('update:name', 'xxxxx')
调用组件时:v-model:name="name"
参考分页控件
在setup() 里调用this.$xxxx 全局方法
// getCurrentInstance 获取当前实例
import { getCurrentInstance } from ‘vue’
const { ctx } = getCurrentInstance()
ctx.$xxxx
在reactive里包含 ref的值时 不需要.value 否则会丢失响应
错误写法:
const name= ref('')
const body = reactive({
params: name.value // 会丢失响应
})
正确写法:
const name= ref('')
const body = reactive({
params: name
})
使用provide 跟inject依赖注入时,provide 的是响应式对象,那inject的时候也是响应式对象。但是在reactive里包含 ref的值时 不需要.value 否则会丢失响应
reactive 不可以全量赋值,否则会丢失响应,如下:
let body = reactive({
params: 'text'
})
错误: body = {}
正确:body.params = 'text2'
这里我们可以封装一个函数用来快速赋值 reactive,并且页面会响应。代码如下:
/**
* 将reactiveObj对象转换成targetObj对象的格式
* 为解决 reactiveObj直接赋值targetObj还能在页面上进行响应
* @param {reactive} reactiveObj [setup中需要赋值的reactive对象]
* @param {Object} targetObj [目标对象]
*/
export const setReactiveObj = (reactiveObj, targetObj) => {
if (Array.isArray(targetObj)) {
if (reactiveObj && reactiveObj.length) {
reactiveObj.length = 0
}
}
for (const key in targetObj) {
if (Object.hasOwnProperty.call(targetObj, key)) {
const val = targetObj[key]
reactiveObj[key] = val
}
}
}
// 用法也很简单,例子如下
// 打开配置页
function openDrawer(row) {
drawer.value = true
setReactiveObj(rowData, row) // rowData 是 reactive响应式代理对象,row是普通的对象
getInfo(rowData.id)
}
element-plus 中的tabs 组件,会默认加载所有tab的里面的内容,并不是只在切换的时候才加载。他的原理是显示隐藏,类似v-show
项目编译的时候不报错,但是一直卡住在某个步骤比如一直卡在 98%。造成的原因很大一部分是因为某个组件中引入其他路径有问题。不存在或者错误写法。例如这么写: import {} from ''
表单如果只有一个input的时候,回车会触发表单的提交导致页面刷新。这个问题原生上就有,注意加上@submit.prevent,阻止默认行为
解决打包生产环境的时候报错 INTLIFY_PROD_DEVTOOLS is not defined
只需要在vue.config.js里面配置下面这句即可
// 解决打包生产环境的时候报错 __INTLIFY_PROD_DEVTOOLS__ is not defined
new webpack.DefinePlugin({
__INTLIFY_PROD_DEVTOOLS__: JSON.stringify(false)
})
完整代码下图
更加规范的props和emits
在vue3中,父子组件传值的props和emits写法更加规范(命名更统一),体现在:v-model的变化
<template>
<child-component v-model:value="myValue"></child-component>
</template>
v-model:value等同于props:'value'和emits('update:value')
需要指定emits,为了便于管理,建议在emits中定义所有用到的emit
export default {
emits: ['update:value', 'otherEmit'],
setup(props, { emit }) {
emit('update:value')
emit('otherEmit')
},
}
$listeners被移除
事件监听器也被包含还在了$attrs中,现在属性透传更方便了
$children 被移除
如果想访问子组件,使用$refs
。
事件API被移除
$on,$off,$once
不再使用。2.x的EventBus方法不能再使用。
Filter被移除
不能再用|
使用filter。Sad。
当使用 watch
选项侦听数组时,只有在数组被替换时才会触发回调。换句话说,在数组被改变时侦听回调将不再被触发。要想在数组被改变时触发侦听回调,必须指定 deep
选项
watch: {
bookList: {
handler(val, oldVal) {
console.log('book list changed')
},
deep: true
},
}
参考文档:
www.jianshu.com/p/b89b94c41…
www.jianshu.com/p/a777d61ce…