崮生

崮生 查看完整档案

长沙编辑湖南信息职业技术学院  |  计算机应用技术 编辑浙江芭欧  |  前端 编辑 shenzilong.cn 编辑
编辑

怕什么真理无穷,进一寸一寸的欢喜

个人动态

崮生 发布了文章 · 1月8日

vue 异步数据呈现方案

vue 异步数据呈现方案

demo 地址源码地址

起因

当我领会到 写程序的重点在于处理好输入与输出之后 再来写一个搜索组件的时候我关于 loading 的思考如下

  • 什么时候显示 loading ?

    • 请求发起后还没有到达的这一段时间
  • 怎么控制视图在这段时间内显示 loading ?

    • 使用一个变量来控制
  • 那这个变量属于输入吗?

    • 不算,他是一个输出,这个搜索组件的输入只有一个: searchText
  • 这个输出的相关的 input、 transform 怎么样的?

    • input:searchText -> transform:异步请求 -> output:loading 状态
  • 怎么实现这样的一个 transform?

    • 这个 transform 需要立即的返回状态,没有状态页面上无法确定 loading 怎么显示

      • 想到了 promise to object
    • 这个 transform 需要持续的返回新状态。loading 一开始必然是显示,如果之后不返回新状态就没办法关闭了

      • 想到了 vue 的计算属性
      • 想到了事件机制
    • 这个 transform 还需要返回异步请求的结果。

      • object 中新增一个 data 字段用来放结果,还可以有一个 error 字段
    • 所以这个 transform 可以当 input 改变时返回一个 object 并且在 依据 input 发起的异步请求成功或者结束后修改之前返回的 object

然后就是在 vue 中实现这样的一个思路

应用的代码长啥样

/读书笔记/vue/vue异步数据呈现方案.html

demo 地址源码地址

import { defineComponent, ref } from "vue";
import { usePromiseComputed } from "./lib/vue.composition.api";

export default defineComponent({
  setup(props, ctx) {
    const searchText = ref("");

    const searchResults = usePromiseComputed({
      defaultData: [] as string[],
      getter() {
        return searchApi(searchText.value);
      },
    });

    return { searchText, searchResults };
  },
}); 

这里的 usePromiseComputed 就是之前思考的 transform ,他返回了一个 ref(object) 然后当 searchText 发生变化时会重新执行查询请求 searchApi(searchText.value); , 当查询请求结束的时候他会修改之前返回的 ref(object)

在模板中

<template>
  <input placeholder="请输入你要搜索的关键字" v-model="searchText" />

  <div v-if="searchResults.pending">正在查询中</div>
  <div v-else-if="searchResults.rejected">
    查询失败
    {{ searchResults.error }}
  </div>
  <div v-else-if="searchResults.fulfilled">
    <div v-for="(item, index) in searchResults.data" :key="index">
      {{ item }}
    </div>
  </div>
  
</template> 

在这里可以看出来 usePromiseComputed 返回的结果其中的五个字段,三个状态字段也就是 前文中提到的控制loading的那个变量 两个 结果字段

总结

就上面的代码而言是一个极简 input -> tranform -> out 结构。这里不需要手动的声明一个状态变量,然后在不同的阶段在去修改这个变量,这样的操作封装在了 usePromiseComputed 里面。

关于 usePromiseComputed 的实现可以去这里查看 https://github.com/2234839/vue-demo/blob/master/src/components/promise-loading/lib/vue.composition.api.ts

实际上针对业务还加入了两个可选参数 deps 和 dataMergeFun

利用 deps 可以显式的声明哪些变量变化的时候重新请求

利用 dataMergeFun 可以非常简单的在上面的代码基础上加入请求结果翻页功能

by 崮生 from 崮生 • 一些随笔 🎨,欢迎 赞助本文o")
本文欢迎分享与聚合,全文转载未经授权( 联系我)不许可。
查看原文

赞 0 收藏 0 评论 0

崮生 赞了文章 · 2020-10-28

不为人知的javascript的内部属性

内部属性在我们了解对象原型及环境变量时都有遇到过,可是毕竟看不到摸不着,很难更加深入的了解它的工作流程和作用,最近在chrome当中查看对象结构时,看到了释放出来的一些内部属性,这些以前大概都是概念,那么既然能看到,就让我们来探索一下吧~

[[Scopes]]

此属性储存在函数对象中,我记得从chrome 62开始我就发现这个属性了,具体哪个版本大家可以google,现在我们把它给打印出来看一下.

clipboard.png

clipboard.png

这是一个不访问外部变量的函数,所以Scopes中只储存了Global全局对象。

还记得作用域链吗(如果不记得,请点击这里看前半部分)?
从前往后分别是 [函数自己的变量对象,.., .., Global] 类似于这样依次向后(上)查找这个执行环境所使用到的变量对象。

在上面的文章说过,javascript在开始执行时,会经过两个阶段,预编译->代码执行,在v8中代码执行阶段运行的是机器码,CPU可以直接接收,
可以说,在javascript代码执行前都会经过复杂的代码分割,生成抽象语法树(AST),编译解析与优化等操作,[[Scopes]]正是这其中的产物。下面说
下它形成的流程。

  1. 词法阶段会定义函数所用到的变量,加入到[[Scopes]]内部属性当中,它是一个数组,最后一位永远都是Global全局对象,向前依次是祖先->父级。注意,这时只是在第一个阶段,js引擎并没有执行你的操作。(总之所有的脏活累活都要在第一个阶段完成,以保证js引擎执行的最高效率)
  2. 执行流进入,读取这个执行环境(函数)的[[Scopes]]属性,并把自身的变量对象加入到前端(unshift),形成作用域链,这样从头到尾的变量对象,构成了伟大的作用域。

需要注意的是,并不是所有的父级作用域的变量都进行存储,而只会存储当前函数所使用到的变量。所以我们进行这样的操作是查看不到父级变量的.

  var a = 1;
  function fun(){
      var b = 1;
      const p = ()=>{}
      console.dir(p)
  }
  fun();

clipboard.png

函数p当中并没用使用到父级函数中的变量b,所以[[Scopes]]只有Global对象(注意,因为Global对象永远存在,并且是引用,所以不会出现这种情况),
我认为这也是一种优化手段,可以极大减少内存的使用。

我们换种写法:

var a = 1;
  function fun(){
      var b = 1;
      const p = ()=>{
        var c = 1;
        const f = ()=>{ console.log(b,c) }
        console.dir(f)
      }
      p();
  }
  fun();

clipboard.png

我们引用了父级作用域中的变量,并打印出来,在编译阶段,编译器把他们加入到了[[Scopes]]中。

此属性,我们不可去访问与修改它,目前只能在控制台中点击查看.

[[FunctionLocation]]

这个很容易理解,类似于debugger功能,可以很容易的查找到此函数的代码位置,比如我们以React为例,查看 React.Component函数位置.

clipboard.png

可以看到,key右侧的可点击部分,表示函数在react-dom.min.js第34行,我们点进去查看,晕了,代码被混淆了...

clipboard.png

对于这个属性,我们以后可以大大减少console的使用啦

[[Prototype]]

遵循ECMAScript标准,someObject.[[Prototype]] 符号是用于指向 someObject的原型。从 ECMAScript 6 开始,[[Prototype]]
可以用Object.getPrototypeOf()和Object.setPrototypeOf()访问器来访问。这个等同于 JavaScript 的非标准但许多浏览器实现的属性
__proto__。我们经常使用Object.prototype.toString来判断对象类型,toString就是把当前的这个属性转换成字符串返回出去了.

这个内部属性,表示对象的原型链,类似与[[Scopes]]也是一个数组格式.

   var b = {a:1};
   function o(a){
     this.b = a;
   }
   o.prototype = { c:3; }
   b.__proto__ = new o(2);
   console.log(b.a,b.b,b.c); //1 2 3

此时原型链关系是这样的:

clipboard.png

貌似还有很多内部属性,一时想不起来(如果发现,以后会更新),大家有知道的,可以发表评论。

查看原文

赞 5 收藏 5 评论 0

崮生 赞了文章 · 2020-09-28

mnl.js —— JavaScript 函数仿生命名法

GitHub: https://github.com/YuanSa/mnl.js


你是否为函数参数过多、顺序混乱头疼过?

想解决这个问题,在python中可以为指定参数赋值,在JavaScript中则可以传递参数对象。

本文提出另一种解决方法:仿生命名法 (Mock Natrual Language)。

仿生命名法是一种给函数命名的方法,让你可以用接近自然语言的语法给函数命名。

仿生命名法很简单,即在函数名内部任意位置插入括号。如:

function deleteThe(i)ItemFrom(arr) {
  return arr.splice(i, 1)
}

由于与现有JavaScript语法不兼容,我们需要一个编译器进行转换。

目前的策略是将括号替换为__x__,参数列表依次添加到函数名末尾。
而出于兼容性考虑,函数名末尾的__x__会被删除。

示例

mnl语法

let myHeart = ['kind', 'evil', 'happy'];
console.log(`I born with ${myHeart.join(', ')}.`);

remove('evil')from(myHeart);
console.log(`Now, I have only ${myHeart.join(', ')} in my heart.`);

function remove(item)from(array) {
    array.splice(array.indexOf(item), 1);
    console.log(`Now I removed the ${item} in it.`);
}

编译后(js语法)

let myHeart = ["kind", "evil", "happy"];
console.log(`I born with ${myHeart.join(", ")}.`);

remove__x__from("evil", myHeart);
console.log(`Now, I have only ${myHeart.join(", ")} in my heart.`);

function remove__x__from(item, array) {
    array.splice(array.indexOf(item), 1);
    console.log(`Now I removed the ${item} in it.`);
}

运行结果

I born with kind, evil, happy.
Now I removed the evil in it.
Now, I have only kind, happy in my heart.

编译器

为实现功能,我用js写了一个编译器,可用node运行。

由于笔者能力有限,目前的demo编译器不能完美编译。目前已知有如下bugs:

  1. 字符串内的代码也会被编译

详情请见mnl.js的GitHub页面:https://github.com/YuanSa/mnl.js

欢迎指教与合作。

查看原文

赞 4 收藏 1 评论 2

崮生 回答了问题 · 2020-09-28

解决vscode有什么插件能点击css的class名跳转到定义处?

我更推荐使用 CSS Navigation

https://github.com/pucelle/vscode-css-navigation

关注 3 回答 3

崮生 发布了文章 · 2020-08-31

powershell 终端美化 git 分支名乱码解决办法

之前通过 on-my-posh 已经美化过一次了但是 如果我 git 分支名中有中文那么他显示的还是乱码,所以现在想让他正常显示

图片.png

通过如下命令找到主题文件

图片.png

打开之后搜寻一番发现

图片.png

ps 脚本我不太懂,看这个文件大致可以猜出来终端中上面那一行就是 $prompt 输出后的结果,现在的问题缩小到如何让 $prompt 内包含的中文输出后正常显示?

经过尝试上图红框出输入中文输出的也是乱码,网上搜寻无果,突然想起来gb2312 这个东西,将该文件使用gb2312编码保存代码内的中文可以输出了

图片.png

但右侧分支名还是乱码,猜测应该是一样的问题,那么应该会有这几种解决方案

  1. 让powershell 支持utf-8。这个因为其他问题之前试过,虽然utf-8 的是正常显示了但导致本来中文能正常输出的反而不行了
  2. 最好的方法应该是直接让这个脚本可以输出utf-8的字符
  3. 分支名转 gb2312 再输出

接下来就是去网上找文档看有没有办法解决或者能实现我上面提出的两个方案

https://www.zhihu.com/question/54724102/answer/1035566559 发现了解决方案1的实现方法

步骤如下

  1. 输入 $profile 得到powershell配置文件地址

图片.png

  1. 添加 $OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding

图片.png

中文分支名正确显示!

图片.png

另外的问题,显示 emoji

我想在最前面放一个 emoji

图片.png

图片.png

在线编码工具 http://tools.jb51.net/transcoding/decode_encode_tool

这个三角形的编码就是 0x1F4D0 但打印出来后前面多了问号,不知道什么原因,但前四位为0的emoji是可以正常显示的,可能是因为组合字的缘故。

这个问题没有想到比较好的方法,望了解者不吝赐教(´▽`ʃ♡ƪ) 。我只能暂时先用单个码点的emoji了

查看原文

赞 1 收藏 1 评论 0

崮生 发布了文章 · 2020-08-20

链式调用与proxy

链式调用虽然快乐,可每个方法后面的 return this 略显繁琐与丑陋,括号与引号也未免太多。

例如下面这个简单的logger

new Logger()
  .addLabel("warn", "l4", "登录", "游客", "error")
  .addContent("失败")
  .addContent("密码不对")
  .end();

你可能已经对这样的封装习以为常了,但其实他还能这样写!

Log.warn.l4.label("登录", "游客").log("失败").error.密码不对;

我觉得后者有一种简洁美

具体实现如下

class Logger {
  label: string[] = [];
  content: unknown[] = [];
  addLabel(...label: string[]) {
    this.label.push(...label);
    return this;
  }
  addContent(content: unknown) {
    this.content.push(content);
    return this;
  }
  end() {
    // 做一些存储打印之类的操作
    console.log(this);
  }
}
function getLog() {
  const logger = new Logger();
  /** 访问链路 */
  const propertyLink: (string | number | symbol)[] = [];
  const self = (new Proxy(/** 目标不重要,因为实际上使用 target */ getLog, {
    get(target, property, receiver) {
      propertyLink.push(property);
      //   console.log(property);
      if (/** 表等级用 */ typeof property === "string" && /l\d+/.test(property)) {
        logger.addLabel(property);
      } else if (/** 直接添加标签 */ typeof property === "string" && ["warn", "error"].includes(property)) {
        logger.addLabel(property);
      } else if (/** 可以调用的方法 */ typeof property === "string" && ["log", "label"].includes(property)) {
        // 调用则添加内容
      } else {
        //over
        logger.addContent(property);
        return logger.end();
      }
      return self;
    },
    apply(target, thisArg, argumentsList) {
      const previousProperty = propertyLink[propertyLink.length - 1];
      if (previousProperty === "label") {
        logger.addLabel(...argumentsList);
      } else if (previousProperty === "log") {
        logger.addContent(argumentsList);
      }
      return self;
    },
  }) as any) as Log;
  return self;
}
const Log = new Proxy(getLog(), {
  get() {
    return getLog();
  },
});
type Log = {
  error: Log;
  warn: Log;
  info: Log;

  label: (...lables: string[]) => Log;

  l1: Log;
  l2: Log;
  l3: Log;
  l4: Log;
  l5: Log;
  l6: Log;
  l7: Log;
  l8: Log;
  l9: Log;
  /** 具体消息 */
  [k: string]: void | Log | any;

  log: (...arg: unknown[]) => Log;

  end: void;
};

Log.error.l9.错了呀;
Log.error.l9.warn.错了呀;
Log.error.l4.那天夕阳下的奔跑是我逝去的青春;

Log.warn.l4.log("有毒?").end;

Log.warn.l4
  .label("登录")
  .label("游客")
  .log("失败").end;

Log.warn.l4.label("登录", "游客").log("失败").error.密码不对;

new Logger()
  .addLabel("warn", "l4", "登录", "游客", "error")
  .addContent("失败")
  .addContent("密码不对")
  .end();

图片.png

查看原文

赞 0 收藏 0 评论 0

崮生 赞了文章 · 2020-07-05

只推荐一本 JavaScript 书,你推荐哪本?

嗨,我是 Martin。最近为了统一社区称谓,都换成 Martin Ager Adams。

前言

前端世界,技术层数不穷。尽管更新速度已经放缓,刚入门的票友总还是鸭梨山大。

前端三剑客 —— HTML、CSS、JavaScript 中面试问的最多的就是 JS。

全网的资料浩如烟海,我们如何学习 JS 呢?别急,今天 Martin 给大家介绍一必看的网站。

首先说一句,它不是 MDN,但是它的确和 MDN 一样重要。

它、MDN、红宝书列为前端必看的资料。

推荐

今天推荐的这个教程是《The Modern JavaScript Tutorial》。

不用担心英语不好,因为有一群中文小伙伴在负责翻译。

中文版地址《现代 JavaScript 教程

知乎

如果只能推荐一本 JavaScript 的书,你会推荐哪本?

这个教程解决了现存 JavaScript 书籍最大的痛点:实时性。这是本教程的第一大特色。

《现代 JavaScript 教程》以最新的 JavaScript 标准为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。保证了内容能够与最新的 ECMAScript 保持同步。

第二大特色是,为读者搭建了良好的学习路线,由浅入深,内容足够详细也足够全面。当然,这里的全面是指在 JavaScript 语言层面的,不包括 React,Vue 等框架的教学。

这个教程主要分为三个部分:

  1. 入门: 主要为 JavaScript 语言方面的内容,包括数据类型,循环,对象,闭包,Class,原型,继承,Promise,ES Module 等基础知识。
  2. 提升: 包括 BOM 和 BOM 的相关内容。
  3. 进阶: 包括网络请求,Web Components,正则,动画,浏览器缓存等相关内容。

第三大特色是:每节内容后,都给出了高质量的课后习题和解析。通过做题可以帮你检验自己的学习效果,并巩固新学到的知识。

教程

第 1 部分 JavaScript 编程语言

第 2 部分 浏览器:文档,事件,接口

第 3 部分其他文章

参考

如果只能推荐一本 JavaScript 的书,你会推荐哪本?

关注

欢迎小伙伴,在评论区写出你最新喜欢的一本 JavaScript 的书。

查看原文

赞 15 收藏 9 评论 4

崮生 关注了标签 · 2020-07-05

typescript

TypeScript 是微软开发的 JavaScript 的超集,TypeScript兼容JavaScript,可以载入JavaScript代码然后运行。TypeScript与JavaScript相比进步的地方。包括:加入注释,让编译器理解所支持的对象和函数,编译器会移除注释,不会增加开销;增加一个完整的类结构,使之更新是传统的面向对象语言。

关注 32573

崮生 发布了文章 · 2020-07-04

nest.js 阿里云云函数部署

之前就想让 nest.js 在阿里云上部署 serverless 试试,但在网上没有搜到相关的例子

只找到了 express 的例子,但我不知道怎么从 nest.js 获得 express app 对象。就此陷入僵局,但在搜索的过程中发现腾讯云是有 nest.js 的例子的,一看他们的代码,( •̀ ω •́ )✧ express app 原来是这么拿的啊,只要用 ExpressAdapter 就好了,但之前没用过就不了解

然后我刷刷刷的写出了如下代码

//file://src/index.ts
import { NestFactory } from "@nestjs/core";
import { ExpressAdapter } from "@nestjs/platform-express";
import { Server } from "@webserverless/fc-express";
import express from "express";
import { AppModule } from "./app.module";
let p = (async () => {
 const adapter = new ExpressAdapter(app);
 const app2 = await NestFactory.create(AppModule, adapter);
  app2.enableCors();
 await app2.init();
 return new Server(app);
})();

module.exports.handler = function (req, res, context) {
  p.then((server) => {
    server.httpProxy(req, res, context);
  });
};

结果 (;´д `)ゞ 他啪啪啪的一直超时,我就不明白了他为啥调用一直超时。

经过一行行的测试发现 `module.exports.handler` 中一旦是异步执行 `server.httpProxy(req, res, context)` 哪怕是这样写 `setTimeout(()=>{server.httpProxy(req, res, context)},1)` 他也会超时。这里不知道原因,也不想浪费时间

既然找到了症结那就简单了,咻咻咻一段修改得到如下代码

//file://src/index.ts
import { NestFactory } from "@nestjs/core";
import { ExpressAdapter } from "@nestjs/platform-express";
import { Server } from "@webserverless/fc-express";
import express from "express";
import { AppModule } from "./app.module";

const app = express();

let p = (async () => {
 const adapter = new ExpressAdapter(app);
 const app2 = await NestFactory.create(AppModule, adapter);
  app2.enableCors();
 await app2.init();
})();
app.use(function (req, res, next) {
 console.log(`[time:${Date.now()} [url:${req.url}]]`);
  p.then(() => next());
});

const server = new Server(app);

module.exports.handler = function (req, res, context) {
  server.httpProxy(req, res, context);
};

完美运行,诀窍就是 `module.exports.handler` 内部不异步执行了,等待 nest.js 初始化的这个操作放到 express 中间件中去就行了

[样例代码 github 地址](https://github.com/2234839/nest.js_aliyun_serverless)

查看原文

赞 1 收藏 1 评论 0

崮生 赞了文章 · 2020-07-02

实现一个成熟的底层毛玻璃效果(纯CSS)

效果图

写在前面

毛玻璃背景是一个很常见的网页样式,但大量实现方法都把问题复杂化了
现提供一个代码很直白且实现效果良好的实现方案,改良自W3Schools


HTML部分

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>FrostedGlass</title>
    <link rel="stylesheet" href="frostedGlass.css">
  </head>
  <body>
    <div class="mainHolder">
      <div class="textHolder">
        <p>this is FrostedGlass</p>
      </div>
    </div>
  </body>
</html>

.mainHolder是主框体
.textHolder是毛玻璃区域
.p是浮于毛玻璃上的文字内容

CSS部分

* {
  box-sizing: border-box;
}
.mainHolder {
  width: 600px;
  height: 600px;
  background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/skyscrapers.jpg);
  background-attachment: fixed;
  background-position: center;
  background-size: cover;
  position: relative;
}
.textHolder {
  width: 100%;
  height: 200px;
  position: absolute;
  right: 0;
  bottom: 0;
  background: inherit;
  overflow: hidden;
}
.textHolder::before {
  content: '';
  position: absolute;
  top:0;
  right: 0;
  bottom: 0;
  left: 0;
  background: inherit;
  background-attachment: fixed;
  filter: blur(4px);
}
.textHolder::after {
  content: "";
  position: absolute;
  top:0;
  right: 0;
  bottom: 0;
  left: 0;
  background: rgba(0, 0, 0, 0.25);
}
p {
  z-index: 1;
  color: white;
  position: relative;
  margin: 0;
}

解决毛玻璃效果里最核心的问题:模糊效果不能影响字体,采用了伪元素::after和::before
值得注意的是,在p标签里的position属性。设置为relative后,z-index会生效,将p从被遮挡状态“提起来”。
另外,对于不同的浏览器内核,filter的写法会有些许不同。


查看原文

赞 9 收藏 6 评论 0

认证与成就

  • 获得 5 次点赞
  • 获得 3 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 3 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

  • web font

    ui 需要展现一些特定的字体,但直接引入字体包又过大,于是想到了裁剪字体,一开始想的使用「字蛛」但他是针对静态网站的,而且实际他会多出许多英文的,估计是直接将源码中存在的文字都算进去了。 后来又找到阿里的「webfont」 但他的字体有限,项目又不开源,所以自己写了这个

注册于 2019-05-04
个人主页被 429 人浏览