前端设计模式和设计原则之设计模式
作为前端开发,在code时,或多或少地都会践行设计模式,但是你清楚自己用到的是何种设计模式吗?
为什么前端开发一定要懂设计模式呢?
code时不遵从设计模式,又能怎样呢?
上面的问题可以留作思考,这里首先介绍一下前端开发经常遇到的一些设计模式和设计原则。
前端常见的设计模式
1 单例模式
在整个应用程序中只允许创建一个实例的模式。
在前端开发中,它通常用于管理全局状态或资源,例如:
- 在 React 应用中,使用 Redux 库来管理应用的状态;
- 在 Vue 应用中,使用 Vuex 库来管理应用的状态;
- 在 Angular 应用中,使用 Service 来管理应用的状态;
angular 服务是可注入的类,用于提供共享的数据、功能或逻辑给整个应用程序的组件;由于服务是以单例形式存在的,每次注入服务都会返回同一个实例。
使用@Injectable({ providedIn: 'root' })
装饰器将MyService
注册为根级提供商,这意味着整个应用程序都可以访问该服务的单一实例。
// my.service.tsimport { Injectable } from '@angular/core';@Injectable({providedIn: 'root'
})export class MyService {private count: number = 0;incrementCount() {this.count++;}getCount(): number {return this.count;}
}
在组件中,可以通过依赖注入的方式来使用该服务;
// my.component.tsimport { Component } from '@angular/core';
import { MyService } from './my.service';@Component({selector: 'my-component',template: `<h2>Count: {{ myService.getCount() }}</h2><button (click)="incrementCount()">Increment Count</button>`
})
export class MyComponent {constructor(private myService: MyService) {}incrementCount() {this.myService.incrementCount();}
}
拓展
如果在Angular中的
@Injectable
装饰器的providedIn
配置中不使用"root"
,而是指定其他模块或组件,那么该服务将在该模块或组件的范围内成为单例。
这意味着,服务将在指定的模块或组件及其子组件中共享同一个实例,而不是在整个应用程序中共享。这对于需要在特定范围内共享数据或功能的场景非常有用。
例如,假设有两个组件ComponentA
和ComponentB
,它们都引用了同一个服务SharedService
,并且将该服务作为提供程序配置在它们各自的模块中。
// shared.service.tsimport { Injectable } from '@angular/core';@Injectable({providedIn: 'other-module' // 指定其他模块,而不是 'root'
})
export class SharedService {public sharedData: string = 'Shared data';
}
// component-a.component.tsimport { Component } from '@angular/core';
import { SharedService } from './shared.service';@Component({selector: 'component-a',template: `<h2>{{ sharedService.sharedData }}</h2>`
})
export class ComponentA {constructor(public sharedService: SharedService) {}
}
// component-b.component.tsimport { Component } from '@angular/core';
import { SharedService } from './shared.service';@Component({selector: 'component-b',template: `<h2>{{ sharedService.sharedData }}</h2>`
})
export class ComponentB {constructor(public sharedService: SharedService) {}
}
在这种情况下,SharedService
将在ComponentA
和ComponentB
之间共享同一个实例,但其作用范围限定在这两个组件及其子组件中。
这种用法可以让开发者更细粒度地控制服务的共享范围,使得不同的模块或组件可以拥有各自独立的服务实例。
2 观察者模式
2.1 Vue.js
针对前端的观察者模式,一种常见的应用是使用Vue.js
框架的响应式系统。Vue.js
使用观察者模式来追踪数据的变化并更新视图。
<!-- index.html --><!DOCTYPE html>
<html>
<head><title>Vue.js Observer Example</title><script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body><div id="app"><h2>{{ message }}</h2><input v-model="message" type="text" placeholder="Type something..."></div><script>// Initialize Vuenew Vue({el: '#app',data: {message: 'Hello, Vue!'}});</script>
</body>
</html>
上述代码中,使用了Vue.js
来创建一个具有双向数据绑定的简单应用。message属性的值将被显示在页面上的 h2 标签中,并且可以通过输入框进行编辑。
Vue.js
的响应式系统会在message
属性发生变化时自动更新页面中对应的内容。这是通过Vue.js在内部使用观察者模式来实现的。当message属性的值发生变化时,观察者会被通知,并执行相应的更新。
这种观察者模式的应用使得开发者无需显式地修改DOM来更新视图,而是只需关注数据的变化,Vue.js会自动处理更新过程。这大大简化了前端开发中处理视图更新的任务。
2.2 Angular
在Angular
中,观察者模式主要通过使用RxJS
(响应式扩展)库来实现。RxJS
是一个强大的事件处理库,它提供了多种操作符和观察者模式的实现,以处理异步事件流。
在Angular
中,通过使用Observables
(可观察对象)和Subjects
(主题),开发者可以实现观察者模式的效果,并在组件之间进行事件通信或数据共享。
下面是一个简单的示例,展示了如何在Angular
中使用观察者模式实现组件之间的通信:
// message.service.tsimport { Injectable } from '@angular/core';
import { Subject } from 'rxjs';@Injectable()
export class MessageService {private messageSubject = new Subject<string>();message$ = this.messageSubject.asObservable();sendMessage(message: string) {this.messageSubject.next(message);}
}
上述代码创建了一个名为MessageService
的服务,它使用Subject
创建了一个消息主题。通过调用主题的next()
方法,可以向订阅该主题的观察者发送消息。
// component-a.component.tsimport { Component } from '@angular/core';
import { MessageService } from './message.service';@Component({selector: 'component-a',template: `<button (click)="sendMessage()">Send Message</button>`
})
export class ComponentA {constructor(private messageService: MessageService) {}sendMessage() {this.messageService.sendMessage('Hello from Component A!');}
}
上述代码创建了一个名为ComponentA
的组件,它通过依赖注入的方式引用了MessageService
。在按钮的点击事件中,我们调用sendMessage()
方法来发送一条消息。
// component-b.component.tsimport { Component } from '@angular/core';
import { MessageService } from './message.service';@Component({selector: 'component-b',template: `<h2>{{ receivedMessage }}</h2>`
})
export class ComponentB {receivedMessage: string = '';constructor(private messageService: MessageService) {}ngOnInit() {this.messageService.message$.subscribe(message => {this.receivedMessage = message;});}
}
上述代码创建了一个名为ComponentB
的组件,并在ngOnInit()
生命周期钩子中订阅了MessageService
的message$
可观察对象。一旦有新的消息发送,观察者将接收到该消息并更新receivedMessage
属性。
使用上述代码,当ComponentA
中的按钮被点击时,它将向ComponentB
发送一条消息,并在ComponentB
中更新显示的消息。这通过观察者模式实现组件之间的双向通信。
2.3 React
在 React
中,观察者模式可以通过使用 Context API
和钩子函数来实现。下面是一个简单的示例:
首先,创建一个观察者上下文(ObserverContext
):
import React, { createContext, useContext, useState } from 'react';const ObserverContext = createContext();export const ObserverProvider = ({ children }) => {const [observers, setObservers] = useState([]);const addObserver = (observer) => {setObservers((prevObservers) => [...prevObservers, observer]);};const removeObserver = (observer) => {setObservers((prevObservers) =>prevObservers.filter((o) => o !== observer));};const notifyObservers = () => {observers.forEach((observer) => observer());};const contextValue = {addObserver,removeObserver,notifyObservers,};return (<ObserverContext.Provider value={contextValue}>{children}</ObserverContext.Provider>);
};export const useObserver = (observer) => {const { addObserver, removeObserver } = useContext(ObserverContext);// 添加观察者useEffect(() => {addObserver(observer);// 组件卸载时移除观察者return () => removeObserver(observer);}, [observer, addObserver, removeObserver]);
};
然后,在需要进行观察的组件中使用 useObserver
钩子来订阅和响应变化。
import React, { useState } from 'react';
import { useObserver } from './ObserverContext';const Counter = () => {const [count, setCount] = useState(0);const handleIncrement = () => {setCount((prevCount) => prevCount + 1);};// 添加观察者useObserver(() => {console.log('Count has changed:', count);});return (<div><p>Count: {count}</p><button onClick={handleIncrement}>Increment</button></div>);
};
在上述示例中,ObserverProvider
提供了观察者的上下文,并定义了添加观察者、移除观察者和通知观察者的方法。使用 useObserver
钩子来订阅观察者模式中的变化。当状态(这里是 count
)发生变化时,观察者将被通知并执行相应的操作。
使用这种方式,可以在 React
中实现简单的观察者模式,以便组件之间能够订阅和响应特定的事件或状态变化。
3 代码工厂模式
代码工厂模式是一种创建对象的设计模式,它通过使用工厂函数或类来封装对象的创建过程。在这种模式下,我们不直接调用对象的构造函数来创建对象,而是通过一个专门的工厂方法来统一管理对象的创建。
代码工厂模式的主要目的是隐藏具体对象创建的细节,并提供一种可扩展和灵活的方式来创建对象。它将对象的实例化逻辑封装在一个独立的组件中,使得创建对象的过程可以进行集中管理,而不是分散在应用程序的各个地方。
3.1 Angular
下面是一个简单的示例,展示了如何在 Angular
中使用代码工厂模式:
import { Injectable } from '@angular/core';@Injectable({providedIn: 'root',
})
export class UserService {private users: string[] = [];addUser(user: string): void {this.users.push(user);}getUsers(): string[] {return this.users;}
}@Injectable({providedIn: 'root',
})
export class UserFactory {constructor(private userService: UserService) {}createUser(name: string): void {this.userService.addUser(name);}
}
在上述示例中,UserService
是一个服务类,它管理用户信息。UserFactory
是一个工厂类,负责创建用户并将其添加到 UserService
中。
在 Angular
中,通过使用 @Injectable()
装饰器和 providedIn: 'root'
选项,我们可以将 UserService
和 UserFactory
注册为可注入的服务,并确保它们在整个应用程序中的任何组件中都可用。
然后,在其他组件中可以通过依赖注入的方式使用这些服务:
import { Component } from '@angular/core';
import { UserFactory } from './user.factory';@Component({...})
export class AppComponent {constructor(private userFactory: UserFactory) {}createUser() {this.userFactory.createUser('John');}
}
在上述示例中,AppComponent
组件通过依赖注入 UserFactory
来使用工厂模式创建用户。
通过在 Angular
中使用代码工厂模式,我们可以将对象的创建和初始化逻辑封装到可注入的服务中,并在需要时利用依赖注入方便地使用这些服务。这样可以提高代码的可维护性、扩展性和测试性。
3.2 React
下面是一个简单的示例,展示了如何在 React
中使用代码工厂模式:
import React from 'react';// 工厂函数
function createButton(type) {const Button = (props) => {let button;if (type === 'primary') {button = (<button className="primary-button" onClick={props.onClick}>{props.children}</button>);} else if (type === 'secondary') {button = (<button className="secondary-button" onClick={props.onClick}>{props.children}</button>);} else {throw new Error('Invalid button type');}return button;};return Button;
}// 使用工厂函数创建按钮组件
const PrimaryButton = createButton('primary');
const SecondaryButton = createButton('secondary');// 使用按钮组件
const App = () => (<div><PrimaryButton onClick={() => console.log("Primary button clicked")}>Primary Button</PrimaryButton><SecondaryButton onClick={() => console.log("Secondary button clicked")}>Secondary Button</SecondaryButton></div>
);
在上述例子中,createButton
是一个工厂函数,根据传入的 type
参数返回一个特定类型的按钮组件。根据不同的类型,创建不同样式、行为或功能的按钮。
通过调用 createButton
工厂函数,可以轻松创建不同类型的按钮组件,并在应用程序中使用它们。这样,避免在多个地方重复编写相似的代码,而是通过工厂模式集中管理和创建组件。
使用工厂模式,可以根据需要快速创建并定制化多个组件,并轻松地进行修改或扩展。这种模式提供了一种更灵活、可维护和可重用的方式来创建和管理 React
组件。
4 策略模式
策略模式用于定义一系列算法,并将其封装成独立的对象,使它们可以相互替换。在前端开发中,策略模式可以用来处理多种算法或逻辑的情况,例如在表单验证中根据不同规则进行验证。
下面是一个简单的示例,用于根据不同的排序策略对数组进行排序:
// 排序策略对象
const sortingStrategies = {quickSort: (arr) => arr.sort((a, b) => a - b),mergeSort: (arr) => arr.sort((a, b) => b - a),
};// 排序上下文对象
class SortContext {constructor(strategy) {this.strategy = strategy;}setStrategy(strategy) {this.strategy = strategy;}sort(arr) {return this.strategy(arr);}
}// 使用策略模式进行排序
const arr = [5, 2, 8, 1, 4];
const context = new SortContext(sortingStrategies.quickSort);
console.log(context.sort(arr)); // 输出: [1, 2, 4, 5, 8]context.setStrategy(sortingStrategies.mergeSort);
console.log(context.sort(arr)); // 输出: [8, 5, 4, 2, 1]
在上述示例中,sortingStrategies
是一个包含不同排序策略的对象,其中 quickSort
和 mergeSort
是两种不同的排序算法。
SortContext
是排序上下文对象,它接收一个排序策略作为参数,并提供 setStrategy
方法来动态更改当前的排序策略。sort
方法使用当前的排序策略对给定的数组进行排序。
通过创建 SortContext
实例并设置不同的排序策略,我们可以根据需要选择特定的排序算法对数组进行排序。这样,我们可以在运行时根据需求灵活地切换算法,而不需要在每个地方都修改排序逻辑。
策略模式使得应用程序更具可扩展性和灵活性,因为我们可以轻松添加新的策略或修改现有的策略,而无需修改已有的代码。同时,它还能提高代码的可读性和可维护性,使算法选择与实际执行逻辑分离开来。
相关文章:
前端设计模式和设计原则之设计模式
作为前端开发,在code时,或多或少地都会践行设计模式,但是你清楚自己用到的是何种设计模式吗? 为什么前端开发一定要懂设计模式呢? code时不遵从设计模式,又能怎样呢? 上面的问题可以留作思考…...
提高在速卖通产品上的曝光率——自养号测评优势全面解析!
速卖通是国际贸易的一个平台,是国内外企业之间的一个桥梁。在速卖通中,如果要让产品得到更好地推广,就必须让产品得到更多的消费者认可。而产品的认可度除了品质保障和售后服务之外,评测也是非常重要的环节。 对于速卖通店铺销量…...
指针进阶(二)
指针进阶 5.函数指针6. 函数指针数组7. 指向函数指针数组的指针8. 回调函数案例:使用回调函数,模拟实现qsort(采用冒泡的方式)。案例:测试qsort排序结构体数据 5.函数指针 补: &函数名就是函数的地址 …...
【HCIE】03.BGP高级特性
每一条BGP路由都可以携带多个路径属性,针对其属性也有特有的路由匹配工具,包括:AS Path Filter和Community Filter。 import方向的属性,出现在如策略里面,加入到BGP路由表中,再传给路由表里,出去…...
单个处理数据祖籍列表层级关系
CREATE DEFINERroot% FUNCTION sys_organization_getAncestorsNames(deptId varchar(36)) RETURNS varchar(1000) CHARSET utf8DETERMINISTIC BEGINDECLARE parentDeptId varchar(36) default ; -- 父部门iddeclare parentDeptName varchar(100) default ; -- 父部门名称decla…...
Maven部署打包多环境(开发、测试、生产)配置教程
Maven打包多环境(开发、测试、生产)配置教程 1、多环境配置的必要性1.1 没有进行多环境配置进行的操作复杂性1.2 不影响运行时配置 2、配置方案2.1 添加profile属性2.1 添加两个插件2.3 主配置文件中添加插值变量 3、效果展示3.1 勾选prod环境3.2 控制台…...
【计算思维题】少儿编程 蓝桥杯青少组计算思维 数学逻辑思维真题详细解析第9套
蓝桥杯青少组计算思维 数学逻辑思维真题详细解析第9套 第十四届蓝桥杯省赛真题 1、要把下面4张图片重新排列成蜗牛的画像,该如何排列这些图片 A、 B、 C、 D、 答案:A 考点分析:主要考查小朋友们的观察能力空...
【Hello Algorithm】贪心算法
本篇博客介绍: 简单介绍下贪心算法 贪心算法 介绍贪心算法最小字典序的字符串拼接最多会议数切棍子的最小成本IPO灯塔问题 介绍贪心算法 贪心算法是一种极具有自然智慧的算法 它会使用以一种局部最功利的标准来做出一个当前看来最好的选择 如果说我们根据局部最优…...
TOP-K问题
目录 问题描述 解法及思想 第一种方式 算法思想 具体实现 第二种方式 算法思想 具体实现 问题描述 Top-K问题是一个十分经典的问题,一般有以下两种方式来描述问题: 在10亿的数字里,找出其中最大的100个数;在一个包含n个整…...
【保姆级从0到1】UE5 蓝图入门教程1:关卡、蓝图入门
20230113 1、新建项目 新建选择 UE 5.1 项目 选择蓝图,项目位置 改变编辑器布局,选择经典布局 2、关卡与蓝图 选择 File -> New Level 准备创建关卡 选择 Basic,点击 Create 进行创建 Ctrl S 保存新建的关卡 关卡蓝图的打开 鼠标右键&…...
【码银送书第六期】《ChatGPT原理与实战:大型语言模型的算法、技术和私有化》
写在前面 2022年11月30日,ChatGPT模型问世后,立刻在全球范围内掀起了轩然大波。无论AI从业者还是非从业者,都在热议ChatGPT极具冲击力的交互体验和惊人的生成内容。这使得广大群众重新认识到人工智能的潜力和价值。对于AI从业者来说…...
redis 报错 Redis protected-mode 配置文件没有真正启动
(error) DENIED Redis is running in protected mode because protected mode is enabled Redis protected-mode 是3.2 之后加入的新特性,在Redis.conf的注释中,我们可以了解到,他的具体作用和启用条件 链接redis 时只能通过本地localhost …...
解决a标签内容中img标签和p标签垂直方向间隔太大的问题
现象如下: 对应的html结构: 解决办法:给a标签设置:display: inline-block和line-height属性。 然后问题解决: 具体原理如下(由chatgpt回答): display: inline-block 可以减少垂直方…...
如何选择靠谱的全景平台?VR全景加盟从哪方面对比?
VR全景行业经过近几年的发展,已经逐渐普及开来,线下各个行业都有实体商家开始引入VR全景去做营销宣传推广了。不少老板也意识到线上线下双渠道的重要性,而VR全景的存在就刚好满足各行各业的需求,从这一点不难看出,VR全…...
CentOS系统环境搭建(十八)——CentOS7安装Docker20.10.12和docker compose v2
centos系统环境搭建专栏🔗点击跳转 CentOS7安装Docker20.10.12和docker compose v2 关于Docker旧版本和docker compose1.0版本的安装可以看这一篇CentOS系统环境搭建(三)——Centos7安装Docker&Docker Compose。 1.卸载旧版本 卸载do…...
NebulaGrap入门介绍和集群安装部署
长风破浪八千里,落日晚霞不回头。 ——大宁。 NebulaGrap——分布式图数据库 官方文档: NebulaGraph Database手册 官方文档 介绍 简介: NebulaGraph 一款开源、分布式图数据库,擅长处理超大规模数据集。 Nebula …...
thinkphp5.0 composer 安装oss提示php版本异常
场景复现: 本地 phpstudy 环境,安装的有7.0到7.3三个版本,首先确认composer已经安装 composer安装阿里云oss的命令为:composer require aliyuncs/oss-sdk-php 运行报错: Problem 1- Root composer.json requires php…...
AList dokcer安装及百度网盘挂载
AList是开源的网盘管理工具。本文介绍如何通过docker安装AList并挂载百度网盘 1、AList安装 1.1、系统安装 通过docker命令进行安装,命令如下: docker run -d --restartalways -v /etc/alist:/opt/alist/data -p 5244:5244 --name"alist" xhofe/alist:…...
whereIn 遇到了最大限制,临时表处理方式
当使用whereIn 遇到了限制,比如whereIn target ID 已经超过了10万级别,但是又没办法join其他库表时,可以使用临时表的方式解决,临时表是以一种会话的方式存在,意味着你断开了mysql 这个临时会话会自动销毁。 为了创建…...
基于SSM的校园快递代取系统设计与实现
末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用JSP技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…...
MySQL事务详细讲解
文章目录 什么是事务:1.事务有哪些特性2.并发事务会引起什么问题3.事务的隔离级别有哪些4.Read View在MVCC中如何工作Read View 有四个重要的字段使用 InnoDB 存储引擎的数据库表,它的聚簇索引记录中都包含下面两个隐藏列: 5.可重复读是怎么工作的6.读提…...
[linux] mmcv-full 安装的时候 Building wheel 卡住
(已解决)FileNotFoundError: [Errno 2] No such file or directory: ‘:/usr/local/cuda-11.8/bin/nvcc‘_鳗小鱼的博客-CSDN博客 安装mmcv一直卡在建车轮_梦想成为大佬的王老八的博客-CSDN博客 pip install -U openmim mim install mmcv...
Python怎么实现更高效的数据结构和算法? - 易智编译EaseEditing
要实现更高效的数据结构和算法,你可以考虑以下几个方面的优化: 选择合适的数据结构: 选择最适合你问题的数据结构至关重要。例如,如果需要频繁插入和删除操作,可能链表比数组更合适。如果需要高效查找操作࿰…...
03-zookeeper节点动态上下线案例
服务器动态上下线监听案例 需求 在分布式系统中,主节点可以有多台,可以动态上下线,任意一台客户端都能实时感知到主节点服务器的上下线。 需求分析 客户端能实时洞察到服务器上下线的变化 基本流程: 1.服务端启动时去注册…...
如何使用TensorFlow完成线性回归
线性回归是一种简单的预测模型,它试图通过线性关系来预测目标变量。在TensorFlow中,我们可以使用tf.GradientTape来跟踪我们的模型参数的梯度,然后用这个信息来优化我们的模型参数。 以下是一个简单的线性回归的例子: pythonimpo…...
@controller和@RestController的区别
//controller和RestController的区别:RestController的返回值就是结果被输出在浏览器 //controller的返回值会到resources的templates下找 返回值".html" 页面 1.controller 简单的来说,当我们的返回值需要跳转大另一个页面时候,我们就会使…...
GeoNet: Unsupervised Learning of Dense Depth, Optical Flow and Camera Pose 论文阅读
论文信息 题目:GeoNet: Unsupervised Learning of Dense Depth, Optical Flow and Camera Pose 作者:Zhichao Yin and Jianping Shi 来源:CVPR 时间:2018 Abstract 我们提出了 GeoNet,这是一种联合无监督学习框架&a…...
蓝桥杯官网填空题(振兴中华)
题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。 小明参加了学校的趣味运动会,其中的一个项目是:跳格子。 地上画着一些格子,每个格子里写一个字,如下所示࿱…...
node基础之七:Mongodb 数据库
下载地址:https://www.mongodb.com/try/download/community v:5.0.20 platform:window package:zip 复制到 c 盘/Programs Files c 盘创建 data/db 文件夹 默认存放数据地址 在 bin 目录下启动数据库 mongod, 客户端连接数据库…...
基于Python和mysql开发的智慧校园答题考试系统(源码+数据库+程序配置说明书+程序使用说明书)
一、项目简介 本项目是一套基于Python和mysql开发的智慧校园答题考试系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Python学习者。 包含:项目源码、项目文档、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都…...
前端做网站都要做哪些/seo排名优化联系13火星软件
Description有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。Input第一行为3个整数,分别表示a,b,n的值第二行至第a1行每行为b个非负整数,表示矩阵中相应位置上的数。每…...
临沂建手机网站公司/上海职业技能培训机构
jdbc statement的说法 1.Statement、PreparedStatement和CallableStatement都是接口(interface)。 2.Statement继承自Wrapper、PreparedStatement继承自Statement、CallableStatement继承自PreparedStatement。 3. Statement接口提供了执行语句和获取结果的基本方法࿱…...
做网站的疑问有哪些/新闻播报最新
如何对PHP程序中的常见漏洞进行攻击(上) 文章属性:翻译 文章来源:httpwww.china4lert.org 文章提交:analysist (analysist_at_china.com) 如何对PHP程序中的常见漏洞进行攻击(上) 原著ÿ…...
程序员做图网站/兰州网站seo优化
原来是 qq 五笔输入法的坑 用上了微软的五笔输入法问题不在。 虽然有点功能上使用不便。...
做购物网站平台/深圳知名网络优化公司
存在即是合理的。 表格的现在还是较为常用的一种标签,但不是用来布局,常见处理、显示表格式数据。创建表格在HTML网页中,要想创建表格,就需要使用表格相关的标签。创建表格的基本语法格式如下:单元格内的文字......在上…...
企业网站要更新文章吗/推广的渠道和方法有哪些
编辑:ll ASEMI代理MC34PF3001A7EP原装现货NXP车规级MC34PF3001A7EP 型号:MC34PF3001A7EP 品牌:NXP /恩智浦 封装:QFN-48 批号:2023 安装类型:表面贴装型 引脚数量:48 类型:集…...