登录  /  注册

也许你需要点实用的-Web前端笔试题

PHP中文网
发布: 2016-08-25 10:20:44
原创
2107人浏览过

之前发的一篇博客里没有附上答案,现在有空整理了下发出来,希望能帮助到正在找工作的你,还是那句话:技术只有自己真正理解了才是自己的东西,共勉。

Web前端笔试题

Html+css

1.WEB标准以及w3c的理解与认识。

标签闭合,标签小写,不乱嵌套:提高搜索机器人的搜索几率;

使用外联的cssjs,结构行为表现的分离:文件下载与页面加载速度更快,内容能被更广泛的设备所访问;

更少的代码和组件:容易维护,改版方便,不需要变动页面内容,提供打印版本而不需要复制内容,提高网站的易用性。

 

2.Xhtmlhtml有什么区别。

Html(超文本标记语言)是标准通用标记语言下的一个应用,也是一种规范,一种标准。

Xhtml(可扩展超文本标记语言)是一种置标语言,表现方式与html类似,不过语法上更加严格,主要不同:

1,所有元素必须被正确嵌套,

2,所有标记必须闭合,

3,标签名,属性名必须小写字母,

4,所有的属性必须用“”括起来,

5,所有非标签一部分的>都必须以编码形式,

6,所有属性必须要有值,

7,注释中不要有--

8,图片必须要有说明文字

 

3.css的引入方式有哪些?link@import的区别是?

四种:内联,内嵌,外链,导入

区别:

1link属于xhtml标签,@import完全是css提供的一种方式,link除了加载css还可以定义rss,定义rel属性等,@import只能加载css

2,加载顺序差别:link引用的css是同时被加载的,@import引用的css会等到页面全部被下载完才会再被加载。

3,兼容性差别,@importcss2.1提出,ie5以上才支持,link没有兼容问题。

4,使用dom控制样式的差别,当用javascript去控制样式的时候,只能使用link@import不是dom能控制的。

5@import可以在css中再次引入其他样式表。

 

4.css选择符有哪些?哪些属性可以继承?优先级如何计算?内联和important哪个优先级高?

标签选择符,类选择符,id选择符

继承的不如指定的,id>class>Tagname

Important优先级高

 

5.前端页面由哪三层构成,分别是什么?作用是什么?

结构层:html

html或者xhtml负责创建,运用标签对网页内容的含义作出描述。

表示层:css

css负责创建,对如何显示有关内容做出回答。

行为层:javascript

javascript负责创建,负责回答应该如何对事件作出反应。

 

6.css的基本语句构成是?

选择器,属性,属性值

 

7.你曾经在哪些浏览器测试过兼容?这些浏览器的内核分别是什么?

Ieie内核),火狐(Gecko),谷歌(webkit),operapresto

 

8.也许你需要点实用的-Web前端笔试题标签上titlealt属性的区别是什么?

Alt是在你的图片因为某种原因不能加载的时候在页面显示的提示信息,它会直接输出在原本加载图片的地方,title是在鼠标悬停在图片上的显示的小提示,鼠标离开就没了,绝大数html标签都支持title

 

9.写出几种IE6 BUG的解决方法

1.双边距BUG float引起的  使用display

2.3像素问题 使用float引起的 使用dislpay:inline -3px  

3.超链接hover 点击后失效  使用正确的书写顺序 link visited hover active

4.Ie z-index问题 给父级添加position:relative

5.Png 透明 使用js代码 改

6.Min-height 最小高度 !Important 解决’

7.select ie6下遮盖 使用iframe嵌套

8.为什么没有办法定义1px左右的宽度容器(IE6默认的行高造成的,使用over:hidden,zoom:0.08 line-height:1px

 

10.描述css reset的作用和用途。

Css reset重置浏览器的默认css样式,浏览器种类不同,默认样式不一样,通过使用css reset重置,让他们统一,方便开发。

 

11.你如何对网站的文件和资源进行优化?期待的解决方案包括:

1,尽可能减少http请求数(文件合并)

2,使用CDN(内容分发网络)

3,添加Expire/Cache-Control

4,启用Gzip压缩

5css放在页面最上面

6scrip放在页面最下面

7,避免在css中使用Expressions

8,把jscss放在外部文件中

9,减少dns查询

10,压缩javascriptcss

11,避免重定向

12,移除重复脚本

13,配置实体标签

14,使用ajax缓存

 

12.什么是语义化的html

根据内容的结构化(内容语义化),选择合式的标签(代码语义化),便于开发者的阅读和写出更加优雅的代码的同时让浏览器的爬虫和机器更好地解析。

 

13.清除浮动有几种方式?各自的优缺点是?

1,父级定义height(优点:代码少,简单易掌握;缺点:只适合固定高度元素,无法高度自适应)

2,结尾处使用空标签清除浮动:Clear:both(优点:理论上能清除所有标签的浮动,简单代码少浏览器支持好;缺点:增加了无意义的标签)

3,父级定义伪类afterzoom(优点:浏览器支持好;缺点:代码多,两句代码结合使用才能让主流浏览器都支持)

4,父级定义overflow:hidden(优点:代码少,简单,浏览器支持好;缺点:必须定义width或者zoom,同时不能定义height,不能和position配合使用)

5,父级定义overflow:auto(优点:代码少,简单,浏览器支持好;缺点:必须定义width或者zoom,同时不能定义height,内部元素高度超过父级会出现滚动条)

还有,父级一起浮动,父级定义display:table,结尾加brclearboth

 

14.浏览器标准模式和怪异模式之间的区别是什么?

所谓的标准模式是指,浏览器按W3C标准解析执行代码;怪异模式则是使用浏览器自己的方式解析执行代码,因为不同浏览器解析执行的方式不一样,所以我们称之为怪异模式。浏览器解析时到底使用标准模式还是怪异模式,与你网页中的DTD声明直接相关,DTD声明定义了标准文档的类型(标准模式解析)文档类型,会使浏览器使用相应的方式加载网页并显示,忽略DTD声明,将使网页进入怪异模式(quirks mode)

标准模式中

IE6不认识!important声明,IE7IE8FirefoxChrome等浏览器认识;而在怪异模式中,IE6/7/8都不认识!important声明

 

15.解释下 CSS sprites,以及你要如何在页面或网站中使用它

是一种网页图片应用处理方式。它允许你将一个页面涉及到的所有零星图片都包含到一张大图中去,这样一来,当访问该页面时,载入的图片就不会像以前那样一幅一幅地慢慢显示出来了。

页面icon很多的情况下使用合适。

 

16.讨论CSS hacks,条件引用或者其他?

各个浏览器都认识,这里给firefox用;

 \9所有的ie浏览器可识别;

  \0 是留给ie8

 + + ie7定了;

 _ _专门留给神奇的ie6

 :root #test { } :root是给ie9的,

 @media all and (min-width:0px){ #test {} } 这个是老是跟ie抢着认\0的神奇的opera,必须加个\0,不然firefoxchromesafari也都认识。。。

 @media screen and (-webkit-min-device-pixel-ratio:0){ #test {} }最后这个是浏览器新贵chromesafari的。

 

这种注释的方式只有IE浏览器支持,其他浏览器只会把它当做html注释,不起任何作用。一般使用JavaScript或者服务器端程序判断User Agent

 

17.解释下浏览器是如何判断元素是否匹配某个 CSS 选择器?

从后往前判断。浏览器先产生一个元素集合,这个集合往往由最后一个部分的索引产生(如果没有索引就是所有元素的集合)。然后向上匹配,如果不符合上一个部分,就把元素从集合中删除,直到真个选择器都匹配完,还在集合中的元素就匹配这个选择器了。

 

18.你能描述一下渐进增强和优雅降级之间的不同吗?

渐进增强 progressive enhancement:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。

优雅降级 graceful degradation:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。

区别:优雅降级是从复杂的现状开始,并试图减少用户体验的供给,而渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要。降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带。

 

19.CSS字母大写?

text-transform 值:
Capitalize 英文拼音的首字母大写
Uppercase 英文拼音字母全大写
Lowercase 英文拼音字母全小写

 

20.CSS选择器都有哪些

  • 派生选择器(用HTML标签申明)

  • id选择器(用DOM的ID申明)

  • 类选择器(用一个样式类名申明)

  • 属性选择器(用DOM的属性申明,属于CSS2,IE6不支持,不常用,不知道就算了)

除了前3种基本选择器,还有一些扩展选择器,包括

  • 后代选择器(利用空格间隔,比如p .a{  })

  • 群组选择器(利用逗号间隔,比如p,p,#a{  })

 

21.超链接访问过后hover样式就不出现的问题是什么?如何解决?

答案:被点击访问过的超链接样式不在具有hover和active了,解决方法是改变CSS属性的排列顺序: L-V-H-A(link,visited,hover,active)

 

22.浏览器还有默认的天生inline-block元素(拥有内在尺寸,可设置高宽,但不会自动换行),有哪些?

答案:也许你需要点实用的-Web前端笔试题

 

23.pxem的区别

PX:

PX实际上就是像素,用PX设置字体大小时,比较稳定和精确。但是这种方法存在一个问题,当用户在浏览器中浏览我们制作的Web页面时,如果改变了浏览器的缩放,这时会使用我们的Web页面布局被打破。这样对于那些关心自己网站可用性的用户来说,就是一个大问题了。因此,这时就提出了使用“em”来定义Web页面的字体。EM:

EM就是根据基准来缩放字体的大小。EM实质是一个相对值,而非具体的数值。这种技术需要一个参考点,一般都是以

另外,em是相对于父元素的属性而计算的,如果想计算px和em之间的换算,这个网站不错,输入数据就可以px和em相互计算。狠击这里:px和em换算

Rem:

EM是相对于其父元素来设置字体大小的,这样就会存在一个问题,进行任何元素设置,都有可能需要知道他父元素的大小。而Rem是相对于根元素

浏览器的兼容性

除了IE6-IE8r,其它的浏览器都支持em和rem属性,px是所有浏览器都支持。

因此为了浏览器的兼容性,可“px”和“rem”一起使用,用"px"来实现IE6-8下的效果,然后使用“Rem”来实现代浏览器的效果。

 

24.透明度

html{

filter:alpha(opacity=50);  /* ie 有效*/

-moz-opacity:0.5; /* Firefox  有效*/

opacity: 0.5; /* 通用,其他浏览器  有效*/

 }

 

Javascript

1.javascripttypeof返回哪些数据类型?

Objectnumberfunctionbooleanundefined

 

2.例举3种强制类型转换和2种隐式类型转换。

强制Number(),String(),Boolean(),Object();

隐式 + - ==  if   while  for in  alert

 

3.Split()join()的区别。

Join() 函数获取一批字符串,然后用分隔符字符串将它们联接起来,从而返回一个字符串。

Split() 函数获取一个字符串,然后在分隔符处将其断开,从而返回一批字符串。

split,是把一串字符(根据某个分隔符)分成若干个元素存放在一个数组里。而Join是把数组中的字符串连成一个长串,可以大体上认为是split的逆操作。

 

4.事件绑定和普通事件有什么区别?

普通添加事件的方法不支持添加多个事件,最下面的事件会覆盖上面的,而事件绑定(addEventListener)方式添加事件可以添加多个。

 

5.数组方法pop() push() unshift() shift()

Push()尾部添加 pop()尾部删除

Unshift()头部添加  shift()头部删除

 

6.Iedom事件流的区别?

1.执行顺序不一样

2.参数不一样

3.事件加不加on

4.this指向问题

 

7.Ie和标准下有哪些兼容性的写法?

Var ev = ev || window.event

document.documentElement.clientWidth || document.body.clientWidth

Var target = ev.srcElement||ev.target

 

8.Ajaxgetpost方式的区别?

1、使用Get请求时,参数在URL中显示,而使用Post方式是放在虚拟载体里面,不会显示出来。

2、 对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。两种方式的参数都可以用Request来获得。

3get传送的数据量较小,不能大于2KBpost传送的数据量较大,一般被默认为不受限制。但理论上,因服务器的不同而异.

4get安全性非常低,post安全性较高。

5get请求需注意缓存问题,post请求不需担心这个问题。

6post请求必须设置Content-Type值为application/x-form-www-urlencoded 

7、发送请求时,因为get请求的参数都在url,所以send函数发送的参数为null,post请求在使用send方法时,却需赋予其参数

 

9.callapply的区别?

call方法:

语法:call(thisObjObject)

定义:调用一个对象的一个方法,以另一个对象替换当前对象。

说明:

call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。

如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj

apply方法:

语法:apply(thisObj[argArray])

定义:应用某一对象的一个方法,用另一个对象替换当前对象。

说明:

如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError

如果没有提供 argArray thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。

 

10.Ajax请求时,如何解析json数据?

使用eval parse 鉴于安全性考虑 使用parse更靠谱

 

11.什么是javascript的本地对象,内置对象和宿主对象?

本地对象:独立于宿主环境的ECMAScript实现提供的对象。它们包括:ObjectFunctionArrayStringBooleanNumberDateRegExpErrorEvalErrorRangeErrorReferenceError SyntaxErroTypeError  URIError 可以实例化。

内置对象 GlobalMath :由ECMASscript实现提供的、独立于宿主环境的所有对象不可以实例化。

宿主对象:所有的非本地对象都是宿主对象即由ECMAscript实现的宿主环境提供的对象。所有BOMDOM对象都是宿主对象,document,window 等。

 

12.Document loaddocument ready的区别?

页面加载完成有两种事件,一是ready,表示文档结构已经加载完成(不包含图片等非文字媒体文件),二是onload,指示页面包含图片等文件在内的所有元素都加载完成。

 

13.编写一个数组去重的方法。

1.创建一个新的数组存放结果

2.创建一个空对象

3.for循环时,每次取出一个元素与对象进行对比,如果这个元素不重复,则把它存放到结果数组中,同时把这个元素的内容作为对象的一个属性,并赋值为1,存入到第2步建立的对象中。

var s = [0, 2, 3, 4, 4, 0, 2, 'tt', 0, 0]; //测试数组
for (var i = 0, o = {}, tmp = [], count = 0, l = s.length; i < l; i++) {
    if (o[s[i]]) {
        count++;//重复+1
    } else {
        o[s[i]] = 1;//不重复设置属性
        tmp.push(s[i])//加入新数组
}}
alert(count);alert(tmp)
登录后复制

14.事件委托。

利用冒泡的原理,把事件加到父级上,触发执行效果。使用事件委托技术能让你避免对特定的每个节点添加事件监听器;相反,事件监听器是被添加到它们的父元素上。事件监听器会分析从子元素冒泡上来的事件,找到是哪个子元素的事件。

15.作用域链。

当代码在一个环境中执行时,会创建变量对象的的一个作用域链(scope chain)。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是一个函数,则将其活动对象作为变量对象。

每一个函数都有自己的执行环境,当执行流进一个函数时,函数环境就会被推入一个环境栈中,而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境,这个栈也就是作用域链。

当执行函数时,将创建函数的执行环境(调用对象),并将该对象置于链表开头,然后将父级函数的调用对象链接在之后,最后是全局对象。

16.闭包。

闭包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。闭包可以用在许多地方。它的最大用处有两个,一个是读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

17.如何阻止事件冒泡和默认事件。

//如果提供了事件对象,则这是一个非IE浏览器 
if  ( e  &&  e.stopPropagation )  { 
  e.stopPropagation();   //因此它支持W3C的stopPropagation()方法
} else {
  window.event.cancelBubble  =  true;  //否则,我们需要使用IE的方式来取消事件冒泡  
  return  false; 
}
//如果提供了事件对象,则这是一个非IE浏览器 
if  ( e  &&  e.preventDefault ) {
  e.preventDefault();  //阻止默认浏览器动作(W3C)  
}  else  { 
  window.event.returnValue  =  false;  //IE中阻止函数器默认动作的方式
  return  false;
}
登录后复制

18.javascript的同源策略。

一段脚本只能读取来自于同一来源的窗口和文档的属性,这里的同一来源指的是主机名、协议和端口号的组合

19.JS排序算法。

var sort = {
 debug: function(str) {
   if (window.console && window.console.log) {
   console.log(str);
   }
 },
 swap: function(arr, index1, index2) { //数组数据交换
  var temp = arr[index1];
  arr[index1] = arr[index2];
  arr[index2] = temp;
 },
 bubbleSort: function(arr) { //冒泡排序
  this.debug("冒泡排序before:" + arr);
  var len = arr.length;
   for (var outer = 0; outer < len - 1; outer++) { //比较的轮数
    for (var inner = 0; inner < len - outer - 1; inner++) { //每轮比较的次数
     if (arr[inner] > arr[inner + 1]) {
      this.swap(arr, inner, inner + 1)
     }
    }
    this.debug("第" + (outer + 1) + "轮后:" + arr);
   }
   this.debug("冒泡排序after:" + arr);
  },
 selectionSort: function(arr) { //选择排序
  this.debug("选择排序before:" + arr);
  var min, len = arr.length;
  for (var outer = 0; outer < len - 1; outer++) {
   min = outer;
   // 比较最小项目和第outer项之后的剩余数组项, 以寻找更小项
   for (var inner = outer + 1; inner < len; inner++) {
    if (arr[inner] < arr[min]) {
     min = inner;
     this.debug("min--" + min);
    }
   }
   this.swap(arr, outer, min);
   this.debug("第" + (outer + 1) + "轮后:" + arr);
  }
  this.debug("选择排序after:" + arr);
 },
 insertionSort: function(arr) { //插入排序
  this.debug("插入排序before:" + arr);
  var temp, inner, len = arr.length;
  for (var outer = 1; outer < len; outer++) {
   temp = arr[outer];
   inner = outer;
   while (inner > 0 && arr[inner - 1] >= temp) {
    arr[inner] = arr[inner - 1];
    --inner;
   }
   arr[inner] = temp;
  }
  this.debug("插入排序after:" + arr);
 },
 shellSort: function(arr) { //希尔排序
  this.debug("希尔排序before:" + arr);
  var gaps = [5, 3, 1],
  temp;
  for (var g = 0; g < gaps.length; g++) {
   for (var i = gaps[g]; i < arr.length; i++) {
    temp = arr[i];
    for (var j = i; j >= gaps[g] && arr[j - gaps[g]] > temp; j -= gaps[g]) {
     arr[j] = arr[j - gaps[g]];
    }
    arr[j] = temp;
   }
  }
  this.debug("希尔排序after:" + arr);
 },
 shellSortDynamic: function(arr) { //动态计算间隔序列的希尔排序
 this.debug("动态计算间隔序列的希尔排序before:" + arr);
 var N = arr.length,
 h = 1;
 while (h < N / 3) {
  h = 3 * h + 1;
 }
 while (h >= 1) {
  for (var i = h; i < N; i++) {
   for (var j = i; j >= h && arr[j] < arr[j - h]; j -= h) {
    this.swap(arr, j, j - h);
   }
  }
  h = (h - 1) / 3;
 }
 this.debug("动态计算间隔序列的希尔排序after:" + arr);
},
mergeSort: function(arr) { //归并排序
 this.debug("归并排序before:" + arr);
 var len = arr.length,
 step = 1,
 left,
 right;
 var mergeArray = function(arr, startLeft, stopLeft, startRight, stopRight) {
  var rightArr = new Array(stopRight - startRight + 1),
  leftArr = new Array(stopLeft - startLeft + 1),
  k = startRight,
  m = 0,
  n = 0;
  for (var i = 0; i < (rightArr.length - 1); ++i) {
   rightArr[i] = arr[k];
   ++k;
  }
  k = startLeft;
  for (var i = 0; i < (leftArr.length - 1); ++i) {
   leftArr[i] = arr[k];
   ++k;
  }
  rightArr[rightArr.length - 1] = Infinity; //哨兵值
  leftArr[leftArr.length - 1] = Infinity; //哨兵值
  for (var k = startLeft; k < stopRight; ++k) {
   if (leftArr[m] <= rightArr[n]) {
    arr[k] = leftArr[m];
    m++;
   } else {
    arr[k] = rightArr[n];
    n++
   }
  }
 }
 if (len < 2) {
  return;
 }
 while (step < len) {
 left = 0;
 right = step;
 while (right + step <= len) {
  mergeArray(arr, left, left + step, right, right + step);
  left = right + step;
  right = left + step;
 }
 if (right < len) {
  mergeArray(arr, left, left + step, right, len);
 }
 step *= 2;
 }
this.debug("归并排序after:" + arr);
},
quickSort: function(arr) { //快速排序
 this.debug("快速排序before:" + arr);
 var _quickSort = function(arr) {
 var len = arr.length,
 lesser = [],
 greater = [],
 pivot,
 meCall = arguments.callee;
 if (len == 0) {
  return [];
 }
 pivot = arr[0];
 for (var i = 1; i < len; i++) {
  if (arr[i] < pivot) {
   lesser.push(arr[i])
  } else {
   greater.push(arr[i])
  }
 }
 return meCall(lesser).concat(pivot, meCall(greater));
}
this.debug("快速排序after:" + _quickSort(arr));
return _quickSort(arr);
}
}
var search = {
linearSearch: function(arr, data) { //线性查找
for (var i = 0; i < arr.length; i++) {
if (arr[i] == data) {
return i;
}
}
return -1;
},
binarySearch: function(arr, data) { //二分查找 适用于已排好序的线性结构
var lowerBound = 0,
upperBound = arr.length - 1,
mid;
while (lowerBound <= upperBound) {
mid = Math.floor((lowerBound + upperBound) / 2);
if (arr[mid] < data) {
lowerBound = mid + 1;
} else if (arr[mid] > data) {
upperBound = mid - 1;
} else {
return mid;
}
    return -1;
}
}
}
var tempArr = [3, 6, 4, 2, 11, 10, 5];
//sort.bubbleSort(tempArr);
//sort.selectionSort(tempArr);
//sort.insertionSort(tempArr);
//sort.shellSort(tempArr);
//sort.shellSortDynamic(tempArr);
//sort.mergeSort(tempArr);
//sort.quickSort(tempArr);
登录后复制




以上就是也许你需要点实用的-Web前端笔试题的内容,更多相关内容请关注PHP中文网(www.php.cn)!


智能AI问答
PHP中文网智能助手能迅速回答你的编程问题,提供实时的代码和解决方案,帮助你解决各种难题。不仅如此,它还能提供编程资源和学习指导,帮助你快速提升编程技能。无论你是初学者还是专业人士,AI智能助手都能成为你的可靠助手,助力你在编程领域取得更大的成就。
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
最新问题
关于CSS思维导图的课件在哪? 课件
凡人来自于2024-04-16 10:10:18
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

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