Django信号与扩展:深入理解与实践
title: Django信号与扩展:深入理解与实践
date: 2024/5/15 22:40:52
updated: 2024/5/15 22:40:52
categories:
- 后端开发
tags:
- Django
- 信号
- 松耦合
- 观察者
- 扩展
- 安全
- 性能
第一部分:Django信号基础
Django信号概述
一. Django信号的定义与作用
Django信号(Signal)是Django框架中的一种机制,用于在特定事件发生时进行通信。信号可以让不同的Django组件松耦合地通信,即使它们不直接相互依赖。这种松耦合的设计使得Django应用更加灵活、可扩展和可维护。
Django信号分为内置信号和自定义信号。内置信号是由Django框架提供的,在Django内部使用,如模型保存、删除、数据库操作等。自定义信号是开发者根据需要创建的信号,用于在自定义事件发生时进行通信。
信号的主要作用包括:
- 解耦组件:信号允许不同的组件在不直接依赖的情况下进行通信,使得组件之间的耦合度降低,提高了代码的可重用性和可维护性。
- 事件监听:信号可以被监听器(Signal Receiver)监听,监听器可以在特定事件发生时执行相应的动作。
- 扩展框架:信号可以用于扩展Django框架,开发者可以在特定事件发生时执行自定义逻辑,实现对Django框架的定制和扩展。
二. Django信号与观察者模式的对比
Django信号和观察者模式(Observer Pattern)都是解决松耦合通信问题的设计模式。它们的主要区别在于实现方式和应用场景。
-
实现方式:
- Django信号采用广播机制,信号发送者不需要知道谁在监听信号。信号发送者只需要发送信号,而信号接收者只需要注册自己感兴趣的信号。
- 观察者模式采用一对多的关系,观察者(Observer)直接订阅主题(Subject)。当主题状态发生变化时,主题会通知所有订阅者。
-
应用场景:
- Django信号适用于Django框架内部的松耦合通信,例如在模型保存、删除、数据库操作等事件发生时进行通信。
- 观察者模式适用于更广泛的场景,例如GUI应用、网络编程、事件驱动编程等领域。
信号的注册与接收
一. 信号的注册与接收
在Django中,信号的注册与接收主要通过以下两个步骤完成:
- 创建信号接收器(Signal Receiver):信号接收器是一个函数,用于在特定信号发生时执行相应的动作。信号接收器需要接收一个sender参数,用于标识信号的发送者。
- 注册信号接收器:将信号接收器与特定信号关联起来,以便在信号发生时调用信号接收器。
二. 内置信号的介绍
Django框架提供了一些内置信号,用于在特定事件发生时进行通信。以下是一些常用的内置信号:
- django.db.models.signals.pre_save:在模型保存前发送。
- django.db.models.signals.post_save:在模型保存后发送。
- django.db.models.signals.pre_delete:在模型删除前发送。
- django.db.models.signals.post_delete:在模型删除后发送。
- django.db.models.signals.m2m_changed:在模型多对多关系发生变化时发送。
三. 自定义信号的创建
要创建自定义信号,需要使用Django的Signal类。以下是创建自定义信号的示例:
from django.dispatch import Signal# 创建自定义信号
custom_signal = Signal(providing_args=["arg1", "arg2"])
在上面的示例中,我们创建了一个名为custom_signal
的自定义信号,并指定了两个参数arg1
和arg2
。
四. 信号接收器的编写与注册
- 编写信号接收器:信号接收器是一个函数,用于在特定信号发生时执行相应的动作。信号接收器需要接收一个sender参数,用于标识信号的发送者。
def custom_signal_receiver(sender, arg1, arg2, **kwargs):# 执行相应的动作pass
- 注册信号接收器:将信号接收器与特定信号关联起来,以便在信号发生时调用信号接收器。
custom_signal.connect(custom_signal_receiver, sender=SomeModel)
在上面的示例中,我们将custom_signal_receiver
函数注册为custom_signal
信号的接收器,并指定SomeModel
为信号的发送者。当custom_signal
信号发生时,custom_signal_receiver
函数将被调用。
信号的发送与处理
一. 信号的注册与接收
信号的注册和接收是通过django.dispatch.dispatcher.Signal
类实现的。下面是注册和接收信号的基本步骤:
- 导入信号:首先需要导入需要使用的信号,例如内置信号
django.db.models.signals.post_save
。 - 创建接收器:接收器是一个函数,当信号触发时,该函数会被调用。接收器函数接收一个参数,即信号对象,其他参数根据信号定义而定。
- 注册接收器:使用
connect
方法将接收器函数注册到信号上。connect
方法接收两个参数:第一个参数是信号对象,第二个参数是接收器函数。
以下是一个简单的信号注册和接收示例:
from django.db.models.signals import post_save
from django.dispatch import receiver
from myapp.models import MyModel@receiver(post_save, sender=MyModel)
def my_receiver(sender, instance, **kwargs):print("MyModel saved!")# Register the receiver
post_save.connect(my_receiver, sender=MyModel)
二. 内置信号的介绍
Django提供了许多内置信号,可以在特定事件发生时触发。下面是一些常用的内置信号:
django.db.models.signals.pre_save
:在模型实例被保存前触发。django.db.models.signals.post_save
:在模型实例被保存后触发。django.db.models.signals.pre_delete
:在模型实例被删除前触发。django.db.models.signals.post_delete
:在模型实例被删除后触发。django.db.models.signals.m2m_changed
:在多对多关系发生变化时触发。
三. 自定义信号的创建
自定义信号可以使用django.dispatch.dispatcher.Signal
类创建。下面是创建自定义信号的步骤:
- 导入
Signal
类。 - 创建自定义信号:创建一个信号对象,并指定信号名称和描述。
- 注册自定义信号:使用
connect
方法将接收器函数注册到自定义信号上。
以下是一个创建自定义信号示例:
from django.dispatch import Signalmy_signal = Signal(providing_args=["arg1", "arg2"])def my_receiver(sender, arg1, arg2, **kwargs):print("MySignal received, arg1=%s, arg2=%s" % (arg1, arg2))# Register the receiver
my_signal.connect(my_receiver)# Trigger the signal
my_signal.send(sender=None, arg1="value1", arg2="value2")
四. 信号接收器的编写与注册
信号接收器是一个函数,当信号触发时,该函数会被调用。信号接收器函数接收一个参数,即信号对象,其他参数根据信号定义而定。
信号接收器可以使用@receiver
装饰器注册,如下所示:
from django.db.models.signals import post_save
from django.dispatch import receiver
from myapp.models import MyModel@receiver(post_save, sender=MyModel)
def my_receiver(sender, instance, **kwargs):print("MyModel saved!")# Register the receiver
post_save.connect(my_receiver, sender=MyModel)
也可以使用connect
方法手动注册,如下所示:
from django.db.models.signals import post_save
from myapp.models import MyModeldef my_receiver(sender, instance, **kwargs):print("MyModel saved!")# Register the receiver
post_save.connect(my_receiver, sender=MyModel)
需要注意的是,在使用@receiver
装饰器注册接收器时,信号会自动解除对该接收器的引用,因此在使用@receiver
装饰器注册接收器时,不需要手动解除接收器的注册。
第二部分:Django信号的高级应用
信号的优化与调试
- 信号的性能考量
信号处理可能会对应用程序的性能产生影响,特别是在处理大量数据或高并发场景时。为了优化信号性能,可以采取以下措施:
- 限制信号接收器的数量:只注册必要的信号接收器,避免不必要的处理。
- 使用异步信号处理:如前所述,可以使用
django_q
等工具实现异步信号处理,以提高应用程序的性能。 - 避免在信号接收器中执行耗时操作:信号接收器应尽量简洁,避免执行耗时的数据库查询、网络请求等操作。
- 信号的调试技巧
AD:漫画首页
在调试信号时,可以采取以下技巧:
- 使用断点:在信号接收器中设置断点,以便在信号触发时暂停执行,检查变量值和调用堆栈。
- 打印日志:在信号接收器中添加日志记录,以便在运行时查看信号处理过程。
- 使用Django Debug Toolbar:Django Debug Toolbar是一个强大的调试工具,可以显示有关请求、响应和信号处理的各种信息。
- 信号的错误处理与日志记录
在处理信号时,可能会遇到错误。为了更好地处理错误和记录日志,可以采取以下措施:
- 异常处理:在信号接收器中使用
try...except
语句捕获异常,并进行相应的处理。
def custom_signal_receiver(sender, **kwargs):try:# 执行相应的动作passexcept Exception as e:# 处理异常print(f"Error in custom_signal_receiver: {str(e)}")
- 日志记录:使用Python内置的
logging
模块或Django的django.utils.log
模块记录日志。
import loggingdef custom_signal_receiver(sender, **kwargs):logger = logging.getLogger(__name__)try:# 执行相应的动作passexcept Exception as e:# 记录错误日志logger.error(f"Error in custom_signal_receiver: {str(e)}")
通过以上措施,可以更好地优化、调试和处理信号,确保应用程序的稳定性和性能。
信号在Django应用中的实践
- 用户认证与权限管理中的信号应用
在用户认证和权限管理方面,Django信号可以用于在用户创建、更新或删除时执行特定的操作。以下是一些示例:
- 用户创建时发送欢迎邮件:
from django.core.mail import send_mail
from django.contrib.auth.signals import user_logged_in
from django.dispatch import receiver@receiver(user_logged_in, sender=User)
def send_welcome_email(sender, user, request, **kwargs):subject = '欢迎加入我们的网站!'message = '感谢您注册我们的网站,祝您使用愉快!'from_email = settings.DEFAULT_FROM_EMAILrecipient_list = [user.email]send_mail(subject, message, from_email, recipient_list)
- 用户权限变更时更新缓存:
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.contrib.auth.models import User@receiver(post_save, sender=User)
def update_permissions_cache(sender, instance, created, **kwargs):if not created:# 更新用户权限缓存pass@receiver(post_delete, sender=User)
def clear_permissions_cache(sender, instance, **kwargs):# 清除用户权限缓存pass
- 模型生命周期中的信号应用
在模型生命周期中,Django信号可以用于在模型实例创建、更新或删除时执行特定的操作。以下是一些示例:
- 创建模型实例时自动生成唯一标识符:
from django.db.models.signals import pre_save
from django.dispatch import receiver
from .models import MyModel@receiver(pre_save, sender=MyModel)
def generate_unique_identifier(sender, instance, **kwargs):if not instance.unique_identifier:instance.unique_identifier = generate_unique_id()
- 删除模型实例时级联删除相关联的数据:
from django.db.models.signals import post_delete
from django.dispatch import receiver
from .models import MyModel@receiver(post_delete, sender=MyModel)
def cascade_delete(sender, instance, **kwargs):# 删除与instance相关联的数据pass
- 信号在第三方应用中的集成
AD:专业搜索引擎
在集成第三方应用时,Django信号可以用于在第三方应用执行特定操作时触发自定义逻辑。以下是一些示例:
- 在第三方博客应用中,当文章发布时通知其他用户:
from django.db.models.signals import post_save
from django.dispatch import receiver
from third_party_app.models import BlogPost@receiver(post_save, sender=BlogPost)
def notify_users(sender, instance, created, **kwargs):if created:# 通知其他用户有新文章发布pass
- 在第三方电子商务应用中,当订单支付成功时更新库存:
from django.db.models.signals import post_save
from django.dispatch import receiver
from third_party_app.models import Order@receiver(post_save, sender=Order)
def update_inventory(sender, instance, created, **kwargs):if instance.payment_status == 'paid':# 更新库存pass
通过在Django应用中实践信号,可以实现更灵活、可扩展的逻辑,提高代码的可维护性和可读性。
信号的安全性与最佳实践:
-
安全隐患与防范:
- 信号滥用:避免在信号处理函数中执行过于复杂的操作,这可能导致性能问题,甚至安全漏洞,比如在信号处理中执行SQL注入攻击。
- 权限控制:确保信号处理函数只由有权限的用户或特定角色执行,防止未经授权的访问。
- 数据同步:在处理敏感数据时,确保数据在信号处理过程中得到恰当的加密和保护,防止数据泄露。
- 避免循环依赖:避免在信号中引发其他信号,这可能导致无限循环,影响系统稳定。
-
最佳实践与编码规范:
- 明确信号目的:为每个信号定义清晰的目的,确保信号处理函数只执行与信号相关的任务。
- 分段处理:将信号处理函数分解为小的、可测试的部分,便于维护和调试。
- 使用@receiver装饰器:在需要的地方使用装饰器来注册信号处理函数,这样更容易管理和控制信号的使用。
- 使用weakref:对于长时间运行的任务,使用
weakref
可以防止内存泄漏,因为信号接收器会在信号不再被使用时自动卸载。 - 信号订阅选择性:只订阅真正需要的信号,避免不必要的性能消耗。
- 异常处理:在信号处理函数中妥善处理可能出现的异常,防止异常传播到其他部分。
- 文档注释:为信号、接收器和处理函数提供清晰的文档,以便其他开发人员理解其作用和使用方式。
遵循这些最佳实践,可以确保信号在Django应用中的安全和高效使用。
附录
Django 信号 API 参考:
Django 信号提供了一种在框架内部或第三方应用之间进行低级别通信的机制。以下是一些主要的 API 函数和类:
AD:首页 | 一个覆盖广泛主题工具的高效在线平台
signal.signal(signal, receiver)
:注册一个信号接收器函数。signal.send(signal, *args, **kwargs)
:发送信号。signal.get_receivers(signal)
:获取所有已经注册的接收器。signal.disconnect(receiver, sender, dispatch_uid)
:解除接收器和信号的连接。signal.connect(receiver, sender, weak=True, dispatch_uid=None)
:连接一个接收器到信号上。
Django 扩展资源列表:
以下是一些常用的 Django 扩展和第三方应用,可以帮助开发人员提高工作效率和增强应用功能:
- django-debug-toolbar:一个 Django 调试工具,提供有关请求、视图、模板、SQL 查询、缓存等方面的信息。
- django-extensions:提供一些有用的 Django 管理命令和扩展,如自动生成 South 数据库迁移、shell_plus 和其他实用工具。
- django-crispy-forms:一个 Django 应用,可以让你更轻松地控制表单的渲染方式。
- django-rest-framework:一个 Django 的 RESTful API 框架,使得构建 Web API 更加简单。
- django-filter:一个 Django 应用,为 ListView 和 GenericView 提供了强大的过滤功能。
Django 社区与支持:
- Django 官方网站:提供 Django 框架的最新资讯、文档和下载。
- Django 中文社区:提供 Django 中文文档、教程、视频、问答等资源。
- Django Software Foundation:Django 的官方非盈利组织,提供 Django 开发和维护的资金支持。
- Django 问答社区:一个 Django 社区问答平台,可以在上面寻求帮助和分享经验。
- Django Stack Overflow:一个关于 Django 的问答社区,可以在上面寻求帮助和分享经验。
- Django 包索引:一个 Django 包和应用的搜索引擎,可以在上面找到适合你需求的扩展和工具。
相关文章:

Django信号与扩展:深入理解与实践
title: Django信号与扩展:深入理解与实践 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 后端开发 tags: Django信号松耦合观察者扩展安全性能 第一部分:Django信号基础 Django信号概述 一. Django信号的定义与作用 Django信…...

使用Docker创建verdaccio私服
verdaccio官网 1.Docker安装 这边以Ubuntu安装为例Ubuntu 安装Docker,具体安装方式请根据自己电脑自行搜索。 2.下载verdaccio docker pull verdaccio/verdaccio3.运行verdaccio 运行容器: docker run -it -d --name verdaccio -p 4873:4873 ver…...

Spring 使用 Groovy 实现动态server
本人在项目中遇到这么个需求,有一个模块的server方法需要频繁修改 经阅读可以使用 Groovy 使用java脚本来时pom坐标 <dependency><groupId>org.codehaus.groovy</groupId><artifactId>groovy</artifactId><version>3.0.9</version>…...

oracle不得不知道的sql
一、oracle 查询语句 1.translate select translate(abc你好cdefgdc,abcdefg,1234567)from dual; select translate(abc你好cdefgdc,abcdefg,)from dual;--如果替换字符整个为空字符 ,则直接返回null select translate(abc你好cdefgdc,abcdefg,122)from dual; sel…...

算法-卡尔曼滤波之卡尔曼滤波的第二个方程:预测方程(状态外推方程)
在上一节中,使用了静态模型,我们推导出了卡尔曼滤波的状态更新方程,但是在实际情况下,系统都是动态,预测阶段,前后时刻的状态是改变的,此时我们引入预测方程,也叫状态外推方程&#…...

刘邦的创业团队是沛县人,朱元璋的则是凤阳;要创业,一个县人才就够了
当人们回顾刘邦和朱元璋的创业经历时,总是会感慨他们起于微末,都创下了偌大王朝,成就无上荣誉。 尤其是我们查阅史书时,发现这二人的崛起班底都是各自的家乡人,例如刘邦的班底就是沛县人,朱元璋的班底是凤…...

【Unity之FairyGUI】你了解FGUI吗,跨平台多功能高效UI插件
👨💻个人主页:元宇宙-秩沅 👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨💻 本文由 秩沅 原创 👨💻 收录于专栏:就业…...

基于51单片机的自动浇花器电路
一、系统概述 自动浇水灌溉系统设计方案,以AT89C51单片机为控制核心,采用模块化的设计方法。 组成部分为:5V供电模块、土壤湿度传感器模块、ADC0832模数转换模块、水泵控制模块、按键输入模块、LCD显示模块和声光报警模块,结构如…...

2024中国(重庆)商旅文化川渝美食暨消费品博览会8月举办
2024中国(重庆)商旅文化川渝美食暨消费品博览会8月举办 邀请函 主办单位: 中国航空学会 重庆市南岸区人民政府 招商执行单位: 重庆港华展览有限公司 展会背景: 2024中国航空科普大会暨第八届全国青少年无人机大赛在重庆举办ÿ…...

MacOS docker 安装与配置
orbstack 安装 官网: https://orbstack.dev 下载链接:Download OrbStack Fast, light, simple Docker Desktop alternative 选择是Apple M系列处理器, 或 Intel系列处理器 到这里就安装好了Orbstack软件,下面开始配置docker 下…...

【嵌入式大赛应用赛道】机械手臂
电机 进步电机:它的转动是以确定的步数进行的,只要计算好脉冲数量和频率,就可以准确预测和控制电机的转动角度、速度以及停止的位置 伺服电机:将输入的电信号(如电压或电流指令)转换成轴上的精确旋转运动…...

MES系统主要包括那些功能?
一开始接触MES系统,对MES细条的功能不清楚,这样很正常,因为MES系统相对于其他系统来讲,功能有多又复杂! 作为曾参与200企业MES系统架构的资深从业人员,我给大家选出了一款优秀模板——简道云MES系统,给大家…...

git 合并commit
操作步骤 合并commit cd xxx/ git checkout a8c0efegfwgtw # 最新commit git reset rhgertheryhg --soft # 最初的commit git status git checkout -b test1 git commit -m "test1" git branch git push origin test1 git tag test1_v0.0.1 git push origin test1_…...

【ARMv8/v9 系统寄存器 5 -- CPU ID 判断寄存器 MPIDR_EL1 使用详细介绍】
文章目录 寄存器名称: MPIDR_EL1寄存器结构:主要功能和用途亲和级别(Affinity Levels)简介CORE ID 获取函数 在ARMv8-A架构中, MPIDR_EL1寄存器是一个非常重要的系统寄存器,它提供了关于处理器在其物理和逻辑配置中的位置的信息。…...

软件工程课程设计之酒店管理系统的设计与实现
这是一个简化的酒店管理系统的需求分析文档、系统设计文档、测试文档的结构概述,以及部分实现阶段的代码示例。详细设计阶段的数据字典、ER图、模块分类图将以文字描述形式给出,而完整的代码未完全实现。这里只做软件工程部分的设计需求说明哈࿵…...

函数递归练习
目录 1.分析下面选择题 2.实现求第n个斐波那契数 3.编写一个函数实现n的k次方,使用递归实现。 4.写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和 5.递归方式实现打印一个整数的每一位 6.实现求n的阶乘 1.分析下面选择…...

公有云Linux模拟TCP三次挥手与四次握手(Wireshark抓包验证版)
目录 写在前面环境准备实验步骤1. 安装nc工具2. 使用nc打开一个连接2.1 公有云-安全组放行对应端口(可选) 3. 打开Wireshark抓包工具4. 新开终端,进行连接5. 查看抓包文件,验证TCP三次握手与四次挥手TCP三次握手数据传输TCP四次挥…...

【Day3:JAVA运算符、方法的介绍】
目录 1、运算符1.1 赋值运算符1.2 比较运算符1.3 逻辑运算符1.3.1 逻辑运算符概述1.3.2 逻辑运算符分类1.3.3 短路的逻辑运算符 1.4 三元运算符1.5 运算符优先级 2、方法2.1 方法介绍2.2 方法的定义和调用格式2.2.1 方法的调用2.2.2 带参数方法的调用2.2.3 带返回值方法的调用2…...

Chrome查看User Agent的实战教程
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

Linux 第三十四章
🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C,linux 🔥座右铭:“不要等到什么都没有了…...

国际化日期(inti)
我们可以使用国际化API自动的格式化数字或者日期,并且格式化日期或数字的时候是按照各个国家的习惯来进行格式化的,非常的简单; const now new Date(); labelDate.textContent new Intl.DateTimeFormat(zh-CN).format(now);比如说这是按照…...

【论文阅读笔记】jTrans(ISSTA 22)
个人博客地址 [ISSTA 22] jTrans(个人阅读笔记) 论文:《jTrans: Jump-Aware Transformer for Binary Code Similarity》 仓库:https://github.com/vul337/jTrans 提出的问题 二进制代码相似性检测(BCSD࿰…...

单位个人如何向期刊投稿发表文章?
在单位担任信息宣传员一职以来,我深感肩上的责任重大。每月的对外信息宣传投稿不仅是工作的核心,更是衡量我们部门成效的重要指标。起初,我满腔热血,以为只要勤勉努力,将精心撰写的稿件投至各大报社、报纸期刊的官方邮箱,就能顺利登上版面,赢得读者的青睐。然而,现实远比理想骨…...

Redis数据结构-RedisObject
1.7 Redis数据结构-RedisObject Redis中的任意数据类型的键和值都会被封装为一个RedisObject,也叫做Redis对象,源码如下: 1、什么是redisObject: 从Redis的使用者的角度来看,⼀个Redis节点包含多个databaseÿ…...

Vue 中使用 el-date-picker 限制只能选择当天、当天之前或当天之后日期的方法详解
网上很多都是不完整的,我这里发布一个完整的 - 8.64e7 表示可选择当天时间(注:小于当前时间,- 8.64e7 则是禁用日期不包含当前日,若大于当前日期, 8.64e7 则是禁用日期包含当前日) time.getTi…...

系列介绍:《创意代码:Processing艺术编程之旅》
系列介绍:《创意代码:Processing艺术编程之旅》 标题创意: “代码绘梦:Processing艺术编程入门”“数字画布:用Processing创造视觉奇迹”“编程美学:Processing艺术创作指南”“创意编程:Proc…...

深度学习设计模式之抽象工厂模式
文章目录 前言一、介绍二、详细分析1.核心组成2.实现步骤3.代码示例4.优缺点优点缺点 5.使用场景 总结 前言 本文主要学习抽象工厂模式,抽象工厂模式创建的是对象家族,比如:苹果是一个产品,但是他不单单只生产手机,还…...

K8s是什么?
url address K8s是一个开源的容器编排平台,可以自动化,在部署,管理和扩展容器化应用过程中涉及的许多手动操作。 Kubernetes最初是由Google工程师作为Borg项目开发和设计的,后于2015年捐赠给云原生计算基金会(CNCF&a…...

【网站项目】SpringBoot796水产养殖系统
🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板ÿ…...

Vue详细介绍
Vue.js(通常简称为Vue)是一个用于构建用户界面的渐进式JavaScript框架。它由尤雨溪(Evan You)创建,并于2014年首次发布。Vue的设计目的是易于上手,同时也能够强大到驱动复杂的单页应用(SPA&…...