vue中import组件时,组件没有立即返回,导致组件无法注册,报错Unknown custom element

新手上路,请多包涵

问题描述

项目中通过v-for生成对应数量的容器,容器中根据条件加载对应的组件,我在加载的指标卡组件中,引入另一个tab容器组件时,发生了Unknown custom element报错,通过console,发现import后值是undefined,延迟1s打印可以获得正确结果

import tabContainer from '../tab/index.vue'
console.log('containerTab :>> ', tabContainer) // undefined
setTimeout(() => {
 console.log('containerTab :>> ', tabContainer) // Object
}, 1000)

进入tabContainer文件,将其中引入的left组件删除后,可以在指标卡中正常引入
left 文件内容

<template>
 <div class="grid-wrapper my-wrapper">
 <grid-layout
 :ref="gridLayoutName"
 :line-style="{color: '#C5533A', size: '1px'}"
 :layout="chartsOption"
 :col-num="containerInit.colNum"
 :row-height="containerInit.rowHeight"
 :use-css-transforms="containerInit.useCssTransforms"
 :is-draggable="!isDisDraggable"
 :margin= "containerInit.margin"
 >
 <grid-item
 v-loading="item.loading"
 v-for="(item) in chartsOption"
 :key="item.i"
 :x="item.x"
 :y="item.y || 0"
 :w="item.w"
 :h="item.h"
 :i="item.i"
 :min-h="containerInit.minH"
 drag-ignore-from=".container-inner"
 class="grid-item"
 :class="{
 active: item.selected,
 [`grid-item-${item.i}`]: true,
 'theme-grid-item': parseInt(item.id) === 0,
 'theme-grid-item-search': parseInt(item.id) === 2,
 'theme-grid-item-MetricCard': parseInt(item.id) == 0 && item.feature.chartId == '18'
 }"
 @click.native.stop="selectContainer(item.i)"
 @resized="resizeOrMove(item.i)"
 @moved="resizeOrMove(item.i)"
 @mouseenter.native.stop="showTips(item.i)"
 @mouseleave.native.stop="hideTips(item.i)"
 >
 <el-dropdown @visible-change="visibleChange" v-if="item.i == currentHoverContainerIndex && !isPreviewToggle" class="actions-btn" @click.native.stop @command="handleCommand">
 <span class="iconfont icon-More"></span>
 <el-dropdown-menu slot="dropdown" class="container-action-options">
 <el-dropdown-item :command="'b'+item.i" v-if="item.id==0">
 <span class="iconfont icon-copy"></span>
 复制
 </el-dropdown-item>
 <el-dropdown-item :command="'a'+item.i">
 <span class="iconfont icon-delect"></span>
 删除
 </el-dropdown-item>
 <el-dropdown-item :command="'c'+item.i" v-if="item.id !== 2 && item.id !== 3">
 <span class="iconfont icon-move1"></span>
 移动
 </el-dropdown-item>
 <el-dropdown-item :command="'d'+item.i" v-if="item.id === 0">
 <span class="iconfont icon-Viewdata"></span>
 查看查询条件
 </el-dropdown-item>
 </el-dropdown-menu>
 </el-dropdown>
 <div class="drag-handle" :class="{noShow: !item.nameToggle}">
 <span class="tig-title-pannel theme-tig-title-pannel-underTab" v-show="item.nameToggle">
 <span class="title-text theme-title-text-underTab">{{ item.name }}</span>
 <span calss="title-right" v-show="hasTitleSkin"><img :src="title_right_src"></span>
 <div class="newMoreData" :class="{'visualMoreData': isDisDraggable}" v-if="item.showMoreDataFlag" @click="getMoreData(item.i)">
 <span class="newMoreDataLabel">更多数据</span>
 <!-- <span class="newMoreDataArrow"></span> -->
 <img class="newMoreDataArrow" src="/static/charts/images/newMoreData.svg">
 </div>
 </span>
 </div>
 <!--标签提示-->
 <tip
 :cur-chart-option="item"
 :tip-style="'corner'"
 :metrics-id="item.feature.metricList"
 :is-tab="true"
 :opacity="tipsArr[item.i]"
 :class="{noTitle: !item.nameToggle}"
 v-if="item.id === 0"
 @handleCatQueryInfo="handleCatQueryInfo(item.i)"
 @dimNumberRange="dimNumberRangeHander(item.i)"
 >
 </tip>
 <!-- <container-inner :index="item.i">图表组件</container-inner> -->
 <lazy-box :index="item.i" :key="item.i" ref="lazyBox">图表组件</lazy-box>
 <border v-if="!isDisDraggable"></border>
 </grid-item>
 </grid-layout>
 <moveContainer ref="moveContainer"></moveContainer>
 <query-condition-dialog ref="queryConditionDialog"></query-condition-dialog>
 <!-- <dimRangeDialog ref="dimRangeDialog" :selected-option="chartsOptionCopy"></dimRangeDialog> -->
 </div>
</template>
  
<script>
import { GridLayout, GridItem } from '@suning/vue-grid-layout'
import { containerInit } from '../../static/configData'
import addPanel from './addPannel'
// import containerInner from './containerInner'
import lazyBox from './lazyBox'
import eventBus from '../../utils/eventBus'
import leftMixin from '../../layout/mixins/leftMixin/leftMixin'
import border from '../../layout/left/border'
import { getContainerByIndex, getGuid, isInHuiyanIframe, getHYOrigin, reportDefaultSearch } from '../../utils/utils'
import Utils from '@/components/Utils'
import api from '@/web-design/api/charts'
import bus from '../../utils/eventBus'
import moveContainer from '../../layout/moveContainer'
import queryConditionDialog from '../../layout/queryConditionDialog'
// import dimRangeDialog from '../../layout/right/focus/chartFocus/dimRangeSetting/dimRangeSettingDialog'
export default {
 name: 'Left',
 components: {
 GridLayout,
 GridItem,
 addPanel,
 border,
 lazyBox,
 moveContainer,
 queryConditionDialog
 // dimRangeDialog
 },
 mixins: [leftMixin],
 props: [
 'containerIndex', // 当前第几个容器
 'tabIndex' // tab页面index
 ],
 data() {
 return {
 containerInit,
 chartsOption: [], // 必须要有本地的chartsOption,如果直接用computed里会先加载,但是dom加载在后
 tipsArr: [],
 currentHoverContainerIndex: -1,
 showMoredataMenu: false,
 lastTop: 0 // 记录移动容器上次的top
 }
 },
 computed: {
 chartsOptionCopy() {
 return this.$store.state.charts.chartsOption.filter(
 item => !item.hide && !item.drop && item.tabContainerIndex === this.containerIndex && item.activeTabIndex == this.tabIndex
 )
 },
 isPreviewToggle() {
 return this.$store.state.charts.previewToggle && this.$route.path !== '/visual'
 },
 isDisDraggable() {
 return this.$route.path === '/visual' || this.$store.state.charts.previewToggle
 },
 isVisual() {
 return this.$route.path === '/visual'
 },
 chartsOptionAll() {
 return this.$store.state.charts.chartsOption
 },
 // 该layout布局在tab切中
 isLayoutInTab() {
 return true
 },
 gridLayoutName() {
 return `gridLayout_${this.tabIndex}`
 },
 hasTitleSkin() {
 // return config.title_left && config.title_right
 return this.$store.state.charts.themeService
 },
 // title_left_src () {
 //   return '/static/skin/spring/image/secondTitleLeft.png'
 // },
 title_right_src() {
 return '/static/skin/spring/image/secondTitleRight_modify.png'
 },
 handleContainerID() {
 const handleContainerID = {}
 this.chartsOptionAll.filter(item => {
 return !item.drop
 }).map(item => {
 return item.id
 }).forEach(item => {
 let containerID = handleContainerID[item]
 if (containerID >= 0) {
 handleContainerID[item] = ++containerID
 } else {
 handleContainerID[item] = 1
 }
 })
 return handleContainerID
 },
 systemConfig() {
 return this.$store.state.charts.systemConfig
 }
 },
 // 监听vuex上的chartsOption,实时改变本地的chartsOption
 watch: {
 chartsOptionCopy(value) {
 this.$nextTick(() => {
 this.chartsOption = value
 })
 }
 },
 mounted() {
 // 等dom加载完毕后再改变本地的chartsOption
 this.$nextTick(() => {
 this.chartsOption = this.chartsOptionCopy
 })
 },
 methods: {
 // 跳转到更多数据页
 async getMoreData(index) {
 let chartsOption = getContainerByIndex(this.chartsOptionAll, index)
 const selectedReport = chartsOption.selectedReport
 let selectedReportVersion = chartsOption.selectedReportVersion
 if (selectedReport == '' || selectedReportVersion == '') {
 this.$message({
 message: '未配置关联报表!',
 type: 'error'
 })
 return
 }
 const selectedSystemId = chartsOption.selectedSystemId
 const sourceQueryPanel = chartsOption.sourceQueryPanel
 const queryPanelSelected = chartsOption.queryPanelSelected
 const targetQueryPanel = chartsOption.targetQueryPanel
 const customReference = chartsOption.feature.customReference
 // 获取已上线的最新版本
 let res = await api.getLatestOnlineVersion({ reportId: selectedReport })
 // console.log(res)
 if (!res) {
 this.$message({
 message: '更多数据打开异常!',
 type: 'error'
 })
 return
 }
 if (res.statusCode == '0') {
 selectedReportVersion = res.data.versionId
 }
 let guidstr = this.getGuidStr() // 全局唯一标识符,用来确认唯一的链接参数
 let paramsObj = {
 linkIndex: guidstr,
 selectedReport: selectedReport,
 selectedReportVersion: selectedReportVersion
 }
 let queryParams = {
 reportId: selectedReport,
 versionId: selectedReportVersion
 }
 if (queryPanelSelected && sourceQueryPanel && targetQueryPanel) { // 有查询面板传参
 let queryInfoData = this.cloneQueryInoData(Number(sourceQueryPanel), index)
 if (queryInfoData) { // 查询面板是否有参数
 paramsObj.queryInfo = {
 targetQurryPanel: targetQueryPanel,
 value: queryInfoData
 }
 }
 }
 if (customReference && customReference.length != 0) { // 是否有自定义传参
 paramsObj.customReference = customReference
 }
 if (paramsObj.queryInfo || paramsObj.customReference) {
 queryParams.paramIndex = guidstr
 this.saveDetailParams(paramsObj)
 }
 // 慧眼环境 or 天工环境
 if (parent && isInHuiyanIframe() && !['alarm'].includes(this.$route.query.platform)) {
 queryParams.other = true
 let url = this.createDetailRouteUrl(queryParams, selectedSystemId)
 let myJson = { type: 'openUrl', reportId: selectedReport, url: url, paramIndex: queryParams.paramIndex ? queryParams.paramIndex : '' }
 let targetOrigin = getHYOrigin(window.env)
 console.log('[postMessage]', `ntype: ${myJson.type}nreportId: ${myJson.reportId}nparamIndex: ${myJson.paramIndex}nurl: ${myJson.url}`)
 // 发送poseMessage 给慧眼
 parent.postMessage(JSON.stringify(myJson), targetOrigin)
 } else {
 let url = this.createDetailRouteUrl(queryParams, selectedSystemId)
 // 生成的链接
 window.open(url)
 }
 },
 selectContainer(index) {
 // 关闭更多指标维度弹窗
 bus.$emit(`cloneDimMetric_${index}`)
 let selectedContainer = this.chartsOption.filter(each => each.i === index)[0]
 if (selectedContainer && selectedContainer.id === 0) {
 document.getElementById('dashboard').click()
 }
 this.$store.commit('selectedChange', index)
 },
 resizeOrMove(index) {
 this.$store.commit('resizeOrMove', this.chartsOption)
 this.$nextTick(() => {
 setTimeout(() => {
 eventBus.$emit(`resizeOrMove_${index}`, index)
 this.$emit('resize')
 }, 200)
 })
 },
 handleCommand(command) {
 if (command[0] === 'c') { // 移动容器
 this.$refs.moveContainer.showMoveContainer(command.slice(1))
 return
 }
 if (command[0] === 'a') { // 删除容器
 this.$store.commit('delContainer', command.slice(1))
 }
 if (command[0] === 'b') { // 复制容器
 this.checkAddContainer(this.handleContainerID) &&
 this.$store.commit('copyContainer', { index: command.slice(1) })
 }
 if (command[0] === 'd') { // 查看查询条件
 this.handleCatQueryInfo(command.slice(1))
 }
 this.selectContainer(command.slice(1))
 },
 checkAddContainer(obj) {
 if (!this.systemConfig.chartsNumber) return true
 let currentNumber = 0
 for (const key in obj) {
 currentNumber += obj[key]
 }
 if (currentNumber >= this.systemConfig.chartsNumber) {
 this.$message({ message: '已超过配置容器最大限制', type: 'warning' })
 return false
 }
 // debugger
 return true
 },
 /**
 * 预览时的tips,当鼠标移入时显示,移出时消失
 */
 showTips(index) {
 if (!this.tipsArr[index] && this.$route.path === '/visual') {
 this.$set(this.tipsArr, index, true)
 }
 if (!this.isPreviewToggle) {
 this.currentHoverContainerIndex = index
 }
 },
 visibleChange(value) {
 this.showMoredataMenu = value
 },
 hideTips(index) {
 if (this.tipsArr[index] && this.$route.path === '/visual') {
 this.$set(this.tipsArr, index, false)
 }
 if (!this.isPreviewToggle && !this.showMoredataMenu) {
 this.currentHoverContainerIndex = -1
 }
 },
 cloneData(obj) {
 let temp = null
 if (obj instanceof Array) {
 temp = obj.concat()
 } else if (obj instanceof Function) {
 // 函数是共享的是无所谓的,js也没有什么办法可以在定义后再修改函数内容
 temp = obj
 } else {
 temp = {}
 for (let item in obj) {
 let val = obj[item]
 temp[item] = typeof val === 'object' ? this.cloneData(val) : val // 这里也没有判断是否为函数,因为对于函数,我们将它和一般值一样处理
 }
 }
 return temp
 },
 cloneQueryInoData(queryPanelId, chartId) {
 if (this.$store.state.charts.chartsOption === undefined) return
 let querynfoData
 this.$store.state.charts.chartsOption.forEach(item => {
 if (item.id.toString().trim() === '2' && item.i.toString().trim() === queryPanelId.toString().trim()) {
 let featureStrObj = JSON.parse(JSON.stringify(item.feature))
 querynfoData = {}
 querynfoData.dataMetricData = []
 // 指标
 let filterMetricData = featureStrObj.dataMetricData.filter(v => !v.unRelativeCharts || (v.unRelativeCharts && !v.unRelativeCharts.includes(chartId))) // this.cloneData(item.feature.dataMetricData)
 // 维度
 querynfoData.dropDownData = featureStrObj.dropDownData.filter(v => !v.unRelativeCharts || (v.unRelativeCharts && !v.unRelativeCharts.includes(chartId))) //   this.cloneData(item.feature.dropDownData)
 // 时间
 querynfoData.periodData = featureStrObj.periodData.filter(v => !v.unRelativeCharts || (v.unRelativeCharts && !v.unRelativeCharts.includes(chartId)))
 // 新增可选未来时间
 if (querynfoData.periodData) {
 querynfoData.futureTimeEnable = featureStrObj.futureTimeEnable || false
 }
  
 // let filterMetricData = featureStrObj.dataMetricData // this.cloneData(item.feature.dataMetricData)
 // querynfoData.dropDownData = featureStrObj.dropDownData //   this.cloneData(item.feature.dropDownData)
 // querynfoData.periodData = featureStrObj.periodData //   this.cloneData(item.feature.periodData)
 querynfoData.dropDownData.forEach(fropitem => {
 fropitem.dimSelected = []
 fropitem.dimSelected = '' // ;//删除属性
 fropitem.Operator = '' // ;//删除属性
 fropitem.children = '' // ;//删除属性
 // fropitem.controlType = '' // ;//删除属性
 fropitem.editName = '' // ;//删除属性
 fropitem.father = '' // ;//删除属性
 fropitem.isActive = '' // ;//删除属性
 fropitem.isCommonTimeFilterDim = '' // ;//删除属性
 fropitem.isTimeDim = '' // ;//删除属性
 fropitem.name = '' // ;//删除属性
 fropitem.type = '' // ;//删除属性
 })
 filterMetricData.forEach(fropitem => {
 if (querynfoData.dataMetricData.filter(v => v.metricCode === fropitem.metricCode && v.selectedOper === fropitem.selectedOper).length === 0) {
 querynfoData.dataMetricData.push(fropitem)
 fropitem.type = '' // ;//删除属性
 fropitem.Operator = '' // ;//删除属性
 fropitem.editName = '' // ;//删除属性
 fropitem.isActive = '' // ;//删除属性
 fropitem.isMetricProperty = '' // ;//删除属性
 fropitem.key = '' // ;//删除属性
 fropitem.metricName = '' // ;//删除属性
 fropitem.metricIndex = '' // ;//删除属性
 fropitem.propertyLabel = '' // ;//删除属性
 fropitem.relyMetric = '' // ;//删除属性
 }
 })
 }
 })
 return querynfoData
 },
 saveDetailParams(data) {
 if (data) {
 const newParams = {
 systemId: Utils.getQueryString('systemId'),
 params: {},
 timer: new Date(new Date().toLocaleDateString()).getTime()
 }
 if (window.localStorage) {
 let oldParams = this.getLocalStorage('paramsToNewPage')
 if (oldParams && oldParams.systemId === newParams.systemId) {
 // newParams.params = oldParams.params
 if (Array.isArray(oldParams.params)) {
 newParams.params = {} // oldParams.params
 } else {
 newParams.params = oldParams.params
 }
 newParams.timer = oldParams.timer
 }
 // 处理自定义参数格式
 let customReference = data.customReference || []
 customReference = customReference.map(item => {
 let dimValueArr = item.dimValue.split(',')
 let condiName = ''
 let condiValue = ''
 dimValueArr.forEach(item2 => {
 condiValue = (condiValue ? condiValue + ',' : condiValue) + item2.split('###')[0]
 condiName = (condiName ? condiName + ',' : condiName) + item2.split('###')[1]
 })
 return {
 condiCode: item.dimCode,
 condiType: 0,
 condiName: condiName,
 condiValue: condiValue
 }
 })
 newParams.params[data.linkIndex] = {
 Value: customReference || [],
 reportId: data.selectedReport,
 versionId: data.selectedReportVersion
 } // linkIndex 存储guid
 if (!data.queryInfo && !customReference) return
 if (data.queryInfo) {
 newParams.params[data.linkIndex].queryInfo = data.queryInfo
 this.setLocalStorage('paramsToNewPage', JSON.stringify(newParams))
 }
 this.setLocalStorage('paramsToNewPage', JSON.stringify(newParams))
 }
 }
 },
 getGuidStr() {
 return getGuid()
 },
 getLocalStorage(key) {
 var exp = 60 * 60 * 24 * 1000 // 一天的秒数
 if (localStorage.getItem(key)) {
 var vals = localStorage.getItem(key) // 获取本地存储的值
 var dataObj = JSON.parse(vals) // 将字符串转换成JSON对象
 // 如果(当前时间 - 存储的元素在创建时候设置的时间) > 过期时间
 var isTimed = (new Date().getTime() - dataObj.timer) > exp
 if (isTimed) {
 // console.log("存储已过期")
 // console.log(dataObj.timer)
 localStorage.removeItem(key)
 return null
 } else {
 var newValue = dataObj
 return newValue
 }
 } else {
 return null
 }
 },
 setLocalStorage(key, value) {
 localStorage.setItem(key, value)
 },
 createDetailRouteUrl(detailFilterParmas1, detailSystemid) {
 let routeData1 = this.$router.resolve({
 path: '/visual',
 query: detailFilterParmas1
 })
 let searchArr = []
 detailSystemid = detailSystemid === '' ? this.$store.state.design.systemId : detailSystemid
 window.location.search.replace('?', '').split('&').map(item => {
 item = item.toLowerCase().indexOf('systemid') >= 0 ? 'systemId=' + detailSystemid : item
 searchArr.push(item)
 })
 let url = window.location.origin + window.location.pathname + '?' +
 searchArr.join('&') + routeData1.href
 return url
 },
 handleCatQueryInfo(commonId) {
 try {
 const nowCurrent = this.chartsOption.find(item => Number(item.i) === Number(commonId)) || {}
 const chartId = nowCurrent.feature.chartId
 const lazyBox = this.$refs['lazyBox'].find(item => Number(item.index) === Number(commonId))
 const containerInner = lazyBox.$children[0]
 // console.log('containerInner', containerInner)
 const component = containerInner.$children[0]
 // console.log('component', component)
 let queryInfo = null
 // 卡片、标签结构与其他不同,特殊处理
 if ([2, 14].includes(chartId)) {
 queryInfo = component.$refs['layout'].queryInfo
 } else {
 queryInfo = component.queryInfo
 }
 // console.log('queryInfo', queryInfo)
  
 const { dimFilter = [], metricFilter = [] } = nowCurrent
 const queryData = {
 queryPanel: queryInfo,
 dataRelation: {
 dimFilter: [...dimFilter],
 metricFilter: [...metricFilter]
 }
 }
 // 设置报表默认不查询,清除过滤器
 if (!reportDefaultSearch(window.HuiYanPermission, this.$store.state.charts.defaultSearch)) {
 queryData.dataRelation.dimFilter = []
 queryData.dataRelation.metricFilter = []
 }
 this.$refs['queryConditionDialog'].openDialog({ index: commonId, queryData })
 } catch (err) {
 console.log('【查看查询条件】error', err)
 }
 },
 dimNumberRangeHander(i) {
 // this.$refs['dimRangeDialog'].openDialog()
 eventBus.$emit(`dimRangeDialog_${i}`)
 }
 }
}
</script>

有没有大佬知道是什么原因导致了我import时,没有同步返回结果, 为啥删除left组件后就可以正常返回了?

阅读 2k
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题