HTML中如何设置按钮元素

最直接设置HTML按钮的方式是使用标签,因其语义化强、内容模型灵活,可嵌套文字、图标等元素,支持type、disabled、onclick等属性,并可通过CSS实现丰富样式和交互反馈,优于按钮;在表单中需注意默认提交行为、重复提交、验证及状态管理等问题,推荐优先使用并结合JavaScript控制行为与状态。

html中如何设置按钮元素

在HTML中设置按钮元素,最直接的方式是使用

标签,它提供了极大的灵活性和语义化优势。当然,你也可以通过


标签的不同

type

属性来创建按钮,比如

type="button"

type="submit"

type="reset"

,这几种方式各有侧重,选择哪种取决于你的具体需求和对交互细节的考量。

解决方案

谈到在HTML里搞定按钮,我们手头其实有几种工具,但最常用也最推荐的,那必须是

标签。它就像一个多面手,能承载各种内容,不仅仅是文字,你甚至可以把图片、图标甚至更复杂的HTML结构塞进去。

最基础的用法,当然是这样:

立即学习“前端免费学习笔记(深入)”;

这就能在页面上呈现一个最简单的按钮了。但按钮之所以强大,在于它的属性。

标签的常用属性:

type

: 这个属性至关重要,它定义了按钮的行为。

submit

(默认值): 当按钮在一个


元素内部时,点击它会提交表单数据。这是最常见的表单提交方式。

button

: 这是一个通用按钮,点击它不会自动提交表单,通常需要配合JavaScript来定义它的行为。

reset

: 点击它会重置表单中的所有输入项到它们的初始值。我的经验是,如果你不确定按钮要干嘛,或者它只是触发一些JS逻辑,就用

type="button"

,这样能避免很多意料之外的表单提交行为。

name

: 当

type="submit"

时,按钮的

name

value

属性可以作为表单数据的一部分被提交。

value

: 同样,当

type="submit"

时,这个值会和

name

一起发送到服务器。

disabled

: 简单粗暴,加了这个属性,按钮就灰掉了,点不了。这在防止重复提交或者某些条件不满足时特别有用。

onclick

: 虽然不推荐直接在HTML里写太多JS,但对于简单的事件,

onclick="alert('Hello!');"

这样的用法也常见。更推荐的做法是把事件监听器写在外部JS文件里。

除了

,我们还有基于


标签的按钮:


: 功能上跟

类似,也是一个通用按钮。


: 功能上跟

类似,用于提交表单。


: 功能上跟

类似,用于重置表单。

这三者最大的区别在于,


标签是自闭合的,按钮的文本内容是通过

value

属性来定义的,它不能像

那样包含复杂的子元素。

样式化按钮 (CSS):无论哪种按钮,要让它好看,都离不开CSS。你可以通过选择器(标签选择器、类选择器、ID选择器)来选中按钮,然后应用各种样式:

button {    background-color: #4CAF50; /* 背景色 */    color: white; /* 文字颜色 */    padding: 10px 20px; /* 内边距 */    border: none; /* 无边框 */    border-radius: 5px; /* 圆角 */    font-size: 16px; /* 字体大小 */    cursor: pointer; /* 鼠标悬停时显示手型 */    transition: background-color 0.3s ease; /* 鼠标悬停动画 */}button:hover {    background-color: #45a049; /* 鼠标悬停时的背景色 */}button:active {    background-color: #3e8e41; /* 鼠标点击时的背景色 */    transform: translateY(1px); /* 轻微下压效果 */}button:disabled {    background-color: #cccccc;    cursor: not-allowed;}

通过CSS,你可以让按钮变得五彩斑斓,甚至加上各种动画效果,让用户体验更上一层楼。


到底有啥区别?什么时候用哪个更合适?

这几乎是每个前端新手都会问的问题,也是一个很值得深思的细节。表面上看,它们都能在页面上呈现一个可点击的按钮,但骨子里,它们的设计哲学和能力边界大相径庭。

核心差异点:

内容模型 (Content Model):

: 这是一个“容器”标签。这意味着你可以在

标签的开始和结束标签之间放置任何流式内容(phrasing content),比如文本、

@@##@@

、甚至

来做图标。这种灵活性让你可以轻松创建带有图标、多行文本或者其他复杂布局的按钮。


: 这是一个“空”标签,或者叫自闭合标签。它的文本内容完全由

value

属性来定义。你不能在


标签内部放置任何其他HTML元素。


所以,如果你想要一个带图标的按钮,用


就非常麻烦,你得用CSS伪元素或者背景图来模拟,远不如

直接。

语义和可访问性 (Semantics & Accessibility):

从语义上讲,

标签更明确地表示一个“按钮”控件。现代浏览器和辅助技术(如屏幕阅读器)对

的解析和支持通常更完善,能更好地传达其交互性质。虽然


也能被识别为按钮,但在复杂交互场景下,

在可访问性方面往往表现更优。

默认行为 (Default Behavior):

如果你在一个


标签内部使用

,并且没有明确指定

type

属性,它的默认

type

就是

submit

。这意味着它会尝试提交表单。这常常是新手踩坑的地方,比如你只想用JS弹个框,结果页面却刷新了。


则没有这种默认提交行为,它始终是一个通用按钮,除非你用JavaScript显式地让它提交表单。

什么时候用哪个更合适?

几乎所有情况下,我个人都倾向于使用

标签。

需要丰富内容和灵活样式时: 比如按钮里要有图标、Loading动画、或者多行文字,

是唯一合理的选择。更好的语义和可访问性: 这对构建健壮、用户友好的Web应用至关重要。与现代前端框架的结合: React、Vue等框架也更倾向于使用

来构建组件化的按钮。避免浏览器兼容性陷阱: 尽管现在差异不大,但历史版本中

在不同浏览器下的渲染一致性往往优于


只有在极少数、非常简单、或者历史遗留项目中,你可能会考虑


简单的纯文本按钮: 如果你的按钮永远只是简单的几个字,没有图标,也不需要复杂的样式定制,那么


也能胜任。快速原型开发: 有时候为了快速搭建一个页面,随便写个


可能比写

少敲几个键,仅此而已。特殊场景或历史兼容: 某些非常特定的老旧系统或框架可能对


有特殊的处理。

总而言之,把

当作你的首选,因为它更现代、更灵活、更语义化。而


则可以看作是特定历史背景下的替代品,或者在极简场景下的一个选择。

如何让你的按钮不仅仅是“能用”,而是“好用”又“好看”?

一个按钮仅仅能点击是不够的,它还需要在视觉上吸引人,在交互上直观,在体验上让人愉悦。这涉及到美学、心理学和可用性工程。

视觉设计:建立品牌识别与层级感

色彩搭配: 按钮的颜色应该与你的品牌色调一致,并且能够清晰地传达其功能。例如,提交或确认按钮通常用主色调(绿色、蓝色),取消或删除按钮则可能用警告色(红色、灰色)。确保文字颜色与背景色有足够的对比度,方便阅读。形状与大小: 圆角、方角,或者胶囊形?这取决于你的整体设计风格。按钮的大小要适中,既不能太小导致难以点击,也不能太大显得笨重。移动端尤其要考虑“手指友好”的点击区域。阴影与渐变: 适当的阴影可以增加按钮的立体感,让它看起来像一个可按下的物理对象。微弱的渐变也能提升质感,避免单调。但切记不要过度,否则会显得俗气。字体选择: 按钮上的文字是用户理解功能的第一步。选择易读的字体,并确保字号和字重合适。

交互反馈:让用户感受到“我点到了”

悬停状态 (

:hover

): 当鼠标(或触控笔)悬停在按钮上时,按钮应该有视觉变化,比如背景色变深/变浅、边框加粗、轻微的缩放或阴影变化。这给用户一个明确的信号:“这个元素是可交互的”。激活状态 (

:active

): 当用户实际点击(按下鼠标左键)按钮时,按钮应该有一个“被按下”的视觉反馈,比如轻微的下沉效果(

transform: translateY(1px);

),或者背景色进一步加深。这模拟了物理按钮的按压感。焦点状态 (

:focus

): 对于键盘用户和辅助技术用户,按钮获得焦点时(通过Tab键切换),必须有清晰的视觉指示,通常是围绕按钮的轮廓线。这对于可访问性至关重要。默认的浏览器轮廓可能不够美观,你可以自定义它,但绝不能移除它而不提供替代方案。加载状态: 当按钮触发一个异步操作(如提交表单、发送请求)时,立即禁用按钮并显示一个加载指示器(Spinner图标或“加载中…”文本),可以有效防止重复点击,并告知用户系统正在处理。

可访问性:确保每个人都能使用

语义化HTML: 使用

标签本身就是可访问性的第一步。清晰的文本内容: 按钮的文本应该简洁明了地描述其功能(例如“提交订单”、“删除用户”),避免模糊的词语如“确定”、“点击这里”。

aria-label

如果按钮的视觉内容不足以完全表达其功能(比如只有一个图标的按钮),可以使用

aria-label

属性为屏幕阅读器提供更详细的描述。

键盘导航: 确保按钮可以通过Tab键聚焦,并通过Enter或Space键激活。这是浏览器默认行为,但要确保你的CSS不会意外破坏它。高对比度: 按钮文本和背景之间要有足够的颜色对比度,以满足WCAG(Web内容无障碍指南)标准,方便视力障碍用户阅读。

响应式设计:适应不同设备

按钮的大小和内边距在移动设备上可能需要调整。使用

rem

em

单位,或者通过媒体查询(

@media

)来调整按钮的样式,确保在小屏幕上依然易于点击。考虑触控设备的特点,按钮的点击区域应该足够大,避免误触。

一个“好用”又“好看”的按钮,是用户体验的基石。它不仅仅是一个功能入口,更是品牌形象和用户关怀的体现。

按钮提交表单时,我该注意哪些“坑”?

按钮在表单提交场景下,确实有一些让人头疼的“坑”,如果不提前了解,可能会导致各种意想不到的问题。我在这里列举几个常见的,希望能帮你避开雷区。

默认行为引发的意外刷新:

坑点:


标签内部,如果你使用

且没有明确指定

type="button"

,或者使用


,它们默认的行为就是提交表单并刷新页面。很多时候,我们希望通过JavaScript来异步提交表单(AJAX),但忘记阻止这个默认行为,导致页面闪烁或数据重复提交。解决方案:对于

,如果它不用于提交表单,总是明确设置

type="button"

。如果确实要异步提交表单,在JavaScript的事件监听器中,务必调用

event.preventDefault()

来阻止浏览器的默认提交行为。

document.getElementById('myButton').addEventListener('click', function(event) {event.preventDefault(); // 阻止表单默认提交// 这里执行你的AJAX提交逻辑console.log('表单已异步提交');});

重复提交问题:

坑点: 用户在网络延迟高或者手速过快的情况下,可能会在第一次点击后,表单数据还没发送成功,就又点击了一次提交按钮,导致同一份数据被提交多次,造成数据冗余或业务逻辑错误。

解决方案:

提交后禁用按钮: 这是最直接有效的方法。在点击提交按钮后,立即将按钮设置为

disabled

状态,并在请求成功或失败后,再根据情况启用或保持禁用。

const submitButton = document.getElementById('submitBtn');submitButton.addEventListener('click', async function(event) {event.preventDefault();submitButton.disabled = true; // 禁用按钮submitButton.textContent = '提交中...'; // 改变按钮文本,提供反馈try {    // 模拟异步提交    await new Promise(resolve => setTimeout(resolve, 2000));    console.log('表单提交成功!');    // 成功后可以跳转页面或显示成功信息} catch (error) {    console.error('提交失败:', error);    submitButton.disabled = false; // 失败后重新启用按钮    submitButton.textContent = '重新提交';}});

使用一个标志位: 在JavaScript中设置一个布尔变量(如

isSubmitting

),在提交过程中设为

true

,结束后设为

false

。在提交前检查这个变量。

表单验证:

坑点: 仅仅依靠后端验证是不够的,如果用户输入了非法数据,每次都提交到服务器再返回错误,会造成糟糕的用户体验和不必要的服务器负载。解决方案:HTML5内置验证: 利用

required

minlength

maxlength

pattern

type="email"

等HTML5属性进行客户端初步验证。JavaScript自定义验证: 对于更复杂的验证逻辑,需要用JavaScript在表单提交前进行验证。如果验证失败,阻止表单提交,并给出清晰的错误提示。后端验证不可少: 客户端验证只是为了提升用户体验,服务器端的验证是必不可少的安全防线,防止恶意用户绕过前端验证。

name

value

属性:

坑点: 有时候你可能会发现,提交表单后,后端收到的数据里包含了你点击的那个提交按钮的

name

value

。这在某些场景下是有用的(比如一个表单有多个提交按钮,需要区分是哪个按钮触发的提交),但如果不需要,它可能会污染你的表单数据。解决方案:如果不需要区分是哪个提交按钮,可以直接不给提交按钮设置

name

value

属性。或者在后端处理时,直接忽略这些字段。

跨浏览器兼容性:

坑点: 虽然现在情况好很多了,但在过去,不同浏览器对


的默认样式、对齐方式以及

type

属性的解析可能存在细微差异。解决方案:使用CSS Reset或Normalize.css来统一不同浏览器元素的默认样式。在开发过程中,多在不同浏览器(Chrome, Firefox, Safari, Edge)中测试表单提交功能。

这些“坑”大部分都与用户体验和数据完整性相关,通过前端的合理设计和JavaScript的介入,可以大大提升表单的健壮性和用户满意度。

按钮的状态管理:禁用、加载中、成功和失败,怎么处理才专业?

专业的按钮状态管理,不仅仅是视觉上的变化,更是对用户操作的引导和反馈。它能让用户清晰地知道当前发生了什么,以及下一步可以做什么,大大提升用户体验。

禁用状态 (

disabled

)

目的: 防止用户在不满足条件时进行操作,或在操作进行中重复点击。实现方式:HTML: 直接在标签上添加

disabled

属性。

JavaScript: 通过DOM操作添加或移除

disabled

属性。

const btn = document.getElementById('myButton');btn.disabled = true;  // 禁用btn.disabled = false; // 启用

视觉反馈: 通常,禁用状态的按钮会呈现灰色或半透明,并且鼠标指针会变成“禁止”图标(

cursor: not-allowed;

)。确保这种状态的视觉对比度足够,但又不至于喧宾夺主。何时使用:表单未填写完整或验证失败时。用户没有权限执行某项操作时。异步操作(如数据提交)正在进行中时,防止重复提交。

加载中状态 (Loading)

目的: 告知用户操作正在进行,避免用户疑惑或重复点击。

实现方式:

禁用按钮: 这是基础,防止重复提交。

改变按钮文本: 将按钮文本改为“加载中…”、“提交中…”等。

添加加载指示器 (Spinner): 在按钮内部或旁边显示一个旋转的图标。

/* CSS for spinner */.spinner {    display: inline-block;    width: 16px;    height: 16px;    border: 2px solid #f3f3f3;    border-top: 2px solid #3498db;    border-radius: 50%;    animation: spin 1s linear infinite;    margin-left: 5px;}.hidden { display: none; }@keyframes spin {    0% { transform: rotate(0deg); }    100% { transform: rotate(360deg); }}
// JavaScript 示例const loadBtn = document.getElementById('loadBtn');const btnText = loadBtn.querySelector('.btn-text');const spinner = loadBtn.querySelector('.spinner');loadBtn.addEventListener('click', async () => {    loadBtn.disabled = true;    btnText.textContent = '加载中...';    spinner.classList

HTML中如何设置按钮元素图标删除

以上就是HTML中如何设置按钮元素的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1574214.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
什么是HTML的行内元素和块级元素
上一篇 2025年12月22日 16:07:29
HTML中如何实现工具栏
下一篇 2025年12月22日 16:07:40

相关推荐

  • 修复Django电商项目中AJAX过滤产品列表图片不显示问题

    在Django电商项目中,当使用AJAX动态加载过滤后的产品列表时,常遇到图片无法正常显示的问题。这通常是由于前端模板中图片加载方式(如data-setbg属性结合JavaScript库)与AJAX动态内容更新机制不兼容所致。解决方案是直接在AJAX返回的HTML中使用标准的标签来渲染图片,确保浏览…

    2026年5月10日
    000
  • 开源免费PHP工具 PHP开发效率提升利器

    推荐开源免费PHP开发工具以提升效率:VS Code、Sublime Text轻量高效,PhpStorm专业强大;调试用Xdebug、Kint、Ray;依赖管理选Composer;代码质量工具包括PHPStan、Psalm、PHP_CodeSniffer;数据库管理可用%ignore_a_1%MyA…

    2026年5月10日
    000
  • Matplotlib 地图中多类型图例的创建与优化

    Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化

    本教程旨在解决matplotlib地图可视化中,如何在一个图例中同时展示颜色块(如区域分类)和自定义标记(如特定兴趣点)的问题。文章详细介绍了当传统`patch`对象无法正确显示标记时,如何利用`matplotlib.lines.line2d`创建标记图例句柄,并将其与颜色块图例句柄合并,从而生成一…

    2026年5月10日 用户投稿
    100
  • Golang JSON序列化:控制敏感字段暴露的最佳实践

    本教程探讨golang中如何高效控制结构体字段在json序列化时的可见性。当需要将包含敏感信息的结构体数组转换为json响应时,通过利用`encoding/json`包提供的结构体标签,特别是`json:”-“`,可以轻松实现对特定字段的忽略,从而避免敏感数据泄露,确保api…

    2026年5月10日
    000
  • 怎么在PHP代码中实现图片上传功能_PHP图片上传功能实现与安全处理教程

    首先创建含enctype的HTML表单,再用PHP接收文件,检查目录、移动临时文件,验证类型与大小,生成唯一文件名,并调整php.ini限制以确保上传成功。 如果您尝试在PHP项目中添加图片上传功能,但服务器无法正确接收或保存文件,则可能是由于表单配置、文件处理逻辑或安全限制的问题。以下是实现该功能…

    2026年5月10日
    100
  • 比特币新手教程 比特币交易平台有哪些

    比特币是一种去中心化的数字货币,基于区块链技术实现点对点交易,具有匿名性、有限发行和不可篡改等特点;新手可通过交易所购买,P2P交易获得比特币,常用平台包括Binance、OKX和Huobi;交易流程包括注册账户、实名认证、绑定支付方式、充值法币并下单购买,可选择市价单或限价单;比特币存储方式有交易…

    2026年5月10日
    000
  • HTML如何隐藏滚动条或去除滚动条

    滚动条可以存在也可以不存在,本文主要介绍了html 隐藏滚动条和去除滚动条的方法的相关资料,大家一起来学习一下html隐藏滚动条或去除滚动条的方法吧。 1. html 标签加属性 XML/HTML Code复制内容到剪贴板 2.body中加入以下代码 立即学习“前端免费学习笔记(深入)”; html…

    用户投稿 2026年5月10日
    000
  • Golang gRPC流式请求异常处理

    在Golang的gRPC流式通信中,必须通过context.Context处理异常。应监听上下文取消或超时,及时释放资源,设置合理超时,避免连接长时间挂起,并在goroutine中通过context控制生命周期。 在使用 Golang 和 gRPC 实现流式通信时,异常处理是确保服务健壮性的关键部分…

    2026年5月10日
    000
  • Go语言mgo查询构建:深入理解bson.M与日期范围查询的正确实践

    本文旨在解决go语言mgo库中构建复杂查询时,特别是涉及嵌套`bson.m`和日期范围筛选的常见错误。我们将深入剖析`bson.m`的类型特性,解释为何直接索引`interface{}`会导致“invalid operation”错误,并提供一种推荐的、结构清晰的代码重构方案,以确保查询条件能够正确…

    2026年5月10日
    100
  • css max-height属性怎么用

    max-height 属性设置元素的最大高度。 说明 该属性值会对元素的高度设置一个最高限制。因此,元素可以比指定值矮,但不能比其高。不允许指定负值。 注意:max-height 属性不包括外边距、边框和内边距。 立即学习“前端免费学习笔记(深入)”; 值描述none 默认。定义对元素被允许的最大高…

    2026年5月10日
    100
  • vscode上怎么运行html_vscode上运行html步骤【指南】

    首先保存文件为.html格式,再通过浏览器或Live Server插件打开预览;推荐安装Live Server实现本地服务器运行与实时刷新,提升开发体验。 在 VS Code 上运行 HTML 文件并不需要复杂的配置,只需几个简单步骤即可预览页面效果。VS Code 本身是一个代码编辑器,不直接运行…

    2026年5月10日
    100
  • 修复点击时按钮抖动:CSS垂直对齐实践

    本文探讨了在Web开发中,交互式按钮(如播放/暂停按钮)在点击时发生意外垂直位移的问题。通过分析CSS样式变化对元素布局的影响,我们发现这是由于按钮不同状态下的边框样式和内边距改变,以及默认的垂直对齐行为共同作用所致。核心解决方案是利用CSS的vertical-align属性,将其设置为middle…

    2026年5月10日
    100
  • Golang goroutine与channel调试技巧

    使用go run -race检测数据竞争,结合runtime.NumGoroutine监控协程数量,通过pprof分析阻塞调用栈,利用select超时避免永久阻塞,有效排查goroutine泄漏、死锁和数据竞争问题。 Go语言的goroutine和channel是并发编程的核心,但它们也带来了调试上…

    2026年5月10日
    000
  • 页面中文本域的值怎么设置

    标签定义多行的文本输入控件。 文本区中可容纳无限数量的文本,其中的文本的默认字体是等宽字体(通常是 Courier)。 可以通过 cols 和 rows 属性来规定 textarea 的尺寸,不过更好的办法是使用 CSS 的 height 和 width 属性。 注释:在文本输入区内的文本行间,用 …

    2026年5月10日
    000
  • 使用 Jupyter Notebook 进行探索性数据分析

    Jupyter Notebook通过单元格实现代码与Markdown结合,支持数据导入(pandas)、清洗(fillna)、探索(matplotlib/seaborn可视化)、统计分析(describe/corr)和特征工程,便于记录与分享分析过程。 Jupyter Notebook 是进行探索性…

    2026年5月10日
    000
  • 如何在HTML中插入表单元素_HTML表单控件与输入类型使用指南

    HTML表单通过标签构建,包含action和method属性定义数据提交目标与方式,常用input类型如text、password、email等适配不同输入需求,配合label、required、placeholder提升可用性,结合textarea、select、button等控件实现完整交互,是…

    2026年5月10日
    100
  • 前端缓存策略与JavaScript存储管理

    根据数据特性选择合适的存储方式并制定清晰的读写与清理逻辑,能显著提升前端性能;合理运用Cookie、localStorage、sessionStorage、IndexedDB及Cache API,结合缓存策略与定期清理机制,可在保证用户体验的同时避免安全与性能隐患。 前端缓存和JavaScript存…

    2026年5月10日
    200
  • HTML5网页如何实现手势操作 HTML5网页移动端交互的处理技巧

    首先利用原生touch事件实现滑动判断,再通过preventDefault解决滚动冲突,接着引入Hammer.js处理复杂手势,最后通过优化点击区域、避免事件冲突和增加视觉反馈提升体验。 在移动端浏览器中,HTML5网页可以通过触摸事件实现手势操作,提升用户体验。虽然原生JavaScript提供了基…

    2026年5月10日
    000
  • 深入理解 Express.js 中 next() 参数的作用与中间件机制

    本文深入探讨 express.js 中间件函数中的 `next()` 参数。它负责将控制权传递给请求-响应周期中的下一个中间件或路由处理程序。文章将详细解释 `next()` 的工作原理、中间件的注册与执行顺序,以及不正确使用 `next()` 可能导致请求挂起的风险,并通过代码示例和实际应用场景,…

    2026年5月10日
    000
  • 创建指定大小并填充特定数据的Golang文件教程

    本文将介绍如何使用Golang创建一个指定大小的文件,并用特定数据填充它。我们将使用 `os` 包提供的函数来创建和截断文件,从而实现快速生成大文件的目的。示例代码展示了如何创建一个10MB的文件,并将其填充为全零数据。掌握这些方法,可以方便地在例如日志系统或磁盘队列等场景中,预先创建测试文件或初始…

    2026年5月10日
    000

发表回复

登录后才能评论
关注微信