Vue2.7 ::v-deep 替换为 :deep 正则表达式
::v-deep\s(.*)\s
:deep($1)
或者
::v-deep\s(.*)\s\{
:deep($1) {
::v-deep 警告:
原因:css深度更改样式语法变化,将::v-deep .header 替换为 :deep(.header)即可解决。
vue2.7引入vue-router报错
原因:vue3 使用的是vue-router4,而vue2.7使用的是vue-router3
先将vue-router升级至3.6.5以上,然后使用以下语法
import { useRouter, useRoute } from 'vue-router/composables'
const $router = useRouter()
$router.push('/home)
或者 当前安装 Vue 2.7.14 版本,支持
在项目 src/utils 下创建 vueApi.js 文件:
import { getCurrentInstance } from 'vue'
// 访问vuex
export const useStore = () => {
const vm = getCurrentInstance()
if (!vm) throw new Error('must be called in setup')
return vm.proxy.$store
}
// 访问router
export const useRouter = () => {
const vm = getCurrentInstance()
if (!vm) throw new Error('must be called in setup')
return vm.proxy.$router
}
// 访问route
export const useRoute = () => {
const vm = getCurrentInstance()
if (!vm) throw new Error('must be called in setup')
return vm.proxy.$route
}
但是在组合式API中 vuex 的 mapState, mapGetters, mapActions 和 mapMutations 辅助函数是无法使用的。
要在 vue devtools 查看页面中的内容信息,需要将 vue devtools 升级到 6.2.0 以上版本。
vue2.7 使用动态组件<component :is='xxx'报错:Unknown custom element: - did you register the component correctly
如下所示定义一个对象,将组件放入即可。
<component
:is="compents[currentComponent]"
/>
<script setup>
import participants from './components/participants/index.vue'
import planInformation from './components/planInformation/index.vue'
import plannedCourses from './components/plannedCourses/index.vue'
const compents = { participants, planInformation, plannedCourses }
<script/>
setup中使用optionsApi中的data值
function useProxy() {
return getCurrentInstance().proxy;
}
const proxy = useProxy();
console.log(proxy.listQuery);
getCurrentInstance 只在 setup 或生命周期钩子中工作:
注意:getCurrentInstance 作为访问内部组件实例的方法,官方是不鼓励在应用程序代码中使用的,下面贴上官方原文及例子:
[Vue warn]: Failed to mount component: template or render function not defined.报错解决
今天突然项目遇到这个报错
网上这种错误可能由不同原因导致的,最后发现我这边报这个错是因为文件我路由引入组件时候没有写后缀xxx.vue,我没写.vue, 此时刚好这个路由下有个同名的js文件,那么由于我这边配置 js文件匹配优先级高就会导致加载路由失败,页面没有出来,渲染失败。
如我的文件:
SmartCampusServices文件名一样
但是我的路由:
没有写后缀
而我的webpack配置优先找js
就导致了报错。
解决:
加上.vue后缀或者js换个名称啦。
错误原因一:
You might be running into the breaking change described here: github.com/vuejs/vue-l…
修改方法
1: component: (resolve) => require([’@/views/home/home.vue’], resolve),
2: component: require(’…/components/movie/movie.vue’).default
错误原因二:
目录中有相同文件名的vue文件与js文件
修改方法:
require时带上后辍名
注意组件名称不能和ref的名称一样,否则会报错
[Vue warn]: Failed to mount component: template or render function not defined.
found in
---> <Anonymous>
<ElCol>
<ElRow>
<Dictionary>
<AppMain> at src/pages/console/views/layout/components/AppMain.vue
<Layout> at src/pages/console/views/layout/layout.vue
<App> at src/pages/console/App.vue
<Root>
# 注意 ref需要导出到vue页面中才能使用
子组件的事件需要暴露给父组件,父组件才可以使用refs.xxx进行调用
vue3 $refs的使用
一、vue2语法
vue2语法在组件上设置ref属性后,在代码里可以通过 this.$refs.ref值 访问到对应的子组件。
一个设置ref值的组件:
在js代码中可以通过如下代码访问到这个组件:
this.$refs.usernameInput
可以调用里面的方法:
// 假设 base-input 组件内有方法foo
this.$refs.usernameInput.foo();
详细使用可以参考底部列出的参考文章。
二、vue3使用
网上找了一些文章比较零散,而且试了下都不能用,但是通过这些文章了解到了一些关键信息,最后整理出如下几步:
1. 组件设置ref值
这个和vue2的类似,父组件调用子组件的时候设置ref值。
2. 组件实例获取
设置完成后,vue3可以通过ref方法获取。
const childRef = ref();
这边变量的名字需要和上面ref的一致。如何直接打印childRef,这个时候会是:
undefined
因为页面组件还没有挂载完成,所以需要在挂载完成之后才能正常使用。
onMounted(() => {
console.log(childRef.value); // Proxy {…}
});
3. 子组件内设置对外公开的变量
上面第2步获取到子组件实例后,无法使用子组件内的方法,因为使用 script setup 的组件默认是关闭的,如果需要公开,需要使用 defineExpose 编译器宏。
// 子组件代码
const foo = () => {
console.log("foo");
}
defineExpose({
foo
});
父组件内调用:
// 调用子组件方法
childRef.value.foo(); // foo
这样就可以调用到子组件的方法了。
查看childRef.value,也可以看到其中公开的foo方法:
vue3父组件调用子组件方法
图片加载失败
该图片来自外部链接,外部链接已失效
请将原图保存到本地后上传,打开图片链接
完整参考代码:
父组件:
<template>
<ChildVue ref="childRef" />
</template>
<script setup lang="ts">
import { ref } from '@vue/reactivity';
import { onMounted } from '@vue/runtime-core';
import ChildVue from './Child.vue';
const childRef = ref();
console.log(childRef.value); // undefined
onMounted(() => {
console.log(childRef.value); // Proxy {…}
// 调用子组件方法
childRef.value.foo(); // foo
});
</script>
<style>
</style>
子组件:
<template>child demo</template>
<script setup lang="ts">
const foo = () => {
console.log("foo");
}
defineExpose({
foo
});
</script>
<style>
</style>
【Bug记录】[@vue/compiler-sfc] defineProps is a compiler macro and no longer needs to be imported
Vue3项目遇到编译警告
错误翻译
- 英文:[@vue/compiler-sfc]
- 翻译:Vue 单文件组件 (SFC) 编译警告。
- 原文:defineProps is a compiler macro and no longer needs to be imported.
- 翻译:defineProps 只是编译器宏,不再需要导入。
- 原文:defineEmits is a compiler macro and no longer needs to be imported.
- 翻译:defineEmits 只是编译器宏,不再需要导入。
错误归因
- 项目使用
- 通过 import 导入了 defineProps 和 defineEmits
- Vue3.2 版本后 defineProps 和 defineEmits 无需导入
官方文档已更新
解决方案🎯
🎯 删除 defineProps 或 defineEmits 的导入语句即可,对象项目没有造成任何影响。
参考代码如下:
<script setup lang="ts">
// 🎯 删除 `defineProps` 或 `defineEmits` 的导入语句即可。
-import { defineProps, defineEmits } from 'vue-demi'
const props = defineProps({
modelValue: {
type: Boolean
}
})
const emit = defineEmits<{
(e: 'update:modelValue', value: boolean): void
(e: 'change', value: boolean): void
}>()
// ...其他代码省略
</script>
Ref相关问题
如何在Vue3中正确获取组件的this.$el?
<template>
<div ref="el"></div>
</template>
import { ref, onMounted } from 'vue'
export default {
setup() {
const el = ref(null);
// Not available until the component mounts:
onMounted(() => {
console.log(el.value)
})
return {
el
}
}
}
setup时候调用
[Vue warn]: Error in v-on handler: "Error: must be called in setup"
正确写法
Vue3组件通信之 defineExpose
子组件通过defineExpose 暴露方法给父组件,父组件用ref调用子组件的方法
vue3使用 setup 语法糖后如何在父组件用ref调用子组件的方法?
defineExpose要在变量和方法声明定义之后再使用,否则浏览器的控制台会输出很多警告,并且最终将该页面卡死。
`Vue3`中的`setup`默认是封闭的,如果要从子组件向父组件暴露属性和方法,需要用到`defineExpose`
和defineProps, defineEmits一样,这三个函数都是内置的,不需要import.
不过defineProps, defineEmits都会返回一个实例,而defineExpose是无返回值的.
const props = defineProps({})
const emit = defineEmits([])
defineExpose({})
defineExpose的使用
子组件暴露方法给父组件,父组件通过子组件的ref获取到子组件实例,进行调用子组件通过defineExpose 暴露出的方法
子组件Child.vue
<template>
{{ name }}
</template>
<script setup>
import { ref } from 'vue'
const name = ref("Nicholas.")
const sayName = ()=>{
console.log("my name is "+name.value)
}
defineExpose({
name,
sayName
});
</script>
父组件Father.vue
<template>
<Child ref="child"></Child>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const child = ref(null)
onMounted(()=>{
console.log(child.value.name) // "Nicholas"
child.value.sayName() // "my name is Nicholas"
})
</script>
总结
向外暴露的时候变量会自动解包,比如上面子组件的name:ref<String>暴露到父组件的时候自动变成了name:String.
注:defineExpose一定要在变量和方法声明定义之后再使用。
Vue3中组件通信之defineProps属性
子组件通过 defineProps 接收父组件传过来的值
defineProps 是vue3提供的方法,不需要引入可以直接使用,用于子组件接收父组件传递的参数,且只读不可更改
二、使用样例
父组件代码
代码如下(示例):
<template>
<div class="box">
<h1>我是父组件</h1>
<hr />
<Child info="我是子组件" :money="money"></Child>
</div>
</template>
<script setup lang="ts">
//props:可以实现父子组件通信,props数据还是只读的!!!
import Child from "./Child.vue";
import { ref } from "vue";
let money = ref(10000);
</script>
<style scoped>
.box {
width: 100vw;
height: 400px;
background: yellowgreen;
}
</style>
子组件代码
代码如下(示例):
<template>
<div class="son">
<h1>我是子组件</h1>
<p>{{props.info}}</p>
<p>{{props.money}}</p>
<!--props可以省略前面的名字--->
<p>{{info}}</p>
<p>{{money}}</p>
<button @click="updateProps">修改props数据</button>
</div>
</template>
<script setup lang="ts">
//需要使用到defineProps方法去接受父组件传递过来的数据
//defineProps是Vue3提供方法,不需要引入直接使用
let props = defineProps(['info','money']); //数组|对象写法都可以
//按钮点击的回调
const updateProps = ()=>{
// props.money+=10; props:只读的
console.log(props.info)
}
</script>
<style scoped>
.son{
width: 400px;
height: 200px;
background: hotpink;
}
</style>
vue3组件通信之defineEmits事件
子组件通过 defineEmits 定义事件名称xxx,与父组件中给子组件绑定的方法进行对应,@xxx=要触发父组件的方法
子组件
defineEmits 定义事件名称xxx
父组件
@xxx=要触发父组件的方法
一、defineEmits是什么?
defineEmits 是vue3提供的方法,又称为自定义事件,不需要引入可以直接使用,用于子组件与父组件通信。
二、使用样例
父组件代码
代码如下(示例):
<template>
<div>
<h1>事件</h1>
<!-- vue3:原生的DOM事件不管是放在标签身上、组件标签身上都是原生DOM事件-->
<!-- 绑定自定义事件xxx:实现子组件给父组件传递数据 -->
<Event2 @xxx="handler3" @click="handler4"></Event2>
</div>
</template>
<script setup lang="ts">
//引入子组件
import Event2 from './Event2.vue';
const handler3 = (param1: any,param2: any)=>{
console.log(param1,param2);
}
//事件回调--5
const handler4 = (param1: any,param2: any)=>{
console.log(param1,param2);
}
</script>
<style scoped>
</style>
子组件代码
代码如下(示例):
<template>
<div class="child">
<p>我是子组件2</p>
<button @click="handler">点击我触发自定义事件xxx</button>
<button @click="$emit('click','AK47','J20')">点击我触发自定义事件click</button>
</div>
</template>
<script setup lang="ts">
//利用defineEmits方法返回函数触发自定义事件
//defineEmits方法不需要引入直接使用
let $emit = defineEmits(['xxx','click']);
//按钮点击回调
const handler = () => {
//第一个参数:事件类型 第二个|三个|N参数即为注入数据
$emit('xxx','东风导弹','航母');
};
</script>
<style scoped>
.child {
width: 400px;
height: 200px;
background: pink;
}
</style>
总结
vue3:原生的DOM事件不管是放在标签身上、组件标签身上都是原生DOM事件,利用defineEmits方法返回函数触发自定义事件,defineEmits方法不需要引入直接使用。
vue3组件传参之useAttrs
前言
useAttrs能够快速的获取到父组件在子组件标签上写的所有属性,不需要像defineProps一个一个去获取。
一、useAttrs是什么?
useAttrs是vue实例上组件传参的一种方法,类似于defineProps,使用该方法能够一次获取到子组件标签上的所有属性。
二、使用用例(el-button的二次封装)
1.在components文件中新建一个UseBuuton.vue文件 代码如下(示例): UseBuuton.vue
<template>
<div class="use-button" title="这是一个use-button">
<el-button :=$attrs >
<slot></slot>
</el-button>
</div>
</template>
<script setup lang='ts'>
import { useAttrs } from 'vue'
const $attrs = useAttrs()
console.log($attrs);
</script>
<style lang="scss" scoped></style>
2.在view中使用封装的组件
代码如下(示例)
<template>
<div class="about">
<el-button type="primary" :icon="Delete">el-button</el-button>
<use-button type="primary" :icon="Delete">use-button </use-button>
</div>
</template>
<script setup lang="ts">
import UseButton from '@/components/UseButton.vue';
import { Delete,Setting } from '@element-plus/icons-vue'
</script>
<style lang="scss" scoped></style>
当useAttrs和defineProps一起使用时,defineProps优先级会更高,useAttrs只能获取到defineProps没有获取的属性。