搜索
您的当前位置:首页正文

详解Vue用自定义指令完成一个下拉菜单(select组件)

2023-12-08 来源:车融汽车网

这次分享的是关于Vue自定义指令的使用方法,学习完基础后我们再来实战完成一个下拉列表,废话不多说,直接上干货

基本用法

//全局注册Vue.directive('my-directive', { // 指令选项})// 局部注册var app = new Vue({ el: '#app' directives: { 'my-directive': { // 指令选项 }})

相信对Vue比较熟悉的人看完都知道,directive的写法与组件 基本类似,只是方法名由component改为了directive。上例只是注册了自定义指令v-my-directive,还没实现具体功能,下面具体介绍 自定义指令的各个选项。

指令定义函数提供了几个钩子函数 (可选):

  1. bind:只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
  2. inserted:被绑定元素插入父节点时调用 (父节点存在即可调用,不必存在于 document 中)。
  3. update:所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode 更新之前。指令的值可能发生了改变也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
  4. componentUpdated:所在组件的 VNode 及其孩子的 VNode 全部更新时调用。
  5. unbind:只调用一次,指令与元素解绑时调用。

可根据需求在不同的钩子函数 内完成逻辑代码,如下面v-focus,我们希望在元素插入父节点时就调用,那用到的最好的就是inserted了。示例代码如下

// html部分<div id="app" v-focus>// js部分Vue.directive('focus', { // 当绑定元素插入到 DOM 中。 inserted: function (el) { // 聚焦元素 el.focus() }})

效果如下图所示

自定义指令 v-focus.png

可以看到,打开这个页面,input输入框就自动获取焦点了,成为可输入状态。

每个钩子函数 都可以有几个参数可用,比如我们上面用到了el。它们 的含义如下:

  1. el:指令所绑定的元素,可以用来直接操作 DOM 。
  2. binding:一个对象,包含以下属性:
    1. name:指令名,不包括 v-前缀。
    2. value:指令的绑定值,例如:v-my-directive="1 + 1", value 的值是 2。
    3. oldValue:指令绑定的前一个值,仅在 update和 componentUpdated钩子中可用。无论值是否改变都可用。
    4. expression:绑定值的字符串形式。例如 v-my-directive="1 + 1" ,expression 的值是 "1 + 1"。
    5. arg:传给指令的参数。例如 v-my-directive:foo,arg 的值是 "foo"。
    6. modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar, 修饰符对象 modifiers 的值是 { foo: true, bar: true }。
  3. vnode:Vue 编译生成的虚拟节点,查阅 VNode API 了解更多详情。
  4. oldVnode:上一个虚拟节点,仅在 update和 componentUpdated钩子中可用。

下面是结合了以上参数 的一些具体示例,代码如下

// HTML部分<div id="app" v-demo:msg.a.b="message"> <div v-text:msg.a.b="message"></div></div>// JS部分Vue.directive('demo', { bind: function (el, binding, vnode) { var s = JSON.stringify el.innerHTML = 'name: ' + binding.name + '<br>' + 'value: ' + binding.value + '<br>' + 'expression: ' + binding.expression + '<br>' + 'argument: ' + binding.arg + '<br>' + 'modifiers: ' + JSON.stringify(binding.modifiers).modifiers + '<br>' + 'vnode keys: ' + Object.keys(vnode).join(',') }})new Vue({ el: '#app', data: { message: 'some text' }})

执行后,<div>的内容会使用innerHTML重置,结果为

name: "test"value: "some text"expression: "message"argument: "msg"modifiers: {"a":true,"b":true}vnode keys: tag, data, children, text, elm, ns, context, functionalContext, functionalOptions, functionalScopeId, key, componentOptions, componentInstance, parent, raw, isStatic, isRootInsert, isComment, isCloned, isOnce, asyncFactory, asyncMeta, isAsyncPlaceholder

在多数使用场景,我们会在bind钩子里绑定一些事件,比如在document上用addEventListerer绑定,在unbind里有removeEventListener 解绑,比较典型的示例就是让这个元素随着鼠标拖拽。

如果需要更多个值,自定义指令也可以传入一个JavaScript对象字面量, 只要是合法类型的JavaScript表达式都是可以的。示例代码如下:

// HTML部分<div id="app" v-demo:msg.a.b="message"> <div v-test="{msg: 'hello', name: 'Aresn'}"></div></div>//JS部分Vue.directive('test', { bind: function (el, binding, vnode) { console.log(binding.value.msg) console.log(binding.value.name) }})var app = new Vue({ el: '#app'})

Vue 2.x很移除大量Vue 1.x自定义指令的配置。在使用自定义指令时,应该充分解业务需求,因为很多时候你需要的可能并不是自定义指令,而是组件。

基础的东西讲完了,我们来根据directive提供的API来写一个点击外部区域可以让其下拉列表消失的菜单

// HTML部分<div id="app" v-clock> <div class="main" v-clickoutside="handleClose"> <button @click="show = !show">点击显示下拉菜单</button> <div class="dropdown" v-show="show"> <p>下拉框内容,点击外面区域可以关闭</p> </div></div>// JS部分var app = new Vue({ el: '#app', data: { show: false },methods: { handleClose() { this.show = false; }}})Vue.directive('clickoutside', { bind: function(el, binding, vode) { function documentHandler (e) { if (el.contains(e.target)) { return false } if (binding.expression) { binding.value(e) } } el.__vueClickOutSide__ = documentHandler document.addEventListener('click', documentHandler) }, unbind: function(el, binding) { document.removeEventListener('click', el.__vueClickOutSide__) delete el.__vueClickOutSide__ }})

要在document上绑定click事件,所以在bind钩子内声明了一个函数documentHandler,并将它作为句柄定在document的click事件上。documentHandler函数做了两个判断,第一个是判断点击的区域是否是指令所在的元素内部,如果是,就跑出函数,不信下继续执行

contains方法是用来判断元素A是否包含了元素 B,包含返回true,不包含返回false

// HTML<div id="parent"> 父元素 <div id="children">子元素</div></div>// JSvar a = doucment.getElemengById('parent')var b = doucment.getElemengById('children')console.log(A.contains(B)) // trueconsole.log(B.contains(A)) // false

第二个判断是当前 的指令v-clickoutside有没有写表达式,在该自定义指令中,表达 式应该是第一个函数 ,在过滤了内部元素后,点击外面任何区域应该招待用户表达 式中的函数 ,所以binding.value就用来执行上下文methods中指定的函数的

小编还为您整理了以下内容,可能对您也有帮助:

vue3 实现 select 下拉选项

本人学生 , 平时在外面没事接点小项目小赚一笔补贴生活费. 之前一直都是使用 Vue2.x 的版本做项目, 暑假刚刚学习了 Vue3 想着新项目就直接用 Vue3 上手.

好了, 话不多说先给大佬们看看效果样式:

因为下拉框可能会在某些情况下被挡住, 所以这里的下拉框被挂载到了 body 标签上, 并且下拉框中的选项往往是以 <slot> 插槽的形式编写, 这里就会困扰到很多小白, 搞不明白怎么样才能在 下拉框 与 触发下拉按钮 之间关联响应式事件与数据.

tk-select 为 select 下选项父标签, 必须含有插槽 #selectDropDown 才能正常使用

tk-select-item 为**select

**下选项子标签(选项标签), tk-select-item 内可以继续写入其他 HTML 内容, 每项的具体值由props value 决定

可以使用 v-modal 实时获取到 下拉选项 选取到的值

首先看看目录结构

两个 .vue 文件用来的干嘛的没什么好说的, selectBus.js 解决 Vue3 中无法安装 eventBus 的问题, token.js 用于给每组 selec t 与 select-item 相互绑定.

我们先看看 vue3 官网怎么说的 进入官网 . 说人话的意思就是不可以像 vue2 那样愉快的安装 Bus , 需要 自己实现事件接口 或者使用 第三方插件 . 这里官网也给出了具体实现方案.

vue3 新增 <teleport> 标签, 可以将标签内的元素挂载到任意位置, 查看官方文档

select 主要有触发下拉按钮 tk-select-button 和下拉列表 tk-select-dropdown 组成, 下拉框中的选项未来将由插槽插入.

首先解决下拉列表打开&关闭和定位的问题

在 select.vue 中接收事件

到这里下拉选项框基本就完成了. 我们像页面添加第一个下拉选项时非常完美,但是如果页面上有两个 select 存在时问题来了. 我们发现当控制其中一个选项被选中是, 另外一个 select 显示的值也随之改变. 我们需要将一组 select & select-item 进行绑定,让 Bus 在接受时知道事件来自于哪个里面的 select-item .

在 vue2 中我们通常获取实例的 parent 然后一层一层寻找父类 select , 但是在 vue3 setup 中并不能获取到正确的 parent , 所以我想到了可以在 select 创建时派发一个 token 在讲此令牌传给所有子类, 好了理论存在, 开始实践.

在vue中使用 provide 可以向子类、孙类等等后代传输数据, 后代使用 inject 接收数据. 查看官网

这里可以模仿Java中的UUID

在 select 创建时生成 token 并派发给后代

这样我们在子类接收后每次使用 bus 发送数据时带上 token

在 select.vue 监听Bus后先验证token

github.com/18651440358/vue3-select

第一次写帖子几分激动几分不知所措, 请各位大佬指点错误或可以优化的地方, 欢迎大家讨论.

在element-ui的select下拉框加上滚动加载

在项目中,我们需要运用到很多来自后端返回的数据。有时是上百条,有时甚至上千条。如果加上后端的多表查询或者数据量过大,这就导致在前端的显示就会及其慢,特别是在网络不好的时候更是如此。

自然,后端就做了一项非常“漂亮”的交互体验数据——分页

这不分页还好,一分页对超过10条数据之后的本来也不多,就20条,偏偏还得做个分页器。(假设为10条)

此时,如果能够像购物商城那样拖拽到底部自动加载新数据就好了。

于是《在element-ui的select下拉框加上滚动加载》诞生了。

这里通过自定义封装vue指令进行封装。(什么是指令:官方指令叫v-on,v-model)

以下以element-ui中的select为例:

在main.js同级别文件中添加directives.js:

// directives.js

import Vue from 'vue'

let MyPlugin = {}

export default MyPlugin.install = function(vue, options) {

}

v-loadmore: 用于在element-ui的select下拉框加上滚动到底事件监听

scrollHeight 获取元素内容高度(只读)

scrollTop 获取或者设置元素的偏移值,常用于, 计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.

clientHeight 读取元素的可见高度(只读)

如果元素滚动到底, 下面等式返回true, 没有则返回false

scrollHeight - scrollTop === clientHeight

这里运用到了滚动偏移来做监听来处理,这与聊天对话框中默认下拉到底部的原理是大同小异的,后续我会有专门的文章进行讲解。

然后在组件中使用

<el-select

v-model="chatmode"

placeholder="聊天模式"

size="mini"

v-loadmore="loadMore">

<el-option

v-for="item in chatmodes"

:key="item.value"

:label="item.qa_name"

:value="item.qa_code"

:disabled="item.disabled">

</el-option>

</el-select>

<script>

export default {

methods: {

loadMore () {

// 这里写入要触发的方法

}

}

}

</script>

element-ui使用select组件和tree组件实现下拉树形选择器

一个嵌套就可以搞定

网上的办法大多都是直接在option上写,给option加一个高度,然后overflow: auto,这样会有问题, 因为select本身使用的是element-ui自己的滚动条组件, max-height为274px,一旦option设置高度过大,会出现双重滚动条,而且原生滚动条真的有点丑,其实这里只需要给option加一个height: auto,就可以使用select自带的滚动条,不需要单独再加其他滚动。

发现两个问题

要解决几点

scrollToOption?拿来吧你

很明显,要传入一个option对象,而option的$el属性是一个dom,则表现形式就是一个Vue的实例,我这边直接用querySelector获取一个dom, 传入{ $el: dom }也能用。再然后就是找这个dom,发现当树某一节点被点击时,其class会多一个is-current,那么就可以这样写:

ps: 只针对单选做的,多选还需按照情况改。

vue---tree实现递归组件(多级下拉菜单)

  <div class="detail-list">

    <div class="item" v-for="(item, index)in list" :key="index">

      <div class="item-title border-bottom" @click.stop="changeStatus(index)" :class="{'active':isActive[index]}">

        <span class="oks">{{ item.title }}

      <!-- 注意递归终止条件 -->

      <div v-if="item.children" class="item-children">

        <!-- 通过name进行递归调用 -->

        <detail-list v-on="$listeners"

          v-if="scopesDefault[index]"

          :list="item.children"

        >

export default {

name:"DetailList",

  props: {

list:Array,

  },

  data() {

return {

isActive:[],

      scopesDefault: [], // 第一级

      scopes: [], // 第二级

    };

  },

  created() {

this.scope();

  },

  mounted(){

},

  methods: {

changeStatus(index) {

var ods=[]

for(var b=0;b

ods.push(false)

}

this.scopesDefault=ods;

      this.isActive=ods;

      if (this.scopesDefault[index] ==true) {

this.$set(this.scopesDefault, index, false);

      }else {

this.$set(this.scopesDefault, index, this.scopes[index]);

        if(this.list[index].children==undefined){

this.$emit("Eok",true)

//数据内容

          // var value = [{

          //  title: "文华酒店自助晚餐",

// }]

//

// this.list[index]['children']=value

          this.$set(this.isActive, index, true);

        }else{

this.$set(this.isActive, index, this.scopes[index]);

        }

}

// this.list.push({

      //  title: "特惠1票",

// })

    },

    scope() {

this.list.forEach((item, index) => {

this.scopes[index]=false

        this.isActive[index]=false

        this.scopesDefault[index] =false; // 第一级索引值全都是false

        if ("children" in item) {// 判断第一级是否有children

          this.scopes[index] =true;

        }else {

this.scopes[index] =false;

        }

});

    },

  },

};

<style scoped>

.item-title {

line-height:40px;

  padding:0 10px;

  display:flex;

  color:#666;

}

.item-title span {

cursor:pointer;

  display:block;

  margin:0 auto;

}

.item-title.active span{

border-bottom:2px solid #03a9f4;

  color:#03a9f4;

}

.item-children {

padding:0 20px;

  position:absolute;

  width:100%;

  left:0;

}

.item-title.active{

}

.detail-list{

width:100%;

  display:flex;

  border-bottom:1px solid #ddd;

  position:relative;

}

.detail-list>div{

flex:1;

}

.item{

flex:1;

}

</style>

车融汽车网还为您提供以下相关内容希望对您有帮助:

vue3 实现 select 下拉选项

到这里下拉选项框基本就完成了. 我们像页面添加第一个下拉选项时非常完美,但是如果页面上有两个 select 存在时问题来了. 我们发现当控制其中一个选项被选中是, 另外一个 select 显示的值也随之改变. 我们需要将一组 sele...

在element-ui的select下拉框加上滚动加载

这里通过自定义封装vue指令进行封装。(什么是指令:官方指令叫v-on,v-model)以下以element-ui中的select为例:在main.js同级别文件中添加directives.js:// directives.js import Vue from 'vue'let MyPlugin = {} expo...

多选下拉框回显无内容

前端使用vue,项目中使用的是element ui组件,在使用select下拉框多选时,新增记录时select多选下拉框正常使用,没问题。但是在编辑记录时,编辑界面也为select下拉框赋值了,却没有显示数据。先放一个select多选下拉框编辑时正确...

element-ui使用select组件和tree组件实现下拉树形选择器

网上的办法大多都是直接在option上写,给option加一个高度,然后overflow: auto,这样会有问题, 因为select本身使用的是element-ui自己的滚动条组件, max-height为274px,一旦option设置高度过大,会出现双重滚动条,而且原生...

vue下拉框如何控制onblur和onchange

&lt;option value=”单位”&gt;单位&lt;/option&gt; &lt;/select&gt; 这样在选择第二个时,值就会变即可触发onChange;二、我们用Select的onchange事件时,常会遇到这样一个问题,那就是连续选相同一项时,不触发onchange事件.select的onchange事件...

iview的select下拉框选项错位怎么处理

在使用iview的过程中,我遇到这样一个问题,在Model中使用select下拉框组件。但是当弹出框超过一屏需要滚动时,select的下拉选项会出现错位(下图1为正常,图2为滚动后,下拉选项错位。)图1:图2:在分析组件代码后,发现...

vue---tree实现递归组件(多级下拉菜单)

this.scopesDefault[index] =false; // 第一级索引值全都是false         if ("children" in item) {// 判断第一级是否有children    ...

自定义指令去除el-select的下拉框

联动效果的select下拉框清空的问题用vue3.x+element-ui来写后台管理,自己二次封装了一个搜索栏组件,想搜索栏组件传递配置项数组实现组件的显示,需求:品类下拉框选择翡翠时才显示货品形态下拉框,如果不是翡翠,则隐藏货品...

vue中list如何放到下拉菜单

把后台传来的list,赋值给cityList。把后台传来的list,赋值给cityList,就可以放到下拉菜单中。如果字段名字不一致需要循环转一下或者让后台改字段名字。vue是一款友好的、多用途且高性能的JavaScript框架,使用vue可以创建可...

如何解决vue与传统jquery插件冲突

比如基于jquery的select2插件,在vue下单独用有很多问题,其实对于这类插件,可以用vue的自定义指令和组件来包装,解决冲突的问题。引用官方vue1.0和2.0的两个例子,学习一下。例子1.0 例子2.0 大功告成。说说基于vue...

本文如未解决您的问题请添加抖音号:51dongshi(抖音搜索懂视),直接咨询即可。

热门图文

Top