bbking

bbking 查看完整档案

武汉编辑  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

bbking 关注了问题 · 10月23日

解决flex-shrink: 0;看起来好像没起作用?请问这是为什么?

HTML

<div class="app">
    <div class="wrap">11</div>
</div>

CSS

html,body{
    margin: 0;
    padding: 0;
}
.app{
    width: 100vw;
    display: flex;
    justify-content: center;
}
.wrap{
    width: 1440px;
    height: 900px;
    flex-shrink: 0;
}

如上代码,当给app设置display:flex之后,正常情况如图所示:
image.png

但是当我把浏览器缩小到1440以下时,检查元素显示wrap的宽度仍然是1440,但是左上角的11却看不见了,请问这是为什么?
image.png

关注 2 回答 2

bbking 回答了问题 · 10月22日

解决flex-shrink: 0;看起来好像没起作用?请问这是为什么?

我知道了,正确做法应该是,当父容器用了display:flex; justify-content:center;并且子容器有固定宽度时,那么应该给父容器加上min-width:子容器的宽;,这个问题就解决了。

关注 2 回答 2

bbking 提出了问题 · 10月22日

解决flex-shrink: 0;看起来好像没起作用?请问这是为什么?

HTML

<div class="app">
    <div class="wrap">11</div>
</div>

CSS

html,body{
    margin: 0;
    padding: 0;
}
.app{
    width: 100vw;
    display: flex;
    justify-content: center;
}
.wrap{
    width: 1440px;
    height: 900px;
    flex-shrink: 0;
}

如上代码,当给app设置display:flex之后,正常情况如图所示:
image.png

但是当我把浏览器缩小到1440以下时,检查元素显示wrap的宽度仍然是1440,但是左上角的11却看不见了,请问这是为什么?
image.png

关注 2 回答 2

bbking 回答了问题 · 10月16日

解决vue中使用 tinymce 只有第一次打开页面初始化有效

在关闭页面或者弹窗的时候调用 tinymce.remove('#tinyDom')

关注 5 回答 4

bbking 提出了问题 · 9月27日

解决关于js递归问题?

最近刚接触到递归,然后遇到了下面这个问题,不知道怎么写下去了

var array = [
    1,
    [3,4,[2,3,[2,3]]],
    [2,[4]]
]

array结构如上,但层级不定

需求,将array中所有的3置为0

然后我的代码如下,else里面不知道怎么写了,该如何获取当前值的路径呢,请问下各位这里该怎么处理?

function setArr(arr) {
    if (typeof arr == 'object') {
        arr.forEach((item, index) => {
            return setArr(item)
        })
    } else {
        // ?
    }
}

setArr(array)

关注 4 回答 4

bbking 赞了回答 · 9月25日

Vue-router-3.0.1 使用router.addRoutes()设置动态路由,动态路由对应页面直接刷新后无效

// 路由跳转前,登录状态判断
router.beforeEach((to, from, next) => {
  let userUid = sessionStorage.getItem('userUuid')
  // sessionStorage中userUid不为空,说明用户已登录
  if (userUid) {
    // vue中state.userInfo.uid为空,说明用户刷新了页面
    if (!store.state.userInfo.uid) {
      store.commit('SET_USER_INFO', userUid)              // 重新提交mutation,设置state.userInfo.uid
      router.addRoutes(store.getters.userDynamicRouters)  // 添加动态路由
    }
    next()  //***此处改为next({...to})***
  } else {
    // 没有登录信息,说明没有登录
    if (to.path.indexOf('/MyCenter') !== -1) {
      next('/Home')
    } else {
      next()
    }
  }
});

上述代码中第一个if中的next()改为next({...to})

关注 3 回答 3

bbking 赞了文章 · 9月21日

Vue 中 强制组件重新渲染的正确方法

作者:Michael Thiessen
译者:前端小智
来源:hackernoon
点赞再看,养成习惯

本文 GitHubhttps://github.com/qq44924588... 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料。欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西。


有时候,依赖 Vue 响应方式来更新数据是不够的,相反,我们需要手动重新渲染组件来更新数据。或者,我们可能只想抛开当前的DOM,重新开始。那么,如何让Vue以正确的方式重新呈现组件呢?

强制 Vue 重新渲染组件的最佳方法是在组件上设置:key。 当我们需要重新渲染组件时,只需更 key 的值,Vue 就会重新渲染组件。

这是一个非常简单的解决方案。

当然,你可能会对其他方式会更感兴趣:

  • 简单粗暴的方式:重新加载整个页面
  • 不妥的方式:使用 v-if
  • 较好的方法:使用Vue的内置forceUpdate方法
  • 最好的方法:在组件上进行 key 更改

简单粗暴的方式:重新加载整个页面

这相当于每次你想关闭应用程序时都要重新启动你的电脑。

图片描述

这种方式或许有用,但这是一个非常糟糕的解决方案,不要这样做,我们来看看更好的方法。

不妥的方式:使用 v-if

v-if指令,该指令仅在组件为true时才渲染。 如果为false,则该组件在DOM中不存在。

来看看,v-if 是怎么工作的,在template中,添加v-if指令:

<template>
  <my-component v-if="renderComponent" />
</template>

script 中,使用nextTick的方法

<script>
  export default {
    data() {
      return {
        renderComponent: true,
      };
    },
    methods: {
      forceRerender() {
        // 从 DOM 中删除 my-component 组件
        this.renderComponent = false;
        
        this.$nextTick(() => {
          // 在 DOM 中添加 my-component 组件
          this.renderComponent = true;
        });
      }
    }
  };
</script>

上面的过程大致如下:

  1. 刚开始 renderComponent设置为true,因此渲染 my-component 组件
  2. 当我们调用forceRerender时,我们立即将renderComponent设置为false
  3. 我们停止渲染my-component,因为v-if指令现在计算结果为false
  4. nextTick方法中将renderComponent设置回true
  5. v-if指令的计算结果为true时,再次渲染my-component

在这个过程中,有两个部分比较重要

首先,我们必须等到nextTick,否则我们不会看到任何变化。

Vue中,一个 tick 是一个DOM更新周期。Vue将收集在同一 tick 中进行的所有更新,在 tick 结束时,它将根据这些更新来渲染 DOM 中的内容。如果我们不等到next tick,我们对renderComponent的更新就会自动取消,什么也不会改变。

其次,当我们第二次渲染时,Vue将创建一个全新的组件。 Vue 将销毁第一个,并创建一个新的,这意味着我们的新my-component将像正常情况一样经历其所有生命周期-createdmounted等。

另外,nextTick 可以与 promise 一起使用:

forceRerender() {
  // 从 DOM 中删除 my-component 组件
  this.renderComponent = false;

  this.$nextTick().then(() => {
    this.renderComponent = true;
  });
}

不过,这并不是一个很好的解决方案,所以,让我们做 Vue 想让我们做的

较好的方法:forceUpdate 方法

这是解决这个问题的两种最佳方法之一,这两种方法都得到了Vue的官方支持。

通常情况下,Vue 会通过更新视图来响应依赖项中的更改。然而,当我们调用forceUpdate时,也可以强制执行更新,即使所有依赖项实际上都没有改变。

下面是大多数人使用这种方法时所犯的最大错误。

如果 Vue 在事情发生变化时自动更新,为什么我们需要强制更新呢?

原因是有时候 Vue 的响应系统会让人感到困惑,我们认为Vue会对某个属性或变量的变化做出响应,但实际上并不是这样。在某些情况下,Vue的响应系统根本检测不到任何变化。

所以就像上一个方法,如果你需要这个来重新渲染你的组件,可能有一个更好的方法。

有两种不同的方法可以在组件实例本身和全局调用forceUpdate

// 全局
import Vue from 'vue';
Vue.forceUpdate();

// 使用组件实例
export default {
  methods: {
    methodThatForcesUpdate() {
      // ...
      this.$forceUpdate();
      // ...
    }
  }
}

重要提示:这不会更新任何计算属性,调用forceUpdate仅仅强制重新渲染视图。

最好的方法:在组件上进行 key 更改

在许多情况下,我们需要重新渲染组件。

要正确地做到这一点,我们将提供一个key属性,以便 Vue 知道特定的组件与特定的数据片段相关联。如果key保持不变,则不会更改组件,但是如果key发生更改,Vue 就会知道应该删除旧组件并创建新组件。

正是我们需要的!

但是首先,我们需要绕一小段路来理解为什么在Vue中使用key

为什么我们需要在 Vue 中使用 key

一旦你理解了这一点,那么这是了解如何以正确方式强制重新渲染的很小的一步。

假设我们要渲染具有以下一项或多项内容的组件列表:

  • 有本地的状态
  • 某种初始化过程,通常在createdmounted钩子中
  • 通过jQuery或普通api进行无响应的DOM操作

如果你对该列表进行排序或以任何其他方式对其进行更新,则需要重新渲染列表的某些部分。 但是,不会希望重新渲染列表中的所有内容,而只是重新渲染已更改的内容。

为了帮助 Vue 跟踪已更改和未更改的内容,我们提供了一个key属性。 在这里使用数组的索引,因为索引没有绑定到列表中的特定对象。

const people = [
  { name: 'Evan', age: 34 },
  { name: 'Sarah', age: 98 },
  { name: 'James', age: 45 },
];

如果我们使用索引将其渲染出来,则会得到以下结果:

<ul>
  <li v-for="(person, index) in people" :key="index">
    {{ person.name }} - {{ index }}
  </li>
</ul>

// Outputs
Evan - 0
Sarah - 1
James - 2

如果删除Sarah,得到:

Evan - 0
James - 1

James关联的索引被更改,即使James仍然是JamesJames会被重新渲染,这并不是我们希望的。

所以这里,我们可以使用唯一的 id 来作为 key

const people = [
  { id: 'this-is-an-id', name: 'Evan', age: 34 },
  { id: 'unique-id', name: 'Sarah', age: 98 },
  { id: 'another-unique-id', name: 'James', age: 45 },
];

<ul>
  <li v-for="person in people" :key="person.id">
    {{ person.name }} - {{ person.id }}
  </li>
</ul>

在我们从列表中删除Sarah之前,Vue删除了SarahJames的组件,然后为James创建了一个新组件。现在,Vue知道它可以为EvanJames保留这两个组件,它所要做的就是删除Sarah的。

如果我们向列表中添加一个person,Vue 还知道可以保留所有现有的组件,并且只需要创建一个新组件并将其插入正确的位置。这是非常有用的,当我们有更复杂的组件,它们有自己的状态,有初始化逻辑,或者做任何类型的DOM操作时,这对我们很有帮助。

所以接下来看看,如果使用最好的方法来重新渲染组件。

更改 key 以强制重新渲染组件

最后,这是强制Vue重新渲染组件的最佳方法(我认为)。

我们可以采用这种将key分配给子组件的策略,但是每次想重新渲染组件时,只需更新该key即可。

这是一个非常基本的方法

<template>
  <component-to-re-render :key="componentKey" />
</template>


export default {
  data() {
    return {
      componentKey: 0,
    };
  },
  methods: {
    forceRerender() {
      this.componentKey += 1;  
    }
  }
}

每次forceRerender被调用时,我们的componentKey都会改变。当这种情况发生时,Vue将知道它必须销毁组件并创建一个新组件。我们得到的是一个子组件,它将重新初始化自身并“重置”其状态。

如果确实需要重新渲染某些内容,请选择key更改方法而不是其他方法。


代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

原文:https://hackernoon.com/the-co...


交流

干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。

https://github.com/qq44924588...

我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!

关注公众号,后台回复福利,即可看到福利,你懂的。

clipboard.png

查看原文

赞 23 收藏 19 评论 0

bbking 收藏了文章 · 8月21日

常见 HTTP/FTP/WebSocket 错误代码大全

常见HTTP/FTP/WebSocket错误代码大全
https://github.com/jaywcjlove...

HTTP

1xx消息

这一类型的状态码,代表请求已被接受,需要继续处理。这类响应是临时响应,只包含状态行和某些可选的响应头信息,并以空行结束。由于HTTP/1.0协议中没有定义任何1xx状态码,所以除非在某些试验条件下,服务器禁止向此类客户端发送1xx响应。 这些状态码代表的响应都是信息性的,标示客户应该采取的其他行动。

  • 100 - 客户端应当继续发送请求

  • 101 - 切换协议

  • 102 - 处理将被继续执行

2xx成功

这一类型的状态码,代表请求已成功被服务器接收、理解、并接受。

  • 200 - (成功)请求已成功,请求所希望的响应头或数据体将随此响应返回。

  • 201 - (已创建)请求成功且服务器已创建了新的资源。。

  • 202 - (已接受)服务器已接受了请求,但尚未对其进行处理。

  • 203 - (非授权信息)服务器已成功处理了请求,但返回了可能来自另一来源的信息。

  • 204 - (无内容)服务器成功处理了请求,但未返回任何内容。

  • 205 - (重置内容)服务器成功处理了请求,但未返回任何内容。

  • 206 - (部分内容)服务器成功处理了部分 GET 请求。

3xx重定向

这类状态码代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的Location域中指明。按照HTTP/1.0版规范的建议,浏览器不应自动访问超过5次的重定向。对重定向一般是由浏览器来控制重定向的次数,重定向会导致客户端不必要的资源消耗

  • 300 - 多重选择,被请求的资源有一系列可供选择的回馈信息。

  • 301 - 永久移除,被请求的资源已永久移动到新位置。

  • 302 - 临时移动,请求的资源现在临时从不同的URI响应请求。

  • 303 - 查看其他位置,对应当前请求的响应可以在另一个URI上被找到,而且客户端应当采用GET的方式访问那个资源。

  • 304 - 未修改。自从上次请求后,请求的网页未被修改过。服务器返回此响应时,不会返回网页内容。

  • 305 - 使用代理,被请求的资源必须通过指定的代理才能被访问。

  • 306 - 临时重定向,在最新版的规范中,306状态码已经不再被使用。

  • 307 - 临时重定向。

4xx客户端错误

这类的状态码代表了客户端看起来可能发生了错误,妨碍了服务器的处理。

  • 400 - 错误的请求。

  • 401 - 访问被拒绝。

  • 402 - 付款要求。

  • 403 - 禁止访问

    • 403.1 - 执行访问被禁止。

    • 403.2 - 读访问被禁止。

    • 403.3 - 写访问被禁止。

    • 403.4 - 要求 SSL。

    • 403.5 - 要求 SSL 128。

    • 403.6 - IP 地址被拒绝。

    • 403.7 - 要求客户端证书。

    • 403.8 - 站点访问被拒绝。

    • 403.9 - 用户数过多。

    • 403.10 - 配置无效。

    • 403.11 - 密码更改。

    • 403.12 - 拒绝访问映射表。

    • 403.13 - 客户端证书被吊销。

    • 403.14 - 拒绝目录列表。

    • 403.15 - 超出客户端访问许可。

    • 403.16 - 客户端证书不受信任或无效。

    • 403.17 - 客户端证书已过期或尚未生效。

    • 403.18 - 在当前的应用程序池中不能执行所请求的 URL。

    • 403.19 - 不能为这个应用程序池中的客户端执行 CGI。

    • 403.20 - Passport 登录失败。

  • 404 - 未找到。

    • 404.0 -(无) – 没有找到文件或目录。

    • 404.1 - 无法在所请求的端口上访问 Web 站点。

    • 404.2 - Web 服务扩展锁定策略阻止本请求。

    • 404.3 - MIME 映射策略阻止本请求。

  • 405 - 用来访问本页面的 HTTP 谓词不被允许(方法不被允许)

  • 406 - 客户端浏览器不接受所请求页面的 MIME 类型。

  • 407 - 要求进行代理身份验证。

  • 408 - 请求超时。

  • 409 - 由于和被请求的资源的当前状态之间存在冲突,请求无法完成。

  • 410 - 被请求的资源在服务器上已经不再可用,而且没有任何已知的转发地址。

  • 411 - 服务器拒绝在没有定义Content-Length头的情况下接受请求。

  • 412 - 前提条件失败。

  • 413 – 请求实体太大。

  • 414 - 请求 URI 太长。

  • 415 – 不支持的媒体类型。

  • 416 – 所请求的范围无法满足。

  • 417 – 执行失败。

  • 418 – 本操作码是在1998年作为IETF的传统愚人节笑话

  • 421 – 从当前客户端所在的IP地址到服务器的连接数超过了服务器许可的最大范围。

  • 422 – 请求格式正确,但是由于含有语义错误,无法响应。

  • 423 – 当前资源被锁定。

  • 424 – 由于之前的某个请求发生的错误,导致当前请求失败。

  • 425 – 无序的集合。

  • 426 – 客户端应当切换到TLS/1.0。

  • 451 – (由IETF在2015核准后新增加)该访问因法律的要求而被拒绝。

5xx服务器错误

这类状态码代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。

  • 500 - 内部服务器错误。

  • 501 - 尚未实施,页眉值指定了未实现的配置。

  • 502 - 错误网关,Web 服务器用作网关或代理服务器时收到了无效响应。

  • 503 - 服务不可用,这个错误代码为 IIS 6.0 所专用。

  • 504 - 网关超时,服务器作为网关或代理,未及时从上游服务器接收请求。

  • 505 - HTTP 版本不受支持,服务器不支持请求中所使用的 HTTP 协议版本。

  • 506 - 服务器没有正确配置。

  • 507 - 存储空间不足。服务器无法存储完成请求所必须的内容。这个状况被认为是临时的。

  • 509 - 带宽超过限制。这不是一个官方的状态码,但是仍被广泛使用。

  • 510 - 没有扩展,获取资源所需要的策略并没有被满足。

FTP

1xx初步

肯定的初步答复,这些状态代码指示一项操作已经成功开始,但客户端希望在继续操作新命令前得到另一个答复。

  • 110 重新启动标记答复。

  • 120 服务已就绪,在 nnn 分钟后开始。

  • 125 数据连接已打开,正在开始传输。

  • 150 文件状态正常,准备打开数据连接。

2xx完成

肯定的完成答复,一项操作已经成功完成。客户端可以执行新命令。

  • 200 命令确定。

  • 202 未执行命令,站点上的命令过多。

  • 211 系统状态,或系统帮助答复。

  • 212 目录状态。

  • 213 文件状态。

  • 214 帮助消息。

  • 215 NAME 系统类型,其中,NAME 是 Assigned Numbers 文档中所列的正式系统名称。

  • 220 服务就绪,可以执行新用户的请求。

  • 221 服务关闭控制连接。如果适当,请注销。

  • 225 数据连接打开,没有进行中的传输。

  • 226 关闭数据连接。请求的文件操作已成功(例如,传输文件或放弃文件)。

  • 227 进入被动模式 (h1,h2,h3,h4,p1,p2)。

  • 230 用户已登录,继续进行。

  • 250 请求的文件操作正确,已完成。

  • 257 已创建“PATHNAME”。

3xx中间

肯定的中间答复,该命令已成功,但服务器需要更多来自客户端的信息以完成对请求的处理。

  • 331 用户名正确,需要密码。

  • 332 需要登录帐户。

  • 350 请求的文件操作正在等待进一步的信息。

4xx瞬态否定

瞬态否定的完成答复,该命令不成功,但错误是暂时的。如果客户端重试命令,可能会执行成功。

  • 421 服务不可用,正在关闭控制连接。如果服务确定它必须关闭,将向任何命令发送这一应答。

  • 425 无法打开数据连接。

  • 426 Connection closed; transfer aborted.

  • 450 未执行请求的文件操作。文件不可用(例如,文件繁忙)。

  • 451 请求的操作异常终止:正在处理本地错误。

  • 452 未执行请求的操作。系统存储空间不够。

5xx永久性否定

永久性否定的完成答复,该命令不成功,错误是永久性的。如果客户端重试命令,将再次出现同样的错误。

  • 500 语法错误,命令无法识别。这可能包括诸如命令行太长之类的错误。

  • 501 在参数中有语法错误。

  • 502 未执行命令。

  • 503 错误的命令序列。

  • 504 未执行该参数的命令。

  • 530 未登录。

  • 532 存储文件需要帐户。

  • 550 未执行请求的操作。文件不可用(例如,未找到文件,没有访问权限)。

  • 551 请求的操作异常终止:未知的页面类型。

  • 552 请求的文件操作异常终止:超出存储分配(对于当前目录或数据集)。

  • 553 未执行请求的操作。不允许的文件名。

6xx受保护

  • 600 Series,Replies regarding confidentiality and integrity

  • 631 Integrity protected reply.

  • 632 Confidentiality and integrity protected reply.

  • 633 Confidentiality protected reply.

WebSockets状态码

WebSockets 的CloseEvent 会在连接关闭时发送给使用 WebSockets 的客户端。它在 WebSocket 对象的 onclose 事件监听器中使用。服务端发送的关闭码,以下为已分配的状态码。

状态码名称描述
0–999-保留段, 未使用。
1000CLOSE_NORMAL正常关闭; 无论为何目的而创建, 该链接都已成功完成任务。
1001CLOSE_GOING_AWAY终端离开, 可能因为服务端错误, 也可能因为浏览器正从打开连接的页面跳转离开。
1002CLOSE_PROTOCOL_ERROR由于协议错误而中断连接。
1003CLOSE_UNSUPPORTED由于接收到不允许的数据类型而断开连接 (如仅接收文本数据的终端接收到了二进制数据)。
1004-保留。 其意义可能会在未来定义。
1005CLOSE_NO_STATUS保留。 表示没有收到预期的状态码。
1006CLOSE_ABNORMAL保留。 用于期望收到状态码时连接非正常关闭 (也就是说, 没有发送关闭帧)。
1007Unsupported Data由于收到了格式不符的数据而断开连接 (如文本消息中包含了非 UTF-8 数据)。
1008Policy Violation由于收到不符合约定的数据而断开连接。 这是一个通用状态码, 用于不适合使用 1003 和 1009 状态码的场景。
1009CLOSE_TOO_LARGE由于收到过大的数据帧而断开连接。
1010Missing Extension客户端期望服务器商定一个或多个拓展, 但服务器没有处理, 因此客户端断开连接。
1011Internal Error客户端由于遇到没有预料的情况阻止其完成请求, 因此服务端断开连接。
1012Service Restart服务器由于重启而断开连接。 [Ref]
1013Try Again Later服务器由于临时原因断开连接, 如服务器过载因此断开一部分客户端连接。 [Ref]
1014-由 WebSocket标准保留以便未来使用。
1015TLS Handshake保留。 表示连接由于无法完成 TLS 握手而关闭 (例如无法验证服务器证书)。
1016–1999-由 WebSocket 标准保留以便未来使用。
2000–2999-由 WebSocket 拓展保留使用。
3000–3999-可以由库或框架使用。 不应由应用使用。 可以在 IANA 注册, 先到先得。
4000–4999-可以由应用使用。

参考资料

查看原文

bbking 提出了问题 · 7月10日

解决容器宽高固定,字数不定,请问如何使字体大小自适应容器大小?

如题:容器宽高固定,字数不定,请问如何使字体大小自适应容器大小?达到下图这样的效果:
image.png
image.png

关注 5 回答 3

bbking 关注了问题 · 6月28日

解决flex布局+overflow后, 右侧边距消失了

css: 
    .flex{
        width: 500px; height: 50px;
        border: 1px solid pink;
        overflow: auto;
        display: flex; align-items: center;
    }
    .flex-child{
        min-width: 25%;
        border: 1px solid violet;
        margin: 0 5px;
        flex: 0 1 25%; display: flex; align-items: center; justify-content: center;
    }
html: 
    <div class="flex">
        <div class="flex-child">1</div>
        <div class="flex-child">2</div>
        <div class="flex-child">3</div>
        <div class="flex-child">4</div>
        <div class="flex-child">5</div>
    </div>

clipboard.png
clipboard.png

关注 4 回答 2

认证与成就

  • 获得 4 次点赞
  • 获得 13 枚徽章 获得 0 枚金徽章, 获得 2 枚银徽章, 获得 11 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2017-06-16
个人主页被 195 人浏览