讲师中心 微信公众号

扫码关注官方订阅号

注册 / 登录
首页
文章
后端开发 web前端 数据库 开发工具 php框架 常见问题 人工智能 Java 系统教程 电脑教程 硬件教程 手机教程 软件教程 游戏教程 自媒体 新闻
专题
后端开发 web前端 数据库 开发工具 php框架 人工智能 Java 系统教程 电脑教程 硬件教程 手机教程 软件教程 游戏教程 新闻
AI工具
AI 聊天问答 Agent智能体 AI 文本写作 AI 绘画作图 AI 设计工具 AI 视频创作 AI 音频制作 AI 办公学习 AI 编程开发 Prompt指令
学习
大前端 后端开发 数据库 移动端 运维开发 计算机基础
编程手册
大前端 后端开发 数据库 移动端 运维开发 计算机基础
下载
js特效 网站源码 工具下载 类库下载 网站素材 学习资源 插件扩展 手机游戏
最近更新
当前位置:首页 > web前端 > js教程 >

正文

0

0

关于js设计模式的超详细介绍

零到壹度

零到壹度

发布时间:2018-04-13 17:42:06

|

1411人浏览过

|

来源于php中文网

原创


本篇文章给大家分享的内容是关于js设计模式的超详细介绍,有着一定的参考价值,有需要的朋友可以参考一下

js设计模式

Jan 14, 2017 | 学习笔记 | 3387 Hits


目录

  • 前言

  • 单体模式

  • 工厂模式

  • 迭代器模式

  • 装饰者模式

  • 策略模式

  • 外观模式

  • 代理模式

  • 中介者模式

  • 观察者模式

前言

本文参考于《javascript模式》,因此会大量内容会和书中相同,手上有这本书的朋友可以直接看书。因为我的记忆习惯是抄书,所以我会先抄写下来再发到博客上。

单体模式

单体模式思想在于保证一个特定类仅有一个实例,意味着当你第二次使用同一个类创建信对象时,应得到和第一次创建对象完全相同。

方法一

@@######@@ @@######@@


缺点

instance 属性暴露。

方法二

使用闭包

@@######@@ @@######@@


缺点

因为重写了构造函数,constructor 还是指向了老的构造函数,且实例化后在添加原型属性也是不一样的。如下

@@######@@ @@######@@


方法三

解决方法二问题。

@@######@@


@@######@@


方法四

自运行函数。

@@######@@ @@######@@


工厂模式

工厂模式是为了创建对象。

例子

  • 公共构造函数 CarMaker

  • 名为factory的CarMaker静态方法来创建car对象

@@######@@ @@######@@


实现

@@######@@


@@######@@@@######@@


内置工厂对象

Object() 构造函数即为内置工厂对象。

迭代器模式

有一个包含某种数据集合的对象,该数据可能存储在一个复杂数据结构内部,而要提供一个简单方法讷讷感访问到数据结构中没一个元素。

  • next() 下一个

    闪拍cms竞拍系统
    闪拍cms竞拍系统

    竞拍程序针对一个商品进行竞拍,每个客户出价需要消耗一定量的金币,每次出价后倒计时会返回20秒,价格会加一点,这个都根据网站后台设置的,如果客户出价后,20内没有人出价,他就拍到商品了。对于网站运营着来说是采取的叠加方式收入的比如 1+2+3+4…… 具体详细玩法可见压缩包内详细例子介绍。

    下载
  • hasNext() 是否有下一个

  • reWind() 重置指针

  • current() 返回当前

@@######@@


@@######@@


装饰者模式

可以在运行时候添加附加功能到对象中,他的一个方便特征在于其预期行为的可定制和可配置特性。

例子 假设在开发一个销售商品的Web应用,每一笔信销售都是一个人新的 sale 对象。该对象“知道”有关项目的价格,并可以通过 getPrice() 方法返回加个。
根据不同情况,可以用额外的功能装饰此对象。
假设客户在魁北克省,买房需要支付联邦税和魁北克省税,则此时需要调用联邦税装饰者和魁北克省税装饰者。

@@######@@ @@######@@


并且装饰是可选的,例如不再魁北克省有可能没有省税。

方法一

@@######@@ @@######@@


方法二

此方法使用列表实现,而且相对来说比较好理解一点。本质就是把装饰者名称保存到一个列表中并且一次调用此列表中的方法。

@@######@@


@@######@@


策略模式

策略模式支持在运行时候选择算法。例如用在表单验证问题上,可以创建一个具有 validate() 方法的验证器对象,无论表单具体类型是什么,该方法都会被调用,
并且返回结果或者错误信息。

@@######@@


@@######@@


策略模式定义及例子实现参考与《javascript模式》及 汤姆大叔的博客

外观模式

外观模式即让多个方法一起被调用

例如。 stopPropagation() 和 preventDefault() 兼容性一起调用。

@@######@@


@@######@@


代理模式

在代理模式中,一个对象充当另外一个对象的接口,和外观模式区别是:外观模式是合并调用多个方法。
代理模式是介于对象的客户端和对象本身之间,并且对该对象的访问进行保护。

包裹例子

现在有个包裹,卖家要把这个包裹寄给gary,则需要通过快递公司寄过来,此时快递公司就是一个 proxy

@@######@@


@@######@@


论坛权限管理例子

本例子参考与 大熊君

  • 权限列表

    • 发帖 1

    • 帖子审核 2

    • 删帖 3

    • 留言、回复 4

用户 代码 权限
注册用户 001 1 4
论坛管理员 002 2 3 4
系统管理员 003 1 2 3 4
游客 000 null

用户类

@@######@@


@@######@@


论坛类

@@######@@


@@######@@


运行

@@######@@


@@######@@


中介者模式

中介者模式可以让多个对象之间松耦合,并降低维护成本

例如:游戏程序,两名玩家分别给与半分钟时间来竞争决出胜负(谁按键的次数多胜出,这里玩家1按1,玩家2按0)

  • 计分板(scoreboard)

  • 中介者 (mediator)

中介者知道所有其他对象的信息。他与输入设备(此时是键盘)进行通信并处理键盘上的按键时间,之后还将消息通知玩家。玩家玩游戏同时(每一分都更新自己分数)还要
通知中介者他所做的事情。中介者将更新后的分数传达给计分板。

除了中介者莫有对象知道其他对象。

图示

图示

@@######@@


@@######@@


观察者模式

观察者模式在 javascript 中使用非常广泛。所有的浏览器时间就是该模式的实现,node.js中的events也是此模式实现。
此模式另一个名称是 订阅/发布模式 。
设计这种模式原因是促进形成松散耦合,在这种模式中,并不是一个对象调用另一个对象的方法,而是一个对象订阅另一个对象的
特定活动并在状态改编后获得通知。订阅者因此也成为观察者,而被观察的对象成为发布者或者主题。当发生了一个重要事件时候
发布者会通知(调用)所有订阅者并且可能经常已事件对象的形式传递消息。

小结

1.单体模式

针对一个类仅创建一个对象。

2.工厂模式

根据字符串制定类型在运行时创建对象的方法。

3.迭代器模式

提供一个API来遍历或者操作复杂的自定义数据结构。

4.装饰者模式

通过从预定义装饰者对象中添加功能,从而在运行时侯调整对象

5.策略模式

在悬在最佳策略以处理特定任务的时候仍然保持相同的接口。

6.外观模式

通过把常用方法包装到一个新方法中,从来提供一个更为便利的API。

7.代理模式

通过包装一个对象从而控制对它的访问,其中主要方法是将方位聚集为租或者
仅当真正必要时侯才执行访问,从未避免高昂的操作开销。

8.终结者模式

通过是你的对象之间相互不直接“通话”,而是通过一个中介者对子昂进行通信,
从而形成松散耦合。

9.观察者模式

通过创建“可观察”的对象,当发生一个感兴趣的事件时可将改时间通告给所有观察者
从而形成松散耦合。


function Universe(){
if(typeof Universe.instance==="object"){
return Universe.instance; //防止被篡改
}
this.xx="xx";
Universe.instance=this;
return this;
}
var uni=new Universe();
var uni2=new Universe();
uni===uni2; //true

function Universe(){
var instance=this; //缓存this
this.xx="xx";
Universe=function(){ //重写此构造函数
return instance;
}
}
var uni=new Universe();
var uni2=new Universe();
uni===uni2; //true

var uni = new Universe();
Universe.prototype.a = 1
var uni2 = new Universe();
console.log(uni === uni2) //true
console.log(uni.a) //undefinded
console.log(uni2.a) //undefinded
console.log(uni.constructor === Universe); //false

function Universe(){
var instance;
Universe=function Universe(){
return instance ;
}
Universe.prototype=this; //保存原型属性
instance=new Universe();
instance.constructor=Universe;
instance.xx="xx";
}

var Universe;
(function(){
var instance;
Universe=function Universe(){
if(instance){
return instance;
}
instance=this;
this.xx="xx";
}
})();
var uni = new Universe();
Universe.prototype.a = 1
var uni2 = new Universe();
console.log(uni === uni2) //true
console.log(uni.a)   //1
console.log(uni2.a)  //1
console.log(uni.constructor === Universe);  //true

var corolla=CarMaker.factory('compact');
var solstice=CarMaker.factory('convertible');
var cherokee=CarMaker.factory('suv');
corolla.drive() //I have 4 doors
solstice.drive() //I have 2 doors
cherokee.drive() //I have 6 doors


function CarMaker() {}
CarMaker.prototype.drive = function() {
return "I have " + this.doors + " doors";
}
CarMaker.compact = function() {
this.doors = 4;
}
CarMaker.convertible = function() {
this.doors = 2
}
CarMaker.suv = function() {
this.doors = 6;
}
CarMaker.factory = function(type) {
if (typeof CarMaker[type] !== "function") {
throw "Error"
}
if (typeof CarMaker[type].prototype.drive !== "function") {
CarMaker[type].prototype = new CarMaker();
}
var newCar = new CarMaker[type]();
return newCar;
}
var corolla = CarMaker.factory('compact');
console.log(corolla.drive()); //I have 4 doors

var agg = (function() {
var index = 0;
var data = [1, 2, 3, 4, 5, 6];
var length = data.length;
return {
next: function() { //这里是从第一个数据开始输出 本例中为 1
if (!this.hasNext()) {
return null;
}
var element = data[index];
index++;
return element;
},
hasNext: function() {
return index < length;
},
reWind: function() {
index = 0;
},
current: function() {
return data[index];
}
}
})();
while (agg.hasNext()) {
console.log(agg.next()); //1,2,3,4,5,6
}
agg.reWind();  //此时重置指针到0

var sale=new Sale(100);
sale=sale.decorate("fedtax"); //联邦税
sale=sale.decorate("quebec"); //魁北克省税
sale=sale.decorate("miney"); //转为美元格式
sale.getPrice(); //返回价格

function Sale(price) {
this.price = price;
}
Sale.prototype.getPrice = function() {
return this.price;
};
Sale.decorators = {}; //储存装饰者的对象
//装饰者
Sale.decorators.fedtax = {
getPrice: function() {
var price = this.uber.getPrice();
return price * 0.8; //对price进行处理
},
}
Sale.decorators.quebec = {
getPrice: function() {
var price = this.uber.getPrice();
return price * 0.7; //对price进行处理
},
}
Sale.decorators.money = {
getPrice: function() {
var price = this.uber.getPrice();
return "$" + price * 0.9; //对price进行处理
},
}
/*decorate() 方法
调用装饰者方法 sale.=sale.decorate("fedtax");
fedtax字符串对应 Sale.decorators中的对象属性。新装饰对象 newobj 将继承目前我们所拥有的对象,这就是ixiangthis
为了完成继承部分代码,此时需要一个临时构造函数,先设置 newobj 的 uber 属性,以便于自对象可以访问到父对象。之后从装饰者中
将所有的额外属性复制到新装饰的对象 newobj 中,最后返回 newobj。
*/
Sale.prototype.decorate = function(decorate) {
var F = function() {};
var overrides = this.constructor.decorators[decorate]; //获取装饰者对象
F.prototype = this;
var newobj = new F();
newobj.uber = F.prototype;
for (var key in overrides) {
if (overrides.hasOwnProperty) { //判断对象是不是自身的
newobj[key] = overrides[key];
}
}
return newobj;
};
var sale = new Sale(100);
sale = sale.decorate("fedtax"); //联邦税
sale = sale.decorate("quebec"); //魁北克省税
sale = sale.decorate("money"); //转为美元格式
console.log(sale.getPrice()); //$50.4

function Sale(price) {
this.price = price;
this.decorateList = [];
}
Sale.decorators = {};
Sale.decorators.fedtax = {
getPrice: function(price) {
var price = this.uber.getPrice();
return price * 0.8; //对price进行处理
},
}
Sale.decorators.quebec = {
getPrice: function(price) {
var price = this.uber.getPrice();
return price * 0.7; //对price进行处理
},
}
Sale.decorators.money = {
getPrice: function(price) {
var price = this.uber.getPrice();
return "$" + price * 0.9; //对price进行处理
},
}
Sale.prototype.decorate = function(decorator) {
this.decorateList.push(decorator);
};
Sale.prototype.getPrice = function() {
var price = this.price;
this.decorateList.forEach(function(name) {
price = Sale.decorators[name].getPrice(price);
});
return price;
};
var sale = new Sale(100);
sale = sale.decorate("fedtax"); //联邦税
sale = sale.decorate("quebec"); //魁北克省税
sale = sale.decorate("money"); //转为美元格式
console.log(sale.getPrice()); //$50.4

var validator = {
// 所有可以的验证规则处理类存放的地方,后面会单独定义
types: {},
// 验证类型所对应的错误消息
messages: [],
// 当然需要使用的验证类型
config: {},
// 暴露的公开验证方法
// 传入的参数是 key => value对
validate: function (data) {
var i, msg, type, checker, result_ok;
// 清空所有的错误信息
this.messages = [];
for (i in data) {
if (data.hasOwnProperty(i)) {
type = this.config[i];  // 根据key查询是否有存在的验证规则
checker = this.types[type]; // 获取验证规则的验证类
if (!type) {
continue; // 如果验证规则不存在,则不处理
}
if (!checker) { // 如果验证规则类不存在,抛出异常
throw {
name: "ValidationError",
message: "No handler to validate type " + type
};
}
result_ok = checker.validate(data[i]); // 使用查到到的单个验证类进行验证
if (!result_ok) {
msg = "Invalid value for *" + i + "*, " + checker.instructions;
this.messages.push(msg);
}
}
}
return this.hasErrors();
},
// helper
hasErrors: function () {
return this.messages.length !== 0;
}
};
//然后剩下的工作,就是定义types里存放的各种验证类了
// 验证给定的值是否不为空
validator.types.isNonEmpty = {
validate: function (value) {
return value !== "";
},
instructions: "传入的值不能为空"
};
// 验证给定的值是否是数字
validator.types.isNumber = {
validate: function (value) {
return !isNaN(value);
},
instructions: "传入的值只能是合法的数字,例如:1, 3.14 or 2010"
};
// 验证给定的值是否只是字母或数字
validator.types.isAlphaNum = {
validate: function (value) {
return !/[^a-z0-9]/i.test(value);
},
instructions: "传入的值只能保护字母和数字,不能包含特殊字符"
};
//使用的时候,我们首先要定义需要验证的数据集合,然后还需要定义每种数据需要验证的规则类型,代码如下:
var data = {
first_name: "Tom",
last_name: "Xu",
age: "unknown",
username: "TomXu"
};
validator.config = {
first_name: 'isNonEmpty',
age: 'isNumber',
username: 'isAlphaNum'
};
//最后获取验证结果 
validator.validate(data);
if (validator.hasErrors()) {
console.log(validator.messages.join("\n"));
}

var myEvent = {
stop: function(e) {
if (typeof e.preventDefault() === "function") {
e.preventDefault();
}
if (typeof e.stopPropagation() === "function") {
e.stopPropagation();
}
//for IE
if (typeof e.returnValue === "boolean") {
e.returnValue = false;
}
if (typeof e.cancelBubble === "boolean") {
e.cancelBubble = true;
}
}
}

var package = function(receiver) {
this.receiver = receiver;
}
var seller = function(package) {
this.package = package;
this.send = function(gift) {
return package.receiver + "你的包裹:" + gift;
}
}
var express = function(package) {
this.package = package;
this.send = function(packageName) {
return new seller(package).send(packageName);
}
}
//调用
var ems = new express(new package("gary"));
console.log(ems.send("键盘")); //gary你的包裹:键盘

function User(name, code) {
this.name = name;
this.code = code;
}
User.prototype.getName = function() {
return this.name;
};
User.prototype.getCode = function() {
return this.code;
};
User.prototype.post = function() {
//发帖功能
};
User.prototype.remove = function() {
// 删帖功能
};
User.prototype.check = function() {
//审核
};
User.prototype.comment = function() {
//留言回复
};

function Forum(user) {
this.user=user;
}
Forum.prototype.getUser = function () {
return this.user;
};
Forum.prototype.post = function () {
var code=this.user.getCode();
if(code=="001"||code=="003"){
return this.user.post();
}else{
return false;
}
};
Forum.prototype.remove = function () {
var code=this.user.getCode();
if(code=="002"||code=="003"){
return this.user.remove();
}else{
return false;
}
};
Forum.prototype.check = function () {
var code=this.user.getCode();
if(code=="002"||code=="003"){
return this.user.check();
}else{
return false;
}
};
Forum.prototype.comment = function () {
var code=this.user.getCode();
if(code=="001"||code=="002"||code=="003"){
return this.user.comment();
}else{
return false;
}
};

new Forum(new User("administartor","003"));

function Player(name) {
this.points = 0;
this.name = name;
}
Player.prototype.play = function() {
this.points += 1;
mediator.played();
};
var scoreboard = {
element: "这里是获取的element用于展示分数",
update: function(score) { //更新分数
var msg;
for (var key in score) {
if (score.hasOwnProperty(key)) {
msg += score[key];
}
}
this.element.innerText = msg;
},
}
var mediator = {
players: {}, //玩家对象
setup: function() {
var players = this.players;
players.home = new Player("home");
players.guest = new Player('guest');
},
played: function() {
var players = this.players;
var score = {
home: players.home.points,
guest: players.guest.points
}
},
keypress: function(e) {
e = e || window.event;
if (e.which === 49) { //or keycode   对应按键 1
mediator.players.home.play();
return;
}
if (e.which === 48) { // 对应按键 0
mediator.player.guest.play();
return;
}
},
}
//运行
mediator.setup();
window.onkeypress = mediator.keypress;
setTimeout(function() { //设置30秒游戏时间
window.onkeypress = null;
alert("game end");
}, 30000);

相关文章

如何从URL哈希值中提取参数并动态显示在HTML标签内

如何准确计算用户年龄:JavaScript 日期差值的正确处理方法

如何自定义复选框选中状态的背景颜色

如何在 Angular 中通过 CSS 自定义复选框选中后的背景色

如何在 Flask 模板中动态选择图像路径并实现交互式图像集切换

相关标签:

javascript

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

上一篇:JS怎么判断客户端类型 下一篇:一些关于js的实用小算法

作者最新文章

跟我学PS第四天01:如何给照片加边框效果

2018-07-23 16:21

跟我学PS第四天02:练习Photoshop中的套索工具

2018-07-23 17:56

跟我学PS第五天01:使用裁剪工具

2018-07-27 15:22

跟我学PS第五天02:移动工具的使用方法和应用

2018-07-27 16:59

跟我学PS第六天01:修复画笔工具

2018-07-28 15:36

跟我学PS第六天02:模糊工具

2018-08-14 16:35

跟我学PS第七天01:如何将彩图抠出线稿效果

2018-08-18 11:26

跟我学PS第七天02:如何抠出复杂树林

2018-08-20 16:25

跟我学PS第八天01:如何抠取文件中的印章

2018-08-25 10:55

跟我学PS第八天02:光效素材的抠图方法

2018-08-28 15:02

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

AI 编程开发AI 聊天问答
豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

AI 编程开发AI大模型
通义千问
通义千问

阿里巴巴推出的全能AI助手

AI 编程开发Agent智能体
腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文档处理AI 聊天问答
文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

AI 编程开发AI 文本写作
讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

AI 文本写作中文写作
即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

图片拼接
ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

AI 编程开发AI 文本写作
智谱清言 - 免费全能的AI助手
智谱清言 - 免费全能的AI助手

智谱清言 - 免费全能的AI助手

AI 编程开发Agent智能体

相关专题

更多
C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

14

2026.01.30

c++ 字符串格式化
c++ 字符串格式化

本专题整合了c++字符串格式化用法、输出技巧、实践等等内容,阅读专题下面的文章了解更多详细内容。

9

2026.01.30

java 字符串格式化
java 字符串格式化

本专题整合了java如何进行字符串格式化相关教程、使用解析、方法详解等等内容。阅读专题下面的文章了解更多详细教程。

12

2026.01.30

python 字符串格式化
python 字符串格式化

本专题整合了python字符串格式化教程、实践、方法、进阶等等相关内容,阅读专题下面的文章了解更多详细操作。

4

2026.01.30

java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

20

2026.01.29

java配置环境变量教程合集
java配置环境变量教程合集

本专题整合了java配置环境变量设置、步骤、安装jdk、避免冲突等等相关内容,阅读专题下面的文章了解更多详细操作。

18

2026.01.29

java成品学习网站推荐大全
java成品学习网站推荐大全

本专题整合了java成品网站、在线成品网站源码、源码入口等等相关内容,阅读专题下面的文章了解更多详细推荐内容。

19

2026.01.29

Java字符串处理使用教程合集
Java字符串处理使用教程合集

本专题整合了Java字符串截取、处理、使用、实战等等教程内容,阅读专题下面的文章了解详细操作教程。

3

2026.01.29

Java空对象相关教程合集
Java空对象相关教程合集

本专题整合了Java空对象相关教程,阅读专题下面的文章了解更多详细内容。

6

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板
  • [图片特效]jQuery带标题的3D图片切换代码
  • [图片特效]jQuery鼠标滚轮控制幻灯片切换
  • [表单按钮]jQuery微信手机端答题表单特效
  • [表单按钮]js正则表达式表单验证代码
  • [图片特效]CSS3图片形状遮罩动画效果
  • [表单按钮]div css手机网站login表单特效
  • [图片特效]qq空间遮罩层jQuery相册切换
  • [表单按钮]jquery衣服尺寸勾选表单
  • [图片特效]22款不同效果产品图片展示切换
  • [表单按钮]jquery带登录注册幻灯片代码
  • [电商源码]openaishop
  • [其它模板]思翔企(事)业单位文件柜 build 20080313
  • [企业站源码]雅龙智能装备工业设备类WordPress主题1.0
  • [电商源码]威发卡自动发卡系统
  • [电商源码]卡密分发系统
  • [电商源码]中华陶瓷网
  • [电商源码]简洁粉色食品公司网站
  • [电商源码]极速网店系统
  • [电商源码]淘宝妈妈_淘客推广系统
  • [电商源码]积客B2SCMS商城系统
  • [网站素材]2026红色几何马年矢量素材
  • [网站素材]手绘烘焙面包食材合集矢量素材
  • [网站素材]复古红日山峰风景矢量素材
  • [网站素材]极简复古意大利面海报矢量模板
  • [网站素材]国风红色灯笼装饰合集矢量素材
  • [网站素材]快餐美食宣传海报模板INS下载
  • [网站素材]卡通灯塔房屋建筑合集矢量素材
  • [网站素材]黑色耳机宣传海报PSD模板设计下载
  • [网站素材]冬季蓝色雪花松枝合集矢量素材
  • [网站素材]情人节爱心主题海报PSD源文件设计下载
  • [前端模板]驾照考试驾校HTML5网站模板
  • [前端模板]驾照培训服务机构宣传网站模板
  • [前端模板]HTML5房地产公司宣传网站模板
  • [前端模板]新鲜有机肉类宣传网站模板
  • [前端模板]响应式天气预报宣传网站模板
  • [前端模板]房屋建筑维修公司网站CSS模板
  • [前端模板]响应式志愿者服务网站模板
  • [前端模板]创意T恤打印店网站HTML5模板
  • [前端模板]网页开发岗位简历作品展示网页模板
  • [前端模板]响应式人力资源机构宣传网站模板

相关下载

更多
闪拍cms竞拍系统
魔众商城系统
凡客系统
声讯电话整站程序
凡人网络购物系统jsp版(JspShop)

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 4.4万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.6万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.1万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 11.2万人学习

最新ThinkPHP 5.1全球首发视频教程(60天成就PHP大牛线上培训班课)
最新ThinkPHP 5.1全球首发视频教程(60天成就PHP大牛线上培训班课)

共79课时 | 151.8万人学习

phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 53.4万人学习

最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.4万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 11.2万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.9万人学习

最新文章

更多
如何在 Django 中正确获取通过 FormData 上传的文件对象
如何在 Chrome 扩展中实现对话框打开时临时屏蔽非关键按键事件
javascript通知api如何使用_怎样发送桌面浏览器通知【教程】
实现两级联动下拉菜单并确保表单能同时提交分类ID与子分类ID
如何从URL哈希值中提取参数并动态显示在HTML标签内
如何准确计算用户年龄:JavaScript 日期差值的正确处理方法
如何实现基于主下拉框动态筛选并提交子下拉框的完整表单
HTML 下拉联动:基于主选项动态筛选子选项并保留 value 值用于表单提交
HTML 下拉联动:基于主分类动态更新子分类并保留 value 值用于表单提交
实现 HTML 下拉联动并保留表单提交所需的 value 值
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号

微信扫码
关注PHP中文网服务号

技术交流群

QQ扫码
加入技术交流群

PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号

  • PHP学习

  • 技术支持

  • 返回顶部