v-if和v-show

v-if和v-show:vue框架中提供了v-if 和 v-show两个指令,用于控制页面DOM结构的显隐性。

一、比较:

1、相同点:均可以实现局部DOM的显示和隐藏。

2、不同点:显示和隐藏的原理不同。v-show隐藏元素的本质是给元素本省添加了display = none这个css属性,其实DOM结构仍存在于页面,可以通过F12查看DOM结构。v-if隐藏元素的本质是不加载DOM结构,不能通过F12查看DOM结构之后再v-if绑定的布尔变量为true时,才添加对应的DOM结构。

3、总结:综上,v-if常用于:

(1)控制DOM加载的顺序:

如果控制显示的DOM用到了某个异步获取的参数,为防止参数还未响应而DOM已加载导致页面无渲染的情况,可以将该DOM添加v-if控制显示并将该参数作为v-if的条件。如控制父子组件的加载顺序:父组件引用了子组件,子组件的生命周期和父组件是一样的,随父组件初始化而初始化,最后随着父组件的销毁而销毁,如果希望改变子组件初始化的顺序,使子组件延迟加载,可以在父组件中加v-if来控制子组件的懒加载。

(2)强制更新子组件:子组件的生命周期和父组件是一样的,如果希望单独更新子组件,常使用v-if来控制子组件的显示。如果涉及页面不更新渲染数据问题,还可以和nextTick函数配合的方法来强制重新渲染:

<Son v-if="sonRefresh"></Son>
 
data(){
  return {
    sonRefresh: true
  }
}
 
// 下面这段内容写在父组件需要更新子组件的地方
this.sonRefresh= false;
this.$nextTick(() => {
    this.sonRefresh= true;
});

二、用法举例:

1、v-if以下报错:NotFoundError: Failed to execute 'insertBefore' on 'Node': The node before  改为v-show后问题解决。

2、如父组件四个tab,点击每个tab都有调用同一个子组件,每个tab调用接口获取id把id传给子组件,子组件根据这个id再掉用后端接口初始化页面。如果父组件调用接口还未响应而子组件先初始化了,就会出现页面为空的情况,这时可以用v-if解决,当父组件的id获取到时才加载子组件。这里在子组件的钩子函数中加了一个alert,也可以看出,如果使用v-show,父页面加载时会立即弹出4个alert,内容为空,改成v-if,会在点击tab的时候弹出,并且id有值:

父:

 <el-tabs v-model="activeName" type="card" @tab-click="handleClick">
        <el-tab-pane label="这是tab1" name="tab1">
		  tab1的描述
          <MyChild v-if="tab1Id"
            :id="tab1Id"
          ></MyChild>
        </el-tab-pane>
        <el-tab-pane label="这是tab2" name="tab2" >
          <MyChild v-show="tab2Id"
            :id="tab2Id"           
          ></MyChild>
        </el-tab-pane>
        <el-tab-pane label="这是tab3" name="tab3">
		   <!--省略图片-->
          <MyChild v-if="tab3Id"
            :id="tab3Id"
          ></MyChild>
        </el-tab-pane>
        <el-tab-pane label="这是tab4" name="tab4">
		  按钮
          <MyChild v-if="tab4Id"
            :id="tab4Id"
          ></MyChild>
        </el-tab-pane>
</el-tabs>


  data() {
    return {
      activeName: 'tab1',
      //tab1
      tab1Id: '',
      schoolOverviewScene: 1,
      //tab2
      tab2Id: '',
      productOverviewScene: 2,
      //tab3
      tab3Id: '',
      areaOverviewScene: 3,
      //tab4
      tab4Id: '',
      keySchoolScene: 4
    };
  },
 
  created() {
    this.getTab1Id();
  },

  methods: {
    handleClick() {
      if (this.activeName === 'tab1') {
        this.getTab1Id();
      } else if (this.activeName === 'tab2') {
        this.getTab2Id();
      } else if (this.activeName === 'tab3') {
        this.getTab3Id();
      } else if (this.activeName === 'tab4') {
        this.getTab4Id();
      }
    },
    getTab1Id() {
      this.$api['user/getMyDatas']({
        roleId: this.roleId,
        scene: this.schoolOverviewScene
      }).then(data => {
        if (data && data.length > 0) {
          this.tab1Id = data[0].reportId;
        }
      });
    },
    getTab2Id() {
      this.$api['user/getMyDatas']({
        roleId: this.roleId,
        scene: this.productOverviewScene
      }).then(data => {
        if (data && data.length > 0) {
          this.tab2Id = data[0].reportId;
        }
      });
    },

    getTab3Id() {
      this.$api['user/getMyDatas']({
        roleId: this.roleId,
        scene: this.areaOverviewScene
      }).then(data => {
        if (data && data.length > 0) {
          this.tab3Id = data[0].reportId;
        }
      });
    },
    getTab4Id() {
      this.$api['user/getMyDatas']({
        roleId: this.roleId,
        scene: this.keySchoolScene
      }).then(data => {
        if (data && data.length > 0) {
          this.tab4Id = data[0].reportId;
        }
      });
    },
  }

子:

<!-- @format -->

<template>
  <div id="frame">
    <iframe 
      :id="myData.iframeId"
      v-bind:src="myData.content"
      :style="{width: width, height:height}"
    ></iframe>
  </div>
</template>


  props: {
    id: {
      required: true,
      type: Number
    }
  },
  data() {
    return {
      myData:'',
      height: window.innerHeight + 'px',
      width: '100%'
    };
  },
  created() {
    alert(this.id);
  },
  mounted() {
    this.init();
  },

  methods: {

    init() {
      if (this.id!== '') {
        this.$api['user/getDetailById']({
         id:this.id
        }).then(data => {
  
		  this.myData.id = this.id+'-'+url;
          }
        });
      }
    }
  }


3、再如:三个文字按钮(使用了面包屑的样式)切换页面,第二和第三个页面需要传递一个参数(异步获取的)给子组件,子组件根据这个参数再次请求后台来初始化页面,为防止该参数还未获取到而子组件已经加载导致初始化的页面为空,这里使用了v-if,同时第三个页面有一个查询按钮,点击按钮需要更新页面显示数据:

父:index.vue

<!-- @format -->

<template>
<div class="body">
   <div class="header">
      <el-breadcrumb separator="/">
        <el-breadcrumb-item @click.native="swithFirst()">首页</el-breadcrumb-item>
        <el-breadcrumb-item @click.native="swithSecond()">活动管理</el-breadcrumb-item>
        <el-breadcrumb-item @click.native="swithThird()">活动列表</el-breadcrumb-item>
     </el-breadcrumb>
    </div>

    <div class="container">
        <!--1-->
        <div>
            <FirstChild v-show="isFirstShow"></FirstChild>
        </div>

        <!--2-->
        <div  v-show="isSecondShow">
             <MyChild 
            v-if="secondId"
            :id="secondId"
           
          ></MyChild>
        </div>
        
        <!--3-->
        <div  v-show="isThirdShow">
            <div class="query-div">
                <el-button @click="search()" type="primary">搜索</el-button>
            </div>
             <MyChild 
            v-if="thirdId"
            :id="thirdId"
     
          ></MyChild>
        </div>
    </div>
  </div>
 
</template>

<script>
import FirstChild from './children/first-child';
import MyChild from '@/components/my-child';
export default {
  name: 'Default',
  data() {
    return {
      isFirstShow: true,
      isSecondShow: false,
      isThirdShow: false,
      roleId: -1,
      //第二个页面
      secondId: '',
      secondScene: 7,
      //
      thirdId: '',
      thirdScene: 8
    };
  },
  methods: {
    swithFirst() {
      this.isFirstShow = true;
      this.isSecondShow = false;
      this.isThirdShow = false;
    },
    swithSecond() {
      if (!this.secondId) {
        this.getSecondId();
      }
      this.isFirstShow = false;
      this.isSecondShow = true;
      this.isThirdShow = false;
    },
    swithThird() {
      if (!this.thirdId) {
        this.getThirdId();
      }
      this.isFirstShow = false;
      this.isSecondShow = false;
      this.isThirdShow = true;
    },
    //获取第二个页面id
    getSecondId() {
      this.$api['user/getMyDatas']({
        roleId: this.roleId,
        scene: this.secondScene
      }).then(data => {
        if (data && data.length > 0) {
          this.secondId = data[0].reportId;
        }
      });
    },
    //获取重点项目达芬奇看板id
    getThirdId() {
      this.$api['user/getMyDatas']({
        roleId: this.roleId,
        scene: this.thirdScene
      }).then(data => {
        if (data && data.length > 0) {
          this.thirdId = data[0].reportId;
        }
      });
    },
    //重新加载
    search() {
      let tem = this.thirdId;
      this.thirdId = '';
      this.$nextTick(() => {
        this.thirdId = tem;
      });
    }
  },
  components: { ProjectOverview, MyChild }
};
</script>

<style lang="less" scoped>
.body {
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%;
  .container {
  }
}
</style>

子1:first-child.vue:

<!-- @format -->

<template>
    <div>总览</div>
</template>
<script>
export default {
  created() {}
};
</script>

子2:my-child.vue:

<!-- @format -->
 
<template>
  <div id="frame">
    <iframe 
      :id="myData.iframeId"
      v-bind:src="myData.content"
      :style="{width: width, height:height}"
    ></iframe>
  </div>
</template>
 
 
  props: {
    id: {
      required: true,
      type: Number
    }
  },
  data() {
    return {
      myData:'',
      height: window.innerHeight + 'px',
      width: '100%'
    };
  },
  created() {
    alert(this.id);
  },
  mounted() {
    this.init();
  },
 
  methods: {
 
    init() {
      if (this.id!== '') {
        this.$api['user/getDetailById']({
         id:this.id
        }).then(data => {
  
		  this.myData.id = this.id+'-'+url;
          }
        });
      }
    }
  }
 
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w_t_y_y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值