vue中的一些高级特性(含vue3新特性)

vue2.0自定义v-model组件

注意下面是vue2的自定义v-model组件使得子组件和父组件的其他dom实现双向绑定,但是vue2.0的实现方式有诸多缺点
比如:

  • 只能双向绑定一个值,不能双向绑定多个值
  • 实现方式比较繁琐,并且难以理解

子组件CustomVModel.vue

<template>
  <!-- 例如:vue 颜色选择 -->
  <input type="text"
      :value="content"
      @input="$emit('changeEvent', $event.target.value)"
  >
  <!--
      1. 上面的 input 使用了 :value 而不是 v-model
      2. 上面的 changeEvent 和 changeEvent 要对应起来
    
  -->
</template>

<script>
export default {
  model: {
      prop: 'content', // 这个content和下面的props里面的content是自己取的但是两者要对应一样
      event: 'changeEvent'
  },
  props: {
      content: String,
      default() { //默认值
          return ''
      }
  }
}
</script>

父组件index.vue

<template>
  <div>
      <!-- <p>vue 高级特性</p>
      <hr> -->

      <!-- 自定义 v-model -->
      <p>{{name}}</p>
      <!--  -->
      <CustomVModel v-model="name"/>

  </div>
</template>

<script>
import CustomVModel from './CustomVModel'

export default {
  components: {
      CustomVModel

  },
  data() {
      return {
          name: '123',
   
      }
  }
}
</script>

vue3.0实现自定义v-model

在这里插入图片描述
根据上图的比较,我们得知vue3.0实现自定义v-model必须具备以下条件

  • 必须具备modelValue属性
  • 需要在更新的时候必须触发一个onUpdate:modelValue的事件

必须具备modelValue属性
在子组件中ValidateInput:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
vue3.0的context 是 setup() 的第二个形参,它是一个上下文对象,可以通过 context 来访问Vue的实例 this
在这里插入图片描述
在父组件中:
在这里插入图片描述

在这里插入图片描述

$nextTick

  • Vue是异步渲染的框架
  • data改变之后,DOM不会立刻渲染
  • $nextTick会在DOM渲染之后被触发,以获取最新的DOM节点
<template>
<div id="app">
  <ul ref="ul1"> 
      <li v-for="(item, index) in list" :key="index">
          {{item}}
      </li>
  </ul>
  <button @click="addItem">添加一项</button>
</div>
</template>

<script>
export default {
name: 'app',
data() {
    return {
      list: ['a', 'b', 'c']
    }
},
methods: {
  addItem() {
      this.list.push(`${Date.now()}`)
      this.list.push(`${Date.now()}`)
      this.list.push(`${Date.now()}`)

      const ulElem = this.$refs.ul1  //获取上面的DOM ul元素
     
     console.log('没有用$nextTick '+ulElem.childNodes.length )

      // 1. 异步渲染,$nextTick 待 DOM 渲染完再回调
      // 3. 页面渲染时会将 data 的修改做整合,多次 data 修改只会渲染一次
      this.$nextTick(() => {
        // 获取 DOM 元素
        const ulElem = this.$refs.ul1  //获取上面的DOM ul元素
     
        console.log(' 用了$nextTick '+ ulElem.childNodes.length )
      })
  }
}
}
</script>

点第一次

在这里插入图片描述

  • 异步渲染,$nextTick 待 DOM 渲染完再回调
  • 页面渲染时会将 data 的修改做整合,多次 data 修改只会渲染一次

vue的动态组件

一句话来概括就是将组件以变量的形式进行渲染

语法如下

<template>
<div>
	<component :is="HelloWorldName"/>
</div>
</template>


import HelloWorld from './HelloWorld'


export default {
    components: {
   HelloWorld
    },
    data() {
        return {
   
            HelloWorldName: "HelloWorld",
      
        }
    }
}
</script>

vue异步加载组件

异步加载组件的简单理解就是什么时候需要用到什么时候就加载

异步组件不需要用import引入了 在下面是这种方式: FormDemo: () => import(’…/…/BaseUse/FormDemo’) 在components里面引入的

点击这个按钮就会出现FormDemo组件(此组件就不贴代码了)

<template>
    <div>
      
        <FormDemo v-if="showFormDemo"/>
        <button @click="showFormDemo = true">show form demo</button>

       
    </div>
</template>

<script>


export default {
    components: {
   
        FormDemo: () => import('../../BaseUse/FormDemo'),// 异步加载组件
  
    },
    data() {
        return {
      
            showFormDemo: false
        }
    }
}
</script>

keep-alive

先从字面意思 上理解,坚持活着,这里的主语是组件,其实本质上就是缓存组件的意思,缓存频繁切换的组件,使其不重复渲染。可以优化vue项目的性能

下面的实例营造了这样一个场景:有三个按钮A,B,C,分别点击不同的按钮,下面会出现不同的 组件,其实本质上就是一个简单的tabBar

将要渲染的三个组件 KeepAliveStageA,
KeepAliveStageB, KeepAliveStageC 用 keep-alive 组件包裹,他们就不会被销毁 了,除非页面被关闭

KeepAlive.vue

<template>
    <div>
        <button @click="changeState('A')">A</button>
        <button @click="changeState('B')">B</button>
        <button @click="changeState('C')">C</button>

        <keep-alive> <!-- tab 切换 -->
            <KeepAliveStageA v-if="state === 'A'"/> 
            <KeepAliveStageB v-if="state === 'B'"/>
            <KeepAliveStageC v-if="state === 'C'"/>
        </keep-alive>
    </div>
</template>

<script>
import KeepAliveStageA from './KeepAliveStateA'
import KeepAliveStageB from './KeepAliveStateB'
import KeepAliveStageC from './KeepAliveStateC'

export default {
    components: {
        KeepAliveStageA,
        KeepAliveStageB,
        KeepAliveStageC
    },
    data() {
        return {
            state: 'A'
        }
    },
    methods: {
        changeState(state) {
            this.state = state
        }
    }
}
</script>

KeepAliveStateA.vue

<template>
    <p>state A</p>
</template>

<script>
export default {
    mounted() {
        // eslint-disable-next-line
        console.log('A mounted')
    },
    destroyed() {
        // eslint-disable-next-line
        console.log('A destroyed')
    }
}
</script>

KeepAliveStageB.vue

<template>
    <p>state B</p>
</template>

<script>
export default {
    mounted() {
        // eslint-disable-next-line
        console.log('B mounted')
    },
    destroyed() {
        // eslint-disable-next-line
        console.log('B destroyed')
    }
}
</script>

KeepAliveStageC.vue

<template>
    <p>state C</p>
</template>

<script>
export default {
    mounted() {
        // eslint-disable-next-line
        console.log('C mounted')
    },
    destroyed() {
        // eslint-disable-next-line
        console.log('C destroyed')
    }
}
</script>

mixin

多个组件之间有相同的逻辑,抽离出来。

这里其实思想和react的自定义hook一模一样
vue3中也有自定义hook的功能了

mixin语法有如下缺点:

  1. 变量来源不明确,不利于阅读
  2. 多个mixin可能会造成命名冲突
  3. mixin和组件可能出现多对多的关系,复杂度较高

朋友们不需要担心,现在vue3出来了,里面也有自定义hook了,完全可以代替mixin

下面一个场景就是,如果多个组件都需要使用到showName方法,就可以showName方法写到一个单独的js文件中,但是此js文件用的是vue的script相同的模板

mixin.js

export default {
    data() {
        return {
            city: '北京'
        }
    },
    methods: {
        showName() {
            // eslint-disable-next-line
            console.log(this.name)
        }
    },
    mounted() {
        // eslint-disable-next-line
        console.log('mixin mounted', this.name)
    }
}

将mixin.js引入到要渲染的组件,这个组件用到minxin的showName方法和city属性

<template>
    <div>
        <p>{{name}} {{major}} {{city}}</p>
        <button @click="showName">显示姓名</button>
    </div>
</template>

<script>
import myMixin from './mixin'

export default {
    mixins: [myMixin], // 可以添加多个,会自动合并起来
    data() {
        return {
            name: 'lisi',
            major: 'English'
        }
    },
    methods: {
    },
    mounted() {
        // eslint-disable-next-line
        console.log('component mounted', this.name)
    }
}
</script>

vue3中的自定义hook函数

下面的自定义hook函数传入参数是一个dom节点,监听document中的点击事件,看点击的区域是否在这个节点内部

import { ref, onMounted, onUnmounted,Ref } from "vue";

const useClickOutside = (elementRef: Ref<null | HTMLElement>) => {
    const isClickOutside = ref(false)
    const handler = (e: MouseEvent) => {
        if (elementRef.value) {
            if (!elementRef.value.contains(e.target as HTMLElement)) {
                isClickOutside.value = false
            }else{
                isClickOutside.value = true
            }
        }
    }
    onMounted(() => {
        // console.log(123132132);
        
        document.addEventListener('click', handler)
        // console.log(isClickOutside.value);
        
    })
    onUnmounted(() => {
        document.removeEventListener('click', handler)
    })
    return isClickOutside
}

export default useClickOutside
    const isClickOutside = useClickOutside(dropRef);

    watch(isClickOutside, () => {
      // console.log(isClickOutside.value);

      if (isOpen.value && !isClickOutside.value) {
        console.log("watch");

        isOpen.value = false;
      }
    });

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值