Search
为指定的 Markdown 渲染内容提供全文搜索功能。
基础用法
通过 target 可以指定搜索的目标元素,支持 CSS 选择器、DOM 元素、组件实例 或者返回以上任意一种类型的 函数。并且可以通过 v-model 绑定搜索内容,内容如果存在则会自动滚动到所在位置并高亮标记。
展开源代码
<template>
<div>
<vmd-search v-model="keyword" :target="renderRef" />
<vmd-render ref="renderRef" style="height: 436px; overflow: auto" :src="md" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const keyword = ref('or')
const renderRef = ref(null)
const md = `
# h1 Heading 8-)
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Horizontal Rules
___
---
***
## Emphasis
**This is bold text**
__This is bold text__
*This is italic text*
_This is italic text_
~~Strikethrough~~
## Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
## Lists
Unordered
+ Create a list by starting a line with \`+\`, \`-\`, or \`*\`
+ Sub-lists are made by indenting 2 spaces:
- Marker character change forces new list start:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ Very easy!
Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Integer molestie lorem at massa
1. You can use sequential numbers...
1. ...or keep all the numbers as \`1.\`
Start numbering with offset:
57. foo
1. bar
## Tables
| Option | Description |
| ------ | ----------- |
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
Right aligned columns
| Option | Description |
| ------:| -----------:|
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
`
</script>一键清空
使用 clearable 可以在搜索框中显示清空按钮,点击可以一键清空搜索内容。
展开源代码
<template>
<div>
<p>
<label>
<input v-model="clearable" name="checkbox" type="checkbox" />
启用 clearable
</label>
</p>
<vmd-search v-model="keyword" :clearable="clearable" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const keyword = ref('vue-markdown-design')
const clearable = ref(true)
</script>关闭按钮
使用 close-icon 可以显示关闭按钮,点击后会触发 close 事件。
展开源代码
<template>
<div>
<p>
<label>
<input v-model="closeIcon" name="checkbox" type="checkbox" />
启用 close-icon
</label>
</p>
<vmd-search :close-icon="closeIcon" @close="onClose" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const closeIcon = ref(true)
const onClose = () => {
console.log('点击了关闭按钮')
}
</script>边框样式
使用 border 可以显示搜索框下边框。
展开源代码
<template>
<div>
<p>
<label>
<input v-model="border" name="checkbox" type="checkbox" />
启用 border
</label>
</p>
<vmd-search :border="border" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const border = ref(true)
</script>搜索框尺寸
使用 size 可以设置搜索框尺寸,支持 huge、large、normal、small 四种尺寸。
展开源代码
<template>
<div>
<p>
<label>
请输入搜索栏尺寸:
<select v-model="size" name="select">
<option value="huge">huge (默认)</option>
<option value="large">large</option>
<option value="normal">normal</option>
<option value="small">small</option>
</select>
</label>
</p>
<vmd-search placeholder="请输入搜索内容" :size="size" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const size = ref('huge')
</script>禁用搜索框
使用 disabled 可以禁用搜索框,禁用状态下无法进行搜索等操作。
展开源代码
<template>
<div>
<p>
<label>
<input v-model="disabled" name="checkbox" type="checkbox" />
启用 disabled
</label>
</p>
<vmd-search v-model="keyword" :target="renderRef" :disabled="disabled" />
<vmd-render ref="renderRef" :src="md" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const disabled = ref(true)
const keyword = ref('or')
const renderRef = ref(null)
const md = `
# Lorem ipsum
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi maximus elit fermentum pellentesque vehicula. Suspendisse potenti. Donec iaculis consectetur erat nec placerat. Suspendisse facilisis justo sit amet hendrerit sollicitudin. Suspendisse commodo malesuada massa, ac elementum risus. Ut eu facilisis neque. Fusce tincidunt, ligula vitae eleifend venenatis, purus purus ultrices purus, nec maximus tellus lectus nec leo. Sed auctor magna sed quam dapibus dapibus. Nullam ornare ultricies sem, a iaculis sapien volutpat euismod. Sed ac dictum nulla. Duis euismod tellus vitae diam hendrerit, sit amet vestibulum mauris rhoncus.
`
</script>占位文本
使用 placeholder 可以自定义搜索框占位文本。
展开源代码
<template>
<vmd-search placeholder="🔍 请输入关键词搜索内容" />
</template>滚动距离偏移量
当搜索框切换索引触发内容跳转时,可以通过 offset 设置滚动的偏移量,支持数值和字符串位置(包含 center、start、end、nearest)。当组件嵌套在多层滚动容器中时,滚动效果和偏移量只对离它最近的滚动容器生效。
提示
搜索框的滚动模式采用的是 if-needed 模式。简而言之,只有当下一个索引超出可视区域时才会触发滚动效果。
展开源代码
<template>
<div>
<h4>数值偏移量:</h4>
<div style="margin-bottom: 16px">
<vmd-search v-model="keyword" :offset="56" :target="renderWhenNumber" />
<div style="flex: auto; position: relative">
<div
style="
width: 100%;
background: #0969da;
position: absolute;
top: 0;
color: #fff;
padding: 16px 32px;
box-sizing: border-box;
z-index: 1;
"
>
固定页头
</div>
<div style="height: 436px; overflow: auto">
<vmd-render
ref="renderWhenNumber"
style="margin-top: 56px; height: 436px; overflow: auto"
:src="md"
/>
</div>
</div>
</div>
<h4>字符串位置偏移量:</h4>
<div>
<vmd-search v-model="keyword" offset="end" :target="renderWhenPosition" />
<div style="flex: auto; position: relative">
<div
style="
width: 100%;
background: #0969da;
position: absolute;
top: 0;
color: #fff;
padding: 16px 32px;
box-sizing: border-box;
z-index: 1;
"
>
固定页头
</div>
<div style="height: 436px; overflow: auto">
<vmd-render ref="renderWhenPosition" style="margin-top: 56px" :src="md" />
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const keyword = ref('or')
const renderWhenNumber = ref(null)
const renderWhenPosition = ref(null)
const md = `
# h1 Heading 8-)
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Horizontal Rules
___
---
***
## Emphasis
**This is bold text**
__This is bold text__
*This is italic text*
_This is italic text_
~~Strikethrough~~
## Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
## Lists
Unordered
+ Create a list by starting a line with \`+\`, \`-\`, or \`*\`
+ Sub-lists are made by indenting 2 spaces:
- Marker character change forces new list start:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ Very easy!
Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Integer molestie lorem at massa
1. You can use sequential numbers...
1. ...or keep all the numbers as \`1.\`
Start numbering with offset:
57. foo
1. bar
## Tables
| Option | Description |
| ------ | ----------- |
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
Right aligned columns
| Option | Description |
| ------:| -----------:|
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
`
</script>平滑滚动
使用 smooth 可以在内容跳转时开启平滑滚动。
展开源代码
<template>
<div>
<p>
<label>
<input v-model="smooth" name="checkbox" type="checkbox" />
启用 smooth
</label>
</p>
<div>
<vmd-search v-model="keyword" :target="renderRef" :smooth="smooth" />
<vmd-render ref="renderRef" style="height: 436px; overflow: auto" :src="md" />
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const renderRef = ref(null)
const keyword = ref('or')
const smooth = ref(true)
const md = `
# h1 Heading 8-)
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Horizontal Rules
___
---
***
## Emphasis
**This is bold text**
__This is bold text__
*This is italic text*
_This is italic text_
~~Strikethrough~~
## Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
## Lists
Unordered
+ Create a list by starting a line with \`+\`, \`-\`, or \`*\`
+ Sub-lists are made by indenting 2 spaces:
- Marker character change forces new list start:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ Very easy!
Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Integer molestie lorem at massa
1. You can use sequential numbers...
1. ...or keep all the numbers as \`1.\`
Start numbering with offset:
57. foo
1. bar
## Tables
| Option | Description |
| ------ | ----------- |
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
Right aligned columns
| Option | Description |
| ------:| -----------:|
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
`
</script>输入框原生属性
通过 input-attrs 将属性传递给组件内部的 input 元素。
展开源代码
<template>
<vmd-search v-model="keyword" :input-attrs="{ maxlength: 11 }" />
</template>
<script setup>
import { ref } from 'vue'
const keyword = ref('最多输入 11 个字符')
</script>切换当前索引
通过 toggle 方法可以手动切换当前索引。该方法接收两个参数:第一个参数为指定索引值,可以传入数值和字符串(包含 prev 和 next),它会自动处理越界索引,并通过 index-change 返回安全的索引值;第二个参数可以指定是否忽略搜索框禁用状态,默认为 true,即在搜索框禁用状态下调用 toggle 方法依然可以触发索引值切换。
展开源代码
<template>
<div>
<p>
<label style="margin-right: 10px">
请输入索引值:
<input v-model="index" name="number" type="number" style="width: 4em" />
</label>
<button @click="searchRef.toggle(index)">前往</button>
</p>
<p>当前索引值(从 0 开始计数):{{ safeIndex }}</p>
<vmd-search
v-model="keyword"
ref="searchRef"
:target="renderRef"
@index-change="safeIndex = $event"
/>
<vmd-render ref="renderRef" style="height: 436px; overflow: auto" :src="md" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const renderRef = ref(null)
const searchRef = ref(null)
const keyword = ref('or')
const index = ref(0)
const safeIndex = ref(0)
const md = `
# h1 Heading 8-)
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Horizontal Rules
___
---
***
## Emphasis
**This is bold text**
__This is bold text__
*This is italic text*
_This is italic text_
~~Strikethrough~~
## Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
## Lists
Unordered
+ Create a list by starting a line with \`+\`, \`-\`, or \`*\`
+ Sub-lists are made by indenting 2 spaces:
- Marker character change forces new list start:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ Very easy!
Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Integer molestie lorem at massa
1. You can use sequential numbers...
1. ...or keep all the numbers as \`1.\`
Start numbering with offset:
57. foo
1. bar
## Tables
| Option | Description |
| ------ | ----------- |
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
Right aligned columns
| Option | Description |
| ------:| -----------:|
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
`
</script>手动刷新
通过 refresh 方法可以手动刷新搜索结果。该方法接收一个布尔值,默认为 true,表示在重新获取搜索结果的同时重置索引值。
提示
如果您使用 Render 组件实例作为搜索目标元素,大部分情况下不需要手动刷新,因为 Search 组件会在内容变化时自动刷新搜索结果。
展开源代码
<template>
<div>
<p>
<label style="margin-right: 10px">
请选择渲染内容:
<select v-model="index" name="select">
<option v-for="(item, index) in options" :key="item.title" :value="index">
{{ item.title }}
</option>
</select>
</label>
<button @click="refresh">更新</button>
</p>
<vmd-search v-model="keyword" ref="searchRef" target="#refreshRef" />
<vmd-render id="refreshRef" :src="md" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const options = [
{
title: 'Lorem',
value:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi maximus elit fermentum pellentesque vehicula. Suspendisse potenti. Donec iaculis consectetur erat nec placerat. Suspendisse facilisis justo sit amet hendrerit sollicitudin. Suspendisse commodo malesuada massa, ac elementum risus. Ut eu facilisis neque. Fusce tincidunt, ligula vitae eleifend venenatis, purus purus ultrices purus, nec maximus tellus lectus nec leo. Sed auctor magna sed quam dapibus dapibus. Nullam ornare ultricies sem, a iaculis sapien volutpat euismod. Sed ac dictum nulla. Duis euismod tellus vitae diam hendrerit, sit amet vestibulum mauris rhoncus.'
},
{
title: 'Sed',
value:
'Sed lectus nisl, blandit at volutpat et, lobortis ac urna. Etiam elementum id mauris a ultricies. Suspendisse rhoncus est justo, eu pellentesque turpis elementum quis. Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque vel dolor orci. Vestibulum rhoncus erat vitae molestie porttitor. Phasellus accumsan risus ut enim mollis, quis feugiat massa auctor. Donec vehicula convallis nisi sit amet dapibus. Integer felis erat, interdum eget erat non, facilisis vulputate augue. Ut sed tortor vitae ante venenatis rhoncus eget id tortor. Etiam molestie luctus ligula sit amet venenatis. Aliquam iaculis tristique sem, vitae convallis mi ultricies nec.'
}
]
const keyword = ref('or')
const index = ref(0)
const md = ref(options[0].value)
const searchRef = ref(null)
const refresh = () => {
md.value = options[index.value].value
searchRef.value?.refresh()
}
</script>API
Props
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| v-model | 搜索内容 | string / number | '' |
| target | 搜索目标元素 | string / HTMLElement / VueInstance / ()=> string | HTMLElement | VueInstance | - |
| clearable | 是否显示搜索框清空按钮 | boolean | true |
| close-icon | 是否显示搜索框关闭按钮 | boolean | true |
| border | 是否显示搜索框下边框 | boolean | true |
| size | 搜索框尺寸 | 'huge' | 'large' | 'normal' | 'small' | huge |
| disabled | 是否禁用搜索框 | boolean | false |
| placeholder | 搜索框占位文本 | string | - |
| offset | 搜索框切换索引时的滚动偏移量 | number / 'start'|'end'|'center'|'nearest' | center |
| smooth | 是否开启搜索在内容跳转时的平滑滚动 | boolean | false |
| input-attrs | 传递给搜索框内部 input 元素的原生属性 | object | {} |
事件
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| input | 搜索框内容变化时触发 | event: Event |
| blur | 搜索框失去焦点时触发 | event: FocusEvent |
| focus | 搜索框获得焦点时触发 | event: FocusEvent |
| change | 仅在搜索框失焦或按下回车时触发 | event: Event |
| clear | 点击搜索框清除按钮时触发 | - |
| close | 点击搜索框关闭按钮时触发 | - |
| step-click | 点击搜索框上一项或下一项按钮时触发 | value: 'prev' | 'next' |
| total-change | 搜索匹配总数变化时触发 | value: number |
| index-change | 当前索引值变化时触发 | value: number |
方法
| 方法名 | 说明 | 类型 |
|---|---|---|
| focus | 使搜索框获得焦点 | () => void |
| blur | 使搜索框失去焦点 | () => void |
| clear | 清空搜索内容 | () => void |
| toggle | 切换当前搜索索引值 | (index: number | 'prev' | 'next', ignoreDisabled?: boolean) => void |
| refresh | 手动刷新搜索结果 | (resetIndex?: boolean) => void |