学习心得

从今天开始,把每天的学习的一些知识小结一下~

2022-8-3

rem 和 vw 的优势与劣势,以及发展历史。

rem 优势:可以应用于移动端页面在 pc 端展示,定义 pc 端的 font-size,不会使得页面内容过大。1px 不需要额外的实现。 vw:rem 的升级版,使用更简单方便,不需要关心 viewport。1px 可以使用 transform 来实现。

如果老项目使用 rem 想迁移到 vw 到话,可以只修改 html 的 font-size,根据 media query,将 px 转换成对应的 vw 即可。

2022-7-12

flex vs grid: 一维和二维的区别,flex 专注于每一行或者每一列内容的排列顺序,但是 grid 可以创建二维布局,并且可以精确的精确的放到单元格内。 列子:首字母和内容的两列布局,每个首字母都有可能存在 2 个及以上的内容,那么在第 2 个内容开始,左边就没有首字母填充,这个时候使用 grid 就方便很多。 内容至上 vs 布局至上,flex 的内容会自动伸缩,grid 的内容不会。

何时使用 grid:

  1. 有一个比较复杂的设计,并且可维护性高
  2. 在块状元素上添加间隙

何时使用 flex:

  1. 设计比较简单,并且行列数量不多
  2. 需要对其元素
  3. 需要内容自适应

在使用 git 多用户的时候,要注意切换本地的 git config 用户信息和 hostname 的 user。 本地的 git config 会在每次 commit 中的用户信息里展示,hostname 则是表示本次 commit 是 github 中哪个账号提交的。

2022-6-17

vue3 虽然用 proxy 监听数组了,但是还是劫持了部分数组的方法。

因为 proxy 监听数组的时候,也会追踪数组的 length 属性,然后在某些例子中会导致无限循环。

例子:

const arr = reactive([]);

watchEffect(() => {
  arr.push(1);
});

watchEffect(() => {
  arr.push(2);
});

源码:

function createArrayInstrumentations() {
  const instrumentations: Record<string, Function> = {}
  // instrument identity-sensitive Array methods to account for possible reactive
  // values
  ;(['includes', 'indexOf', 'lastIndexOf'] as const).forEach(key => {
    instrumentations[key] = function (this: unknown[], ...args: unknown[]) {
      const arr = toRaw(this) as any
      for (let i = 0, l = this.length; i < l; i++) {
        track(arr, TrackOpTypes.GET, i + '')
      }
      // we run the method using the original args first (which may be reactive)
      const res = arr[key](...args)
      if (res === -1 || res === false) {
        // if that didn't work, run it again using raw values.
        return arr[key](...args.map(toRaw))
      } else {
        return res
      }
    }
  })
  // instrument length-altering mutation methods to avoid length being tracked
  // which leads to infinite loops in some cases (#2137)
  ;(['push', 'pop', 'shift', 'unshift', 'splice'] as const).forEach(key => {
    instrumentations[key] = function (this: unknown[], ...args: unknown[]) {
      pauseTracking()
      const res = (toRaw(this) as any)[key].apply(this, args)
      resetTracking()
      return res
    }
  })
  return instrumentations
}

function createGetter(isReadonly = false, shallow = false) {
  return function get(target: Target, key: string | symbol, receiver: object) {
    ...
    const targetIsArray = isArray(target)

    if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) {
      return Reflect.get(arrayInstrumentations, key, receiver)
    }

    ...
    return res
  }
}

在 vue3-tsx 中,就算 computed 后计算出来的值没有变,但是只要依赖变了,就会触发 component 的 render。

如果 computed 后计算的值没有在 render 中被使用,那么就算依赖变了导致计算出来的值也变了,computed 函数也不会执行了,只执行 2 次。

vue-router 中,router.push 内部会先调用 router.replace(),再调用 router.push()

不能在 setup 中的 defineProps 中使用 import 的 type 和 interface。

ts 中,??和?.只要验证的是 null 和 undefined 值,而&&和||验证的是 falsy 值(‘‘、”“、0、NaN、null、undefined、false)。 非空断言!在部分业务场景中还是很适用的。var!可以直接排除 null 和 undefined 的情况

访问对象值的时候尽量使用解构赋值,好处有以下几点:

  1. 可以自定义新的变量名
  2. 提高可读性,便于维护
  3. 可以设置默认值
  4. 减少了访问数据属性所采取的步骤数
  5. 有助于减少应用程序中使用的代码量。
  6. 节省了多次迭代对象数组的时间。

位运算:

  1. 判断奇偶的时候使用 i & 1 === 0 来代替 i % 2=== 0

vue3 中编译模版的时候,会遍历所有的 node 节点,并打上静态提升标记 push 到 transformContext.hoists 里,在生成代码字符串的时候,会遍历 hoists,并在 code 里拼接上const _hoisted_${i + 1} =...

2022-5-26

If you use CSS Flexbox Layout to implement a page component with horizontal scrolling, be aware that browsers ignore the end-side padding (in this case, padding-right) of the flex container.

You can emulate the missing padding by spacing the flex items via margin-right and adding a very narrow ::after flex item to the container.

.container {
  display: flex;
  overflow-x: scroll;
  padding: 1em; /* browsers ignore the padding-right component */
}

.container::after {
  content: '';
  padding-right: 0.02px; /* smallest size that is cross browser */
}

使用 ionicon 来引入自定义 svg 的时候,注意引入的地址,如果是本地地址,customElement 默认是不会编译地址的。

2020-6-19

  1. react-router-dom 中的 redirect 不会自动把 query 带上,如果自己不添加到 search 里,则会丢失 query。
  2. react 中设置 stoppropagation 失效是因为 react 会把所有的事件绑定到 document 上,并且返回一个合成事件,每次你在合成事件中 stoppropagation 只能阻止外层合成事件的触发,但是不会阻止 document 上的原生事件。在 react17 中会把所有的事件绑定到 root 上,这样使得在不同的 react 版本的项目中,不会因为版本不同的存在而使得项目事件混乱。

2020-4-20

css 变量

.q {
  display: flex;
  --px: 0;
}

.q > div {
  width: 300px;
  height: 100px;
  //  --px: 0;  如果在这里设定默认的--px,那么修改q上的style Attribute会被默认的覆盖。
}

.a {
  background: pink;
}

.b {
  background: blue;
}

.c {
  background: red;
  transform: translateY(calc(130px * var(--px)));
}
$('.q').style.setProperty('--px', '100px');

同时可以通过 style.setProperty 来修改 css 变量,不过父元素 style Attribute 会被子节点默认的 css 变量覆盖。

2019-9-4

清空 git 当前分支的历史缓存

尝试 运行 git checkout --orphan latest_branch
添加所有文件git add -A
提交更改git commit -am "commit message"
删除分支git branch -D master
将当前分支重命名git branch -m master
最后强制更新存储库git push -f origin master

如果git push -f 被拒绝了则需要修改服务器端的receive.denyNonFastForwards字段为false

2019-4-1

console.log(1)(function () {})();

为什么上面这段代码会报错呢?因为 js 会把(function…)当作是函数 console.log(1)的参数来执行,所以就会报错。

foo()
bar()

var foo = function bar () {}

注意上述代码中的bar函数不会提升,而且全局变量中也不能获取到bar函数

实际上编译成下面:

var foo;

foo()   // TypeError,foo不是函数
bar()   // ReferenceError,声明不存在

foo = function () {
  var bar = self
  ...
}
function foo() {
  console.log(a); //2
}
function bar() {
  var a = 3;
  console.log(a); //3
  foo();
}

var a = 2;

bar();

因为 js 中的作用域是词性作用域,词法作用域是在写代码或者说定义时确定的,词法作用域关注函数在何处声明。但是 this 机制类似动态作用域,动态作用域是在运行时确定的,动态作用域关注函数从何处调用。

2019-2-14

禁止浏览器回退:

window.addEventListener(
  'popstate',
  function (e) {
    pushHistory();
  },
  false
);

function pushHistory() {
  var state = {
    title: '',
    url: window.location.pathname, // 填入当前的url path
  };
  window.history.pushState(state, state.title, state.url);
}

// 这两行代码也是需要的,如果打开页面后并没有pushState过,则还是可以点击返回按钮的,因为此时没有往history中pushState过,所以监听不到popstate。
pushHistory();
window.history.go(-1);

用 Vue 发开微信公众号网页中,调用微信的 jssdk 的时候,每次跳转页面就发现安卓的签名过期,查找了一下发现原因是这样的:安卓和 ios 的微信对于 H5 新增的的路由跳转方式解析不同。

在微信的文档中有一句话:同一个 url 仅需调用一次,对于变化 url 的 SPA 的 web app 可在每次 url 变化时进行调用,目前 Android 微信客户端不支持 pushState 的 H5 新特性,所以使用 pushState 来实现 web app 的页面会导致签名失败,此问题会在 Android6.2 中修复。

之前我只在初始化的时候获取签名,这个时候安卓就发现签名过期。然后看到文档这句话后我就每次路由跳转都重新获取签名,这个时候就是 IOS 发现签名过期了。

原因就是在 IOS 的微信上,无论页面如果跳转,他认准的签名 URL 是你第一次进入这个网页时的 URL,所以在 IOS 上你跳转页面的时候就不应该重新获取签名。

既然知道了原因,那解决方式也很简单,只要先判断是安卓还是 IOS,是安卓就自动获取签名,是 IOS 就判断是否已经有了签名,有则不重新获取,没有则获取。

import { getsignature } from './Api/api.js';

let exist = false;

export const getSignature = {
  created: function () {
    const u = navigator.userAgent;
    const isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);

    if (isiOS && exist) return;
    getsignature(encodeURIComponent(location.href.split('#')[0]))
      .then((res) => {
        // eslint-disable-next-line no-undef
        wx.config({
          debug: false,
          appId: res.data.appid,
          timestamp: res.data.timestamp,
          nonceStr: res.data.noncestr,
          signature: res.data.signature,
          jsApiList: [
            'updateAppMessageShareData',
            'updateTimelineShareData',
            'onMenuShareAppMessage',
            'onMenuShareTimeline',
            'chooseWXPay',
            'editAddress',
          ],
        });
        // eslint-disable-next-line no-undef
        wx.error(function (res) {
          alert(res.errMsg);
        });
        if (isiOS && !exist) exist = true;
      })
      .catch((err) => {
        alert(err);
      });
  },
};

// 在你需要使用jssdk的页面导入即可
import { getSignature } from '../utils';
export default {
  mixins: [getSignature],
};

在目前最新的 jssdk 版本 1.4.0 中,updateAppMessageShareData 和 updateTimelineShareData 暂时无法使用,报错 fail,原因未知。

2019-1-3

新年新气象,在使用 react-native 的使用要用到 echarts,然后发现 react-native-echarts 已经好久没有更新迭代了,而且有很多的 issue 的问题也没有修复,看了他的源码,发现它也就是引入 echarts,然后包在 webview 中展示,那么其实我们完全可以自己来做引入,还能使用 v4 的 echarts。

在稳固 echarts 的 api 的时候,不知道为什么就想看下它的源码。可能是最近经常看源码,导致看啥轮子都想看看源码的实现。

2018-12-20

在什么时候要使用height: 100%呢?

要解决这个问题关键是理解 height 这个属性。

如果我们不设置 height 的话,它就会遍历子元素,然后获取子元素的高度设置成自己的 height。也就是说填充自己。

如果你设置了 height 为 100%,他就会继承父元素的高度。但是这个时候如果父元素的高度没有设置的话,它遍会寻找父元素的父元素的高度,直至找到位置。html 默认为 100%。body 元素比较特殊,如果 html 的 height 为 80%,那么不设置 body 的高度的话,它的 height 还是 100%。如果 html 的高度大于 100%,body 的高度则和 html 相同。但是 div 未设置 height 的高度则始终和父元素的高度相同。

2018-12-11

以前写过 bind 的原生实现,但是时间久了还是有些细节遗忘了,今天还是记录一下。

es6: if (typeof Function.prototype.bind1 !== 'function') {
  Function.prototype.bind1 = function (context, ...rest) {
    if (typeof this !== 'function') {
      throw new TypeError(
        'Function.prototype.bind - what is trying to be bound is not callable'
      );
    }
    var self = this;
    return function F(...args) {
      if (this instanceof F) {
        return new self(...rest, ...args);
      }
      return self.apply(context, rest.concat(args));
    };
  };
}

es5: Function.prototype.bind2 = function (context) {
  if (typeof this !== 'function') {
    throw new Error(
      'Function.prototype.bind - what is trying to be bound is not callable'
    );
  }

  var self = this;
  var args = Array.prototype.slice.call(arguments, 1);

  var fNOP = function () {};

  var fBound = function () {
    var bindArgs = Array.prototype.slice.call(arguments);
    // 使new出来的函数的this指向实例,而不是bind后的context
    return self.apply(
      this instanceof fNOP ? this : context,
      args.concat(bindArgs)
    );
  };

  // 避免修改fBound原型的时候也同时修改了原函数的原型对象
  fNOP.prototype = self.prototype;
  fBound.prototype = new fNOP();
  return fBound;
};

高颜值的 curry 实现方式:

var curry = (fn) =>
  (judge = (...args) =>
    args.length === fn.length ? fn(...args) : (arg) => judge(...args, arg));

2018-10-31

mac 下好用的工具:

  1. brew install wget 下载、扒站神器
  2. brew install ack 搜索代码神器
  3. brew install autojump 终端下多目录跳转神器

正则的部分理解:

  1. (?:exp)的作用是什么?
  2. ^([1-9][0-9]*|0)$^[1-9][0-9]*|0$的区别

2018-8-30

Object.create(null) 和 {} 的区别是:Object.create(null)创造出来的对象是没有继承任何原型的,他没有 toString,hasOwnProperty 等等方法。


理解递归的应用
(fn =>
    (f => f(f))(f => fn(n => f(f)(n)))
)(g =>
    n => [1, 2].indexOf(n)> -1 ? 1 : g(n - 1) + g(n - 2)
)(10);

2018-7-30

  1. 在 mac 中使用 nvm 的时候,如果直接yarn global add <package>,我发现它不会帮我们安装到 nvm 所对应的 version 下,而是安装在了.config 下的 yarn 中。但是 npm 安装全局包是可以的。

写一个方法过滤数组中的空字符串:

const filterEmptyString = function (arr, result) {
  arr.forEach((e) => {
    if (Object.prototype.toString.call(e) === '[object Array]') {
      result.push([]);
      filterEmptyString(e, result[result.length - 1]);
      if (!result[result.length - 1].length) result.splice(r.length - 1, 1);
    } else {
      if (e !== '') result.push(e);
    }
  });
  return result;
};

2018-7-25

  1. 在 vscode 中使用 nvm 会出现一点问题,就算你通过nvm alias default <version>设置了默认都 node 版本,但是每次在 vscode 中打开终端发现 node 版本还是等于 system,但是通过系统内置终端或者 iterm2 都是正常的。查找了网上都资料发现别人也有这个问题,如果要解决可以在 bash_profile 都结尾处添加nvm use <versioin>
  2. 发现 vue/cli 3.0 构建的项目在热更新中有点问题。pc 端是没有问题的,但是在移动端打开项目后,每次修改触发热更新后,界面是会变化,但是如果你刷新页面后,页面又回到了起始项目运行的界面,即界面收到 HMR 的 hash 是最初的 hash,并不是最新的 hash,不知道具体是什么问题,我构建的 vue-cli 2.0 是没有该问题的。(发现在 safari 下才有问题,chrome 中是没有问题的。)
  3. 吐槽最近的 github 总是抽筋!!!
  4. 在使用 HMR 的时候,我在 webpack 引入 babel 后,发现 module.hot.accept 只能接收到一次数据。
  5. 搭建简易的 vue 感觉还是蛮简单的,原理也不是很难。比较困难的感觉是后面生态的建设,组件等等,因为这些会导致原来的思考方式在目前看来是行不通的。以及部分代码的实现等等,最近要好好想想怎么更好的制作一个简易的 Vue。
  6. 在使用 vue 的 keep-alive 的时候,如果使用在字符串中分隔逗号的话,要注意逗号后面的空格,它会将这个空格也算到 name 中。所以在写的时候要删除逗号之后的空格。
  7. 在异步导入组件的时候,是不能在 import 中使用变量以及模版字符串的,可能是为了安全因素考虑。

2018-7-9

新公司 emm 蛮不错的,最近写了一些小插件,感觉写插件真好玩!!

  1. IE 浏览器中 css3 动画(height)不流畅卡顿,原因是动画所选中的元素设置了 position 为 relative,导致动画卡顿。在 chrome 下无卡顿。
  2. requireJs 中 shim 主要是针对对非 AMD 规范的导入方式的优化,如果不使用 shim,则那些文件在 define 引用后无法使用,但是使用了 shim,则 require 会自动帮我们返回全局变量中的模块信息。
  3. requireJs 的学习可以直接看文档,写的还是比较详细的。
  4. vue-cli 3.0 的学习,看了一下项目构建,发现和 react 的 create-react-app 好像,基本都把配置内置了,如果要修改可以自己写一个 vue.config.js 文件,会覆盖默认配置。
  5. 看了一下 vue-cli-service 的源码,还有部分没理解透,等理解透了再写篇文章整理一下。

2018-5-24

最近学习了微信小程序,阅读深入理解计算机系统这本书,不得不说,我看的真的快睡着了。即将离开第一家公司,心里也很不是滋味。最近这段时间都感觉迷茫了。加油加油吧!

2018-5-7

使用 toString()可以将函数转化成 string 打印出来,但是如果你重新 bind 了函数的指向,再打印,会出现function () { [native code] }

关于移动端输入框挡住 input 的解决方法:

window.addEventListener('resize', function () {
  if (
    document.activeElement.tagName === 'INPUT' ||
    document.activeElement.tagName === 'TEXTAREA'
  ) {
    window.setTimeout(function () {
      if ('scrollIntoView' in document.activeElement) {
        document.activeElement.scrollIntoView();
      } else {
        document.activeElement.scrollIntoViewIfNeeded();
      }
    }, 0);
  }
});

AE(Adobe After Effects)中有个插件(Bodymovin),他可以将在 AE 中的动画导出成 json 文件,然后在网页中引入bodymovin.js就可以播放这段动画。

2018-4-24

对于行内不可替换元素,设置上下外边距无效,左右有效,同理内边距。
这是因为对于行内不可替换元素来说,上下边距不会改变 line-height,而边距又是透明的,所以没有任何视觉效果,但是查看盒子模型还是可以看到上下边距存在。
对于行内可替换元素来说,上下边距和左右边距都有效。

instanceof 的原理:能否在实例的原型链中找到该该实例的构造函数的原型对象(即 prototype 指向),能找到就返回 true。

  如何优雅的将'20180408000000'字符串转成'2018-04-08 00:00:00'

  let formatStr = function (str, type) {
    let i = 0,
        _type = type || "xxxx-xx-xx xx:xx:xx"
        return _type.replace(/x/g, () => str[i++])
  }

手写原生 ajax 请求

  function createXHR() {
    if (window.XMLHttpRequest) {
      return window.XMLHttpRequest()
    } else {
      return new ActiveXObject('Microsoft.XMLHttp')
    }
  }

  var xhr = createXHR()
  xhr.onReadyStateChange = function () {
    if (xhr.readyState === 4) {
      if ((xhr.state >= 200 && xhr.state <= 300) || xhr.state === 304) {
        console.log(xhr.responseText)
      } else {
        .....
      }
    }
  }

2018-4-16

  1. 关于队列任务的执行顺序:process.Trick() > Promise 的回调 > setTimeout > setImmediate
  2. 前端模块化解决的问题:命名冲突,繁琐的文件依赖,复用性差,可维护性差。

关于 AMD/CMD/CommonJs 的区别:

  1. AMD/CMD/CommonJs 是 JS 模块化开发的标准,目前对应的实现是 RequireJs/SeaJs/nodeJs。
  2. CommonJs 主要针对服务端(因为客户端没有 export,require,global 等字段),AMD/CMD 主要针对浏览器端。
  3. AMD/CMD 区别,虽然都是并行加载 js 文件,但还是有所区别,AMD 是预加载,在并行加载 js 文件同时,还会解析执行该模块(因为还需要执行,所以在加载某个模块前,这个模块的依赖模块需要先加载完成);而 CMD 是懒加载,虽然会一开始就并行加载 js 文件,但是不会执行,而是在需要的时候才执行。
  4. AMD 优点:加载快速,尤其遇到多个大文件,因为并行解析,所以同一时间可以解析多个文件。
  5. AMD 缺点:并行加载,异步处理,加载顺序不一定,可能会造成一些困扰,甚至为程序埋下大坑。
  6. CMD 优点:因为只有在使用的时候才会解析执行 js 文件,因此,每个 JS 文件的执行顺序在代码中是有体现的,是可控的。
  7. CMD 缺点:执行等待时间会叠加。因为每个文件执行时是同步执行(串行执行),因此时间是所有文件解析执行时间之和,尤其在文件较多较大时,这种缺点尤为明显。

2018-3-27

可以使用caret-color来修改 input 中光标的颜色。

腾讯面试问题:

  1. http 的状态码,什么情况下会返回 304?cache-control 和 etag,last-modified 的区别?
  2. 描述一下 css 盒模型
  3. 实现垂直水平居中有哪些方法
  4. 跨域有什么处理方法?JSONP 的原理是什么?JSONP 可以用 post 请求吗?为什么?
  5. cookie 和 localstorage 有什么区别?
  6. vue 数据双向绑定的原理
  7. react 的生命周期有哪些?什么时候会用到 componentwillreceiveprops?

初始化 constructor static getDerivedStateFromProps() UNSAFE_componentWillMount() render componentDidMount 更新过程 UNSAFE_componentWillReceiveProps() static getDerivedStateFromProps() shouldComponentUpdate() UNSAFE_componentWillUpdate() render getSnapshotBeforeUpdate() componentDidUpdate 卸载过程 componentWillUnmount

  1. let 和 var 的区别
  2. 使用过构建工具吗?webpack 的 loader 是干什么的?

2018-3-19

前几天看到 js 位运算,发现有好多可以巧用这个技巧。

  1. 按位非 ~-1 === 0

  2. 异或来交换数字

let a = 1,
  b = 2;
a = a ^ b;
b = a ^ b;
a = a ^ b;

a; // 2
b; // 1

关于for..in,Object.keys(),Object.hasOwnPropertyNames(obj),obj.hasOwnProperty(prop)的区别:

  1. for…in 会遍历所有可枚举属性,对象从其构造函数原型中继承的属性。
  2. Object.keys()会遍历所有可枚举属性,但是不访问其构造函数原型中继承的属性。
  3. Object.hasOwnPropertyNames(obj)方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 值作为名称的属性)组成的数组,但是不会返回其构造函数原型中继承的属性。
  4. obj.hasOwnProperty(prop)可以用来检测一个对象是否含有特定的自身属性;和 in 运算符不同,该方法会忽略掉那些从原型链上继承到的属性。
  5. for…in 和 obj.hasOwnProperty(prop)搭配筛选后的结果和 Object.keys()相同。
  6. Object.hasOwnPropertyNames(obj)返回的只比 Object.keys()多指定对象的不可枚举属性。

x = (1, 2, 3)表达式为 Comma operator。
Comma operator:他表示依次执行括号中的每个表达式,然后返回最后那个结果(返回的是结果,是指,不是 reference)。
如果返回的那个结果是 console.log(this),那么这个 this 不是执行那个方法,而是 undefined。

例子如下:

'use strict'
const fn = function () {
  default () {
   console.log(this)
  }
}

(fn[default])()  // fn
(0, fn[default])()  // this

只有在fn.a()fn[a]()这样才会被认为是在执行fn的a方法this才会指向fn(0, fn[a])只是返回fn[a]的结果即console.log(this)而此时this为undefined在非严格模式下应该是返回window全局对象)。

2018-2-24

在 rgb 中,red 是暖色,green 是中性色,blue 是冷色,如果 r>b,则为暖色,否则为冷色。

在 hsv 中,hsv.h >= 60 && hsv.h <= 240为冷色调,减淡变亮,色相顺时针旋转更暖。hsv.h <= 60 && hsv.h >= 240为暖色调,减淡变亮,色相逆时针旋转更暖。

实现深拷贝

function deepClone(data) {
  let r = null;
  if (typeof data !== 'object') {
    r = {};
    for (let key in data) {
      if (data.hasOwnProperty(key)) {
        r[key] = deepClone(data[key]);
      }
    }
  } else if (Array.isArray(data)) {
    r = [];
    for (let i = 0; i < data.length; i++) {
      r.push(deepClone(data[i]));
    }
  } else {
    return data;
  }
}

2018-2-6

今天在使用 vue 的时候发现一个问题,beforeCreate 居然在 create 之后执行,百思不得其解,后来才发现原来在 create 中的 ajax 设置了 async 为 false,因为是同步,所以会导致 beforeCreate 中的 loading 组件延迟执行。

vue 中 provide,inject 使用。配合 vee-validate 可以在父组件中对所有使用验证的子组件进行验证。

为什么 flex 的子元素在设置 display 为 flex 后,它的子元素无法撑开它自己。

svg 中使用简便的时候,使用 d3.area()才渲染下面的面积,如果使用 d3.line()会使上扬的线条的上部分渲染。

2018-1-16

webpack-dev-server 使用,vue 模拟数据的配置。

nginx 中重写路径:

  location /static {
    if ($http_referer ~* "test\/"){
      rewrite ^(/static\/.*)   /test/$1 break;
    }
    rewrite ^(/static\/.*)   $1 break;
  }

2018-1-3

今天在给 ie 调试 ajax 的时候发现 ajax 不会发送,jquery1.5+ ajax 跨域请求在 IE 下没反应

The root route must render a single element 这个异常,这是因为 module.exports(CommonJS) 和 ES6 里的 export default 有区别。

如果你是使用 es6 的写法,并且就是你的组件都是通过 module.exports 导出的,那么在 getComponent 方法里面需要加入 .default。

如果你是使用 CommonJS 的写法,也就是通过 module.exports 导出的,那就无须加 .default 了。

在 vue 中使用 async。

2017-12-25

如果是自己手动配置 webpack,当你要打包的时候,打包的方式是 runtime-only build 模式(运行时构建),这个时候new Vue挂载的时候不支持 template,只能只能 render,如果使用 template,就会报错You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build
相关链接

因为要给公司开发自用的 chrome 插件,所以最近肯定要学习不少的内容。就在这几天使用 jq 的时候,发现很多以前的知识都遗忘了。
比如要获取 radio 的 checked 的属性时,不应该使用 attr,应该使用后 prop。

对于 HTML 元素本身就带有的固有属性,在处理时,使用 prop 方法。
对于 HTML 元素我们自己自定义的 DOM 属性,在处理时,使用 attr 方法。

给某个 name 的 radio 设置 checked 的 value,$('input[name="radioName"][value="checkedValue"]').prop('checked', true)

2017-12-20

移动端调试工具:debuggap,ChromeDevTools,weinre

2017-12-14

浏览器中, js 引擎线程会循环从 任务队列 中读取事件并且执行, 这种运行机制称作 Event Loop (事件循环)。
不仅如此, event loop 至少拥有如下两种队列:
1.task queue, 也叫 macrotask queue, 指的是宏任务队列, 包括 rendering, script(页面脚本), 鼠标, 键盘, 网络请求等事件触发, setTimeout, setInterval, setImmediate(node)等等。 2.microtask queue, 指的是微任务队列, 用于在浏览器重新渲染前执行, 包含 Promise, process.nextTick(node), Object.observe, MutationObserver 回调等。

以下是原文:

An event loop has one or more task queues. A task queue is an ordered list of tasks, which are algorithms that are responsible for such work as: events, parsing, callbacks, using a resource, reacting to DOM manipulation… Each event loop has a microtask queue. A microtask is a task that is originally to be queued on the microtask queue rather than a task queue.

浏览器(或宿主环境) 遵循队列先进先出原则, 依次遍历 macrotask queue 中的每一个 task, 不过每执行一个 macrotask, 并不是立即就执行下一个, 而是执行一遍 microtask queue 中的任务, 然后切换 GUI 线程重新渲染或垃圾回收等.

2017-12-13

cmd 中arp -aipconfig/allnslookup

window.requestAnimationFrame 方式的应用。

nginx X-real-ip、X-Forwarded-For 字段理解:
proxy_set_header X-real-ip $remote_addr 是设置客户端的 ip,如果不设置,经过代理服务器 nginx 后,web 服务器接收到的 ip 是 nginx 的 ip,并非是客户端的真是 ip(如果只隔了 1 台 nginx)。
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for 意思是增加一个$proxy_add_x_forwarded_for 到 X-Forwarded-For 里去,注意是增加,而不是覆盖,只不过由于默认的 X-Forwarded-For 值是空的,所以我们觉得是赋值,在中间使用多台代理的时候就会展现不同。$proxy_add_x_forwarded_for 变量包含客户端请求头中的”X-Forwarded-For”,与$remote_addr 两部分。每次在 X-Forwarded-For 中增加一个 X-Forwarded-For $proxy_add_x_forwarded_for,就可以看成是将接收到的 X-Forwarded-For 加上自上一台代理或者客户端的 ip,逐一传递下来后 web 服务端就可以接收到从客户端以及各个代理的 ip。

参考资料

2017-12-12

parallax.js 滚动插件的使用,注意不是 parallax 这个轻量级的可视化引擎。

srcset 的应用场景分析:同一张图片针对不同响应式展现不同精度的格式。

js 三种递归方式以及区别:

1.直接调用自身

function a(n) {
  if (n <= 0) {
    return 1;
  } else {
    return n + a(n - 1);
  }
}

a(5); //15
let b = a;
b(5); //15
a = null;
b(5); //error:a is not a function

这里就可以看出,b 其实是 a 的一个引用,当 a 设置为 null 的时候,b 自己也就无法使用了。

2.通过 arguments 调用自身

let a = function () {}和匿名函数结论相同
function a(n) {
  if (n <= 0) {
    return 1
  } else {
    return n + arguments.callee(n - 1)
  }
}

a(5)   //15
let b = a
b(5)  //15
a = null
b(5)  //15

虽然 arguments.callee 可以调用自身,但是在严格模式下,是禁止使用 arguments.callee 的。

3.通过函数命名表达式

let a = function f(n) {
  if (n <= 0) {
    return 1;
  } else {
    return n + f(n - 1);
  }
};

a(5); //15
let b = a;
b(5); //15
a = null;
b(5); //15

这个方法使用了函数命名表达式来定义函数 a。然后在函数内部通过函数名 f 来调用自身,这样就 b 和 a 也就没有任何关系了。他们的指针都指向 f 函数,在 a 设置为 null 后,也只是将修改了 a 的指针,并没有修改 f 函数。

2017-12-8

之前就研究过 exports 和 module.exports,最近好好梳理下。

module.exports = {}
这个时候因为 module.exports 绑定了一个新对象,所以会和原本的 exports 失去联系,exports 不再是 module.exports 的引用,所以 export.xx = xx 不会被导出。
解决办法是exports = module.exports = {},然后 exports.xx = xx 还是会被导出。
这是比较关键的一点。另一个是exports = {}这个时候,exports 不再是原来的 module.exports 的引用,所以还是会失去关联。
若 exports 和 module.exports 都以 aa.xx = bb 的形式赋值,则相互不影响。若有相同的 key 时,value 取后赋值的,不是 module.exports 赋值的。

2017-12-6

js 下载文件方法汇总

1.a 标签 get 方式下载

window.open(url? + params)

2.form 表单 post 方式下载

$('body').append(form);
form.attr('style', 'display:none');
form.attr('target', '_blank');
form.attr('method', 'post');
form.attr('action', url);
for (let i in data) {
  let input = $('<input>');
  input.attr('name', i);
  input.attr('value', data[i]);
  form.append(input);
}
form.submit();
form.remove();

3.blog 方式下载

配合downloadjs一起使用;

axios({
  method: 'post',
  url: url,
  data: data,
  responseType: 'blob',
  headers: {
    Accept:
      'application/vnd.openxmlformats-officedocument' + '.spreadsheetml.sheet',
  },
}).then((res) => {
  download(res.data, 'test1.xls');
});

2017-12-5

for (const prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    console.log(`obj.${prop} = ${obj[prop]}`);
  }
}

// for in 会循环继承的属性,而hasOwnProperty则会忽略继承的属性

2017-11-20

怎么在 vue 中修改 echarts 的 tooltip 框的大小宽度,因为 tooltip 框是一个 echarts 自动生成的 div,而他的样式都是行内样式,所以直接通过改变 tooltip 的样式是比较麻烦的,比较轻松的一种方式是通过formatter来实现。
因为 formatter 可以返回一个 div,所以我们可以通过 params 得到图表的 name 等别的参数,然后显示在 div,通过给 div 一个 class,然后设置 css 来实现 tooltip 的换行已经宽度控制,当然如果在 vue 中使用的时候要格快注意取消 css 的 scope 属性。

2017-10-27

在 vue 遇到Do not use 'new' for side effects,可以在这函数头顶上加一句/* eslint-disable */

删除 html 中的标签,删除空格,删除换行的正则匹配:
text.replace(/<.*?>/ig, '').replace(/(^\s*)|(\s*$)/g, '').replace(/(\n)/g, '')

2017-10-18

当 vue 使用 history 的 router 模式后,如果你想打包完看打包之后的项目,需要配置相关服务器配置,这是因为 vue 是单页面应用,而 history 在跳转的时候会直接跳转到另外一个网页,而不是当前的单页面,所以会出现 index 可以打开,但是跳转别的页面的时候会出现 not found,这是因为 route 在这里无法被识别。所以需要配置相关的服务器。

在官网中有好几种方式,我试了下 node 的,发现并不好用,因为他每次返回的 content-type 都是 text,这就导致获取到的 js 文件也是 text 类型,然后就会出现unexpected token >这个错误。

然后我尝试使用 expredd 搭配connect-history-api-fallback中间件这个方法,一开始也是有点摸不到头脑,连主页都是 not found,后来在issus#35中找到了答案,原来在使用这个中间件的时候,还要配置默认的静态文件和 index 跳转路径。

具体代码:

var history = require('connect-history-api-fallback');
var express = require('express');

var app = express();

// 这里指向你的index.html文件目录,第一次使用的时候是为了让中间件获取主要的静态文件请求
app.use(express.static('./'));

app.use(history({}));

// 第二次使用时为了让中间件重写请求,如果这里不添加的话只会显示主页,跳转别的页面的时候就会出现not found
app.use(express.static('./'));

const port = 5000;
app.listen(port, () => {
  console.log(`Example app listening on port ${port}!`);
});

2017-10-13

在使用 swiper 的时候遇到了很多问题,首先是如果遇到页面进去不自动播放的话,先设置 observer 和 observeParents 为 true,还不行的话就看看 this.swiper.autoplayPaused 是否为 true,如果为 true 则设置为 false,然后在this.swiper.init()一下就会自动播放了。至于点击之后不自动播放那就需要设置 autoplayDisableOnInteraction 为 false。

centeredSlides可以让图片居中显示。

由于移动端和 pc 端还是有蛮大的差别,首先移动端不常用 px,很多是以 rem 为单位。

2017-9-22

UMM!~~好久没写了~还是照旧总结下最近新获取的到的一些内容~

  1. 在 bootstrap 的弹出框中看到可以点击弹出框外的部分实现弹出框关闭,vue 中就是在 created 中给 document.addEventListener 中绑定一个函数,让弹出框的 disable 为 true,然后给弹出框的 div 绑定一个 click,event.stopPropagation()即可。
  2. 最近的新项目比较大,然后数据接口全由前端来设计,虽然这对前端是好事,但是事情也多了不少了,接口对接文档写的头疼,特别是需求改了之后部分接口数据接口都变了,不过我发现写这个还是蛮有趣的,挺锻炼人的~
  3. 在关于 vue 中组件化的区分,如果父组件和子组件之间联系很大的话,比如子组件的渲染很大程度的依靠父组件各个数据,那么组件化的过程中可以主要的把 css 等样式组件化出去,js 等方法还是写在父组件中,但是如果是子组件自己的方法的话还是应该写在子组件中的 script 中。
  4. 虽然每天写代码,但是我发现其实自己的基础还是掌握的不好,很多基础的 api 还是需要去翻文档,不翻就写不出来,所以现在每天都会把基础的知识写在小本子上,平时的时候多翻翻。
  5. transition 不能应用在 display 的变化上。
  6. 如果不想使用 table,但是又想使用 table 的那些布局,那么可以给 div 设置 display 为 table-row 和 table-cell 来实现行和列的效果。
  7. 如果在 table 想让 table 的 tbody 出现滚动条,而 thead 保持不动,我发现实在是没什么好办法,虽然很多人说给 tbody 的 tr 和 thead 添加 display 为 table,但是当 tbody 的 display 设置成 block 之后 tbody 和 thead 就已经不联动了,如果你的 table 的 th 和 td 都是固定的,那还是可以显示那个效果,但是如果你的 th 和 td 都是联动的,th 的宽度和会根据 td 的宽度而改变的时候这时候这个方法就不适用了。所以这个时候只能通过 js 获得每个 td 的宽度,然后分别给对应的 th 设置宽度。

VeeValidate 的使用,在 main.js 中引入 VeeValidate,然后设置 config,再Vue.use(VeeValidate, config)即可,你可以将需要验证的表单内容写在 main.js 中,也可以写在各自的组件中,只要在 created 中定义好表单信息,然后updateDictionary一下,比如:

const dict = {
  zh: {
    custom: {
      user: {
        required: '用户名不能为空',
      },
      password: {
        required: '密码不能为空',
      },
    },
  },
};
this.$validator.updateDictionary(dict);

使用 vue 自带的 dev-server.js 写接口,比如:

// api.js文件的内容
let path = require('path');
let api = {
  'api/url': path.resolve(__dirname, 'data/data.json'),
};
module.exports = api;

// 在der-server.js中引入接口api的文档
let api = require('../mocking/api');

//遍历api中每个对象
Object.keys(api).forEach(function (url) {
  app.get(url, (req, res) => {
    fs.readFile(api[url], 'utf8', (err, data) => {
      if (err) return console.log(err);
      let json = JSON.parse(data);
      res.json(json);
    });
  });
});

你将需要的数据写在 json 文档中,这样当你写好接口文档的时候,就不需要等到后端接口写好才去测试,自己可以边开发边测试接口数据。post 的类似,不过需要一些 node.js 知识来判断传过来的数据。

2017-8-11

在学习 node 的时候把 node 更新到了 8.3.0,结果之前的几个用了 sass 的项目打不开了,原因貌似是因为依赖的 node 版本改变,我 npm rebuild node-sass 后发现还是不行,就下了一个 nvm 解决了。使用 node.js 的时候用 8.3.0,不然就切换会 6.10.1。

2017-8-4

使用 scss 的时候记得安装相应的包:
npm install sass-loader node-sass vue-style-loader --D
然后再 style 中加入lang="scss"

只有设置了 prototype 的对象可以查看 prototype,不然不可查看。

构造函数 new 出来的对象的 constructor 会随着原型的改变而改变。如果原型没有改变,constructor 就指向构造函数,如果原型改变,则 constructor 则指向修改后的原型的 constructor。

理解 js 中的 replace 函数用法:
当第二个参数是函数的时候,他会给函数传递几个参数,matchStr,groups,index,sourceStr,其中 groups 根据正则中分组的情况增加,有两个分组就会传递 matchStr,group1,group2,index,sourceStr。
matchStr: 每次正则匹配到的字符串,这是固定的;
groups: 代表的是 group1,group2,group3……等等参数。参数个数根据捕获组的个数来定。
index: 匹配项在字符串中的开始下标;
sourStr: 原字符串。

2017-8-2

今天看了十年踪迹在清华大学演讲的 ppt,看到他用了很多的高阶函数,使用它的目的是 write less, do more!所以在今天也学习了很多简单高阶函数的用法!

第一次看到高阶函数的时候,比较感觉困惑的是参数的定义,当最外层函数传入一个参数的时候,内层函数再传参数那参数到底是怎么层层调用的呢,然后输出函数又是怎么再内层函数中调用,以及一系列的问题。现在来总结一下:

比如这个例子:

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
</ul>
function batch(fn) {
  return function (target, ...args) {
    if (target.length >= 0) {
      console.log('11');
      return Array.from(target).map((item) => fn.apply(this, [item, ...args]));
    } else {
      return fn.apply(this, [target, ...args]);
    }
  };
}

function queriable(fn) {
  return function (selector, ...args) {
    if (typeof selector === 'string') {
      selector = document.querySelectorAll(selector);
    }
    console.log(...args);
    return fn.apply(this, [selector, ...args]);
  };
}

function pack(map) {
  return function (el, obj) {
    for (let key in obj) {
      map[key].call(this, el, obj[key]);
      console.log(obj[key]);
    }
  };
}

function setColor(el, color) {
  el.style.color = color;
}

function setFontSize(el, fontSize) {
  el.style.fontSize = fontSize;
}

let css = pack({ color: setColor, fontSize: setFontSize });
css = queriable(batch(css));

css('ul > li:nth-child(2n + 1)', { color: 'red' });
css('ul > li:nth-child(3n + 1)', { color: 'green', fontSize: '22px' });

刚开始看到这个的时候我是比较困惑的,到底是先执行 css,再 batch,还是先 queriable 再 batch,所以我在每个函数中打 log,打每个的 args 等参数,了解到函数都是从外到内运行,即 queriable 到 batch 再到 css,然后参数都是通过函数内置的 arguments 来传递。

其中那个 pack 函数我整整理解了很久才领略到高阶函数的魅力,他的确能够用更少的代码做更多的事,虽然难度比较大,也不好理解。

以及这个应用了 ramda.js 的例子:

最开始我并不是很理解函数柯里化,但是当我理解了这个例子中 changeColorTo 函数后,我不禁感叹函数柯里化的强大,而对于 ramda.js 这个库,阮一峰老师的这篇博文也说的很棒这里

<div id="students"></div>

<button id="printBtn">print</button>
class Component {
  constructor(id, opts = { data: [] }) {
    this.container = document.getElementById(id);
    this.options = opts;
    this.container.innerHTML = this.render(opts.data);
  }
}

class StudentViewModule {
  constructor(view) {
    this.view = view;
    this.nameEl = view.querySelector('.student-name');
    this.ageEl = view.querySelector('.student-age');
    this.ageEl.onchange = function (evt) {
      this.age = evt.target.value;
    };
  }
}

// 这里使用defindProperty是因为要双向绑定,不然可以直接在class StudentViewModule中设置name和age
Object.defineProperty(StudentViewModule.prototype, 'name', {
  set(val) {
    this.nameEl.innerHTML = val;
  },
  get() {
    return this.nameEl.innerHTML;
  },
});

Object.defineProperty(StudentViewModule.prototype, 'age', {
  set(val) {
    this.ageEl.value = val;
  },
  get() {
    return this.ageEl.value;
  },
});

class Students extends Component {
  constructor(id, opts = { data: [] }) {
    // super()是新建父类的this对象,但是this还是指向子类,所以这里调用父类的constructor的方法,其中的this指向子类,
    // 所以父类的constructor方法中的this.render不会报错,因为this指向子类。
    super(id, opts);
    this.bind();
  }
  render(data) {
    let content = data.map(
      (student) => `
      <li class="student-info">
        <span class="student-name">${student.name}:</span>
        <input type="text" value="${student.age}" class="student-age"/>
      </li>
    `
    );
    return `<ul>${content.join('')}</ul>`;
  }
  bind() {
    let students = this.container.querySelectorAll('li.student-info');
    let data = this.options.data;
    let info = [];
    students.forEach((student, i) => {
      info[i] = new StudentViewModule(student);
    });
    this.studentInfo = info;
  }
}

let data = [
  {
    name: '张三',
    age: '27',
  },
  {
    name: '李四',
    age: '21',
  },
  {
    name: '王五',
    age: '22',
  },
  {
    name: '赵六',
    age: '23',
  },
];

var studentList = new Students('students', { data });

printBtn.onclick = function () {
  // 这里studnetList中调用了new Students,他在bind()中设置了studentInfo,这里的student是studentList.studentInfo的每个对象
  console.log(
    studentList.studentInfo.map((student) => {
      return [student.name, student.age];
    })
  );
};

这是一个双向绑定的例子。

不得不说,今天的收获满满,虽然没做什么,但是感觉对 js 的理解更深了一步。

2017-8-1

alert(1 && 2)会输出 2,知道这是为什么吗?

在使用 object.defineProperty 的时候要注意 descriptor 的定义。

//调用Object.defineProperty()方法时,如果不指定
var someOne = {};
someOne.name = 'coverguo';
console.log(Object.getOwnPropertyDescriptor(someOne, 'name'));
//输出 Object {value: "coverguo", writable: true, enumerable: true, configurable: true}

//直接在对象上定义的属性,这个特性默认值为为 true
var otherOne = {};
Object.defineProperty(otherOne, 'name', {
  value: 'coverguo',
});
console.log(Object.getOwnPropertyDescriptor(otherOne, 'name'));
//输出 Object {value: "coverguo", writable: false, enumerable: false, configurable: false}

2017-7-27

如果是对整个子组件应用 vue 过渡效果的时候,由于没有设置 position,它在进入和消失的时候会闪屏,因为他消失好像是从上往下,我应用的时候由于顶部有个 black 的 bar,所以看起来特别明显。但是设置了 position 后就没有这个闪屏的效果了。

2017-7-26

在 vue 中使用 addEventListener 的时候,不要直接绑定在 body 上,这样多次绑定同一个函数的话不会被覆盖,应该覆盖在相应的组件上,可以用$.el来获取当前的组件。

使用 v-html 插入 html 的时候,如果当前组件的 css 是 scoped 的,那么插入的 html 不会被 css 渲染,解决方法就是不要设置 scoped 属性。

vue 不会监测到一个对象新属性的增加与删除,解决方法是使用vm.$set(target, key, value)vm.$delete(target, key)

mixins 选项可以接受一个混合对象的数组。这些混合实例对象可以像正常的实例对象一样包含选项,他们将在Vue.extend() 里最终选择使用相同的选项合并逻辑合并。Mixin 钩子按照传入顺序依次调用,并在调用组件自身相同的钩子之前被调用。比如 mixins 里的 created()钩子在实例的 created()前调用,但是 mixins 的 mounted()钩子在实例的 created()钩子之后调用。

使用 directives 指令的时候,由于传入的参数只能是可读,当你要修改传入的参数的时候,使用 dataset 来修改。dataset 可以绑定 data 中的变量,但是在 directives 中修改 dataset 值的时候发现,他只能修改所绑定 el 的 dataset 的值,但是不会同时修改 data 中 dataset 所绑定的变量的值。比如:

<div v-a :data-name="bb">2222</div>

data () {
  return {
    bb: '22'
  }
}
directives: {
  a: {
    bind (el) {
      console.log(el.dataset.name)   // '22'
      console.log(el)     // <div v-a data-name="22">2222</div>
      el.dataset.name = 'bbb'
    }
  }
}

// <div v-a data-name="bb">2222</div>
执行完函数后发现div中的data-name等于bbb,但是data中的bb还是等于22

2017-7-24

因为要短时间重写 jsp 老项目,只能暂时用 iframe 来代替 jsp 的 include,在使用 iframe 的时候发现获取不到页面滚动条的数值,最后自己再看 window.parent 的时候发现可以在window.parent.document.scrollingElement中获取 scrollTop。

function totop() {
  var scroll_top = window.parent.document.scrollingElement;
  $(scroll_top).animate(
    {
      scrollTop: '0px',
    },
    400
  );
}

2017-7-19

除了使用 chrome 的 web server 扩展可以开本地服务,也可以使用 npm 的 serve 来开启服务,他的端口自动设为 5000,如果占用了就往上加。

2017-7-13

windows 下全局安装 mocha 的时候发现无法安装,主要是没有管理员权限,解决方法是以管理员权限运行 cmd,再进行全局安装。

设置 node.js 的全局安装路径:打开 git,输入npm config ls,修改 prefix 的值,npm config set prefix "xxxxxxxx"就 ok 了。

关于 istanbul 这个代码覆盖率工具,如果是在 window 上和 mocha 一起使用的时候,要注意不能直接打istanbul cover _mocha这个代码,因为 window 的路径问题,要使用istanbul cover node_modules/mocha/bin/_mocha,这个在官方说明上 usage on windows 也有提到。

学习了一些 makefile 文件的配置,不过因为在 window 系统上,所以刚开始使用的时候还是很懵比,怎么也用不了 make。后来在http://sourceforge.net/projects/mingw/files/latest/download?source=files上下载了 GNU 编译器,然后在后面的界面中选择基础配置和 C++编译器,将 MinGW 安装目录下的 bin 中的 mingw32-make.exe 重命名为 make.exe。接着就可以使用 make 指令了,网上有说要配置系统变量,不过我没配置好像也可以运行。之后我在 git 上尝试使用 make,但是始终告诉我 make commend not found,配置了用户变量也是提醒这个错误,我也不知道这个是什么原因 0.0。

2017-7-5

今天又遇到给后台传参要传数组的问题,发现还是不好传,所以以后还是直接传 json 对象比较好。今天还遇到表单提交的时候需要另外提交字段,如果后台用了 spring,解决方法是接受的时候增加一个参数来解析文字。

今天在使用 vuex 的时候发现,如果跳转的使用的是window.location.href,那么 vuex 中 store 保存的信息都会清空,这是因为window.location.href会刷新页面。所以在 vue 中需要跳转的时候最好是用this.$router.push()来进行跳转。

2017-7-4

一看发现好久没写心得了,最近也比较忙(其实都是借口,就是懒),今天电话面试了一家公司,感觉自己还不错,虽然有些问题没答上来,以及在厕所不敢大声说话。这次面试也学到了蛮多东西,主要是一些 js 基本的应用概念,太久没写原生 js 了,发现自己有点忘了,还是要常常温故,之前拉下的 js 高级教程的笔记也要开始补起来了。今天被问到一些 ie8 兼容性,MVVM,MVP,MVC 框架的区别等等,以前都记过但是忘了,今天重新记下笔记:

  1. ie8 关于 json 的兼容性,因为 ie8 不兼容 JSON.parse()的解析方法,所以可以使用 eval()方式,不过比较危险,因为 eval()在解析的时候会执行字符串中的代码。关于转成字符串,一个比较有趣的方式是将 JSON.js 改名为 JSON2.js,然后调用 JSON2.stringify()。
  2. MVC 框架是最早提出的,用户操作->View(负责接收用户的输入操作)->Controller(业务逻辑处理)->Model(数据持久化)->View(将结果反馈给 View)。MVP 是把 MVC 中的 Controller 换成了 Presenter(呈现),目的就是为了完全切断 View 跟 Model 之间的联系,由 Presenter 充当桥梁,做到 View-Model 之间通信的完全隔离。如果说 MVP 是对 MVC 的进一步改进,那么 MVVM 则是思想的完全变革。它是将“数据模型数据双向绑定”的思想作为核心,因此在 View 和 Model 之间没有联系,通过 ViewModel 进行交互,而且 Model 和 ViewModel 之间的交互是双向的,因此视图的数据的变化会同时修改数据源,而数据源数据的变化也会立即反应到 View 上。
    通过这一段话可以看出 MVVM 框架比较重要的进步是关于数据的控制,双重绑定保证了数据的一致性,而且在获取数据上也比通过 dom 操作简单很多。
  3. 关于 vue 的数据渲染逻辑:自定义 Render 函数,template 写法,el 写法。不过基本都是用 template。
  4. Vue 中 v-bind 和 v-on 的区别,v-bind 绑定的是变量,v-on 绑定的是方法,虽然知道怎么用但是一时间却说不上来这个。

现在总结一下这半个月学到的一些东西:

  1. 深层次的了解了 js 中的运算机制,比如++[[]][+[]]+[+[]] = 10(1+{})[4]= j等等(详见 justjavac 博客)
  2. 公司新项目的开发,其中用到了一个集合 input 和 select 功能的 div,就是能用够像 select 一样进行下拉列表展示,也可以在 select 框中手动输入数据,并自动 filter,主要的思路就是使用一个 div,下面包裹一个 ul 列表用来展示下拉列表。
  3. 学习了 es6 的编码规范
  4. 在使用 JQuery 的时候,注意使用变量的时候使用单引号将字符串隔开

昨天在听了部分 justjavac 的知乎 live 中的前端工程师的入门与进阶,我总结几个要点:

  1. 前端工程师也还是程序员,所以必须要写出比较好的代码,好的代码包括,代码的很强壮,比较容易维护,逻辑条理清晰
  2. 在学习新的框架的时候也不能忘了 js,css 等基本的东西,很多人都是学习了 3 个月的知识,然后重复使用了好多年,即使有多年经验,但是知识还是那么多

等有空我单独写一篇心得 0.0

2017-6-20

毕业典礼请假了半个多月,感慨很多,今天回来上班,那就好好工作学习。那么今天呢,主要学习了关于前端反向代理跨域来调用后端的接口,从而获得数据。

一开始我使用的是 ngnix,在配置 ngnix 的时候我也遇到了一些问题:

  1. 当修改了配置文件的时候,ngnix -reload 不管用,需要先 ngnix -quit,在 start ngnix。
  2. ngnix 监听的端口不能与项目的端口一样,会产生冲突。我一开始使用的是 vue 的的 8080 端口,而 ngnix 的端口是 80,所以一直显示 404。
  3. ngnix 的 location 有两种写法,一种是 rewrite,一种是直接在标记的代码结构前添加请求的网址。相比较后一种直接添加的比较方便。

因为使用了 vue,如果在项目外重新开 ngnix 的话,ngnix 就监听不了 vue 的项目了,后来发现 vue-cli 本来就有反向代理这个功能,就是在 config 中的 index.js,proxyTable 这个字段,适用方法如下:

proxyTable: {
  'api': {
    target: 'your url',
    changeOrigin: true
  }
}

当你在页面中调用 api/aa 的时候,返回的数据就是 your url/api/aa 接口的数据。

当然 proxyTable 也有 rewrite 的功能。

proxyTable: {
  'api': {
    target: 'your url',
    changeOrigin: true,
    pathRewrite: {
      '^/api': 'bb'
    }
  }
}

这样你在页面中调用 api/aa 的时候,返回的数据就是 your url/bb/aa 接口的数据。

2017-5-25

在知乎上看到一个话题,有个公司面试了一个 5 年经验的前端,结果那个面试者答不上原型链的基础知识,张口闭口就是 vue,react 等框架的实现原理等等,看着评论,大家的反应都不太一样,很多人说面试官要会发现面试者的优点,但是也有很多一批人说连 js 基础的知识了解的都一知半解,说句实话,感觉如今人们被工具支配的太恐怖了,以至于有了工具却不去了解基础知识了。我在平时的学习中一定要打好基础,努力加油。下面是哪个面试官出的一道题目:

输入 m,n,生成一个长度为 m 的每个数都为 n 的数组,如果不能用循环,可以使用递归:

function t3(m, n) {
  var arr = arguments[2] || []
  if (m > 0) {
    arr.push(n)
    t3(--m, n, arr)
  }
  return arr
}

或者使用new Array(m+1).join('n'),不过递归的方法没有循环来的性能高。

arguments 对象存储的是实际传递给函数的参数,而不局限于函数声明所定义的参数列表,而且不能显式创建 arguments 对象。

2017-5-11

今天在用 vue 获取 ajax 请求的数据的时候发现一个问题,当我在 created 发出 ajax 请求来获取数据,在 template 中调用的时候,会报错,原因是因为当我调用的时候,数据还没有请求到,所以会出现 undefined 的现象,解决方法是在请假数据的外面包一个 div,v-if="数据",这样当数据不存在的时候便不会执行下面的代码,当数据请求到了,会自动更新。

2017-5-10

如果要给后台传 json 字符串的话,比如 ajax 中的请求是data: Data,Data 是 json 字符串,那么需要在 ajax 中添加这句话,contentType: 'application/json; charset=utf-8',告诉服务器,我给你的 json 字符串,不然可能会出错。但是如果 json 字符串是写在 data 的对象里的话,则不需要写那句话,如:data: {jsonString: Data}

2017-4-26

try-catch 语句中如果后面跟着 finally 子句,那么无论 try 还是 catch 语句中的 return 语句都被毁忽略。finally 语句一定会被执行。

2017-4-21

因为 vue 中的 {{}} 是文本插值,所以 data 中的’\n’是不会再 html 中换行的,不过可以在换行的地方使用<br>进行换行,用 jq 的 html()显示

2017-4-19

当使用 bootstrap 的时候,如果子元素设置了 margin-top,父元素没有 clearfix 的话,可能会出现子元素的 margin-top 应用在了父元素上,即父元素有了 margin-top,而子元素还是和父元素紧紧的依靠在一起,解决方法是给父元素 clearfix,出现这个的原因是 bootstrap 中有自带的默认 float 属性。

2017-4-17

在 vue 中使用 datetimepicker 插件的时候,因为这个插件是依赖 jq 的,所以在使用这个插件的时候在先引入 Jq,第一种方法在 index.html 中引入 jquery.js,在 webpack 中加入全局变量$

externals: {
  jquery: 'window.$';
}

,然后再 index.html 中引入插件的 js 文件,在 vue 组件中 require jq,var $ = require('jquery'),就可以使用了。
第二种方法是在 index.html 中引入 jq 文件,然后再 vue 组件中 import 插件的 js,再 require jq,var $ = require('jquery'),就 ok 了

2017-4-10

当使用 CSS3 的 nth-child()的时候,千万要记住 body 是 html 的第二个子元素,所以 nth-child(2)会应用在 body 上。

CSS 的样式优先级:内联样式 > 内部样式 > 外部样式。

  1. JQ 的 addClass 是在外部文件或者内部样式中定义好的。
  2. JQ 的.css()是直接通过元素的 style 属性附加到元素上,属于内联样式。

所以.css()的优先级会高于 addClass,当你使用 JQ 实现点击、hover 样式转变的时候,最好使用 addClass 不容易出错。

2017-4-6

word-wrap 和 word-break 的区别:word-wrap 是用来决定单词内要不要断句,word-break 是用来决定怎么样断句。共同点就是当一个单词过长超过包裹的父级元素的宽度的时候,会另起一行,将单词断开。但是不同点是,word-wrap 会先另起一行,即将那个很长的单词另起一行显示,当那个单词太长一行都放不下的时候,再断开。但是 word-break 不会另起一行显示那个单词,而是接着前面的单词,当那行剩余的部分包裹不了的时候再换行。所以 word-break 比较节省空间。

2017-3-25

页面使用 border 创建一条线,怎么让它在 div 中竖直方向居中,除了用了 position,,可以使用 margin

2017-3-23

这几天学习了 vue.js

在 methods 中调用 ajax 的时候,一开始的 this 指向 vue 实例,但是 success 中的 this 指向 success 这个方法,如果要在 success 方法中调用 vue 实例中的数据,可以在 ajax 开头var self = this,那这个 self 就是 vue 实例。

2017-3-17

position:fixed 始终以 body 为父级元素,所以当 height 为 100%的时候就会覆盖整个页面,用来整页修改 css 很有用。

2017-3-15

今天遇到了一个问题,在写项目的时候发现动态生成的 48 个表单中,有一个表单的样式不对,然后今天自己就好好使用断点来查找问题,最后发现是传回来的数据的末尾是/,然后和>形成了闭合,所以产生了两个 tr。所以以后再使用 js 动态添加节点的时候,最好值和>之间空一个空格,就可以避免这个问题,然后,虽然这个问题很小,但是我比较算正式的使用了断点这个功能,感受了他的魅力!

2017-3-13

今天遇到一个错误,显示 Uncaught SyntaxError: Unexpected token o in JSON at position 1
查了一下资料,原因是接收到的 json 已经是对象了,所以不能再使用 JSON.parse()将之转换成对象。

2017-3-10

项目基本写完了,这几天都在看 JavaScript 高级程序设计,看了 BOM,DOM,客户端检测,感觉看的晕乎乎的,没有前面几章看到有兴趣,也许是因为这几张比较侧重实例,不过自己还是要好好啃完它,啃完就要准备开始学习 vue 了。

2017-3-8

昨天和今天主要在为原来的项目增加可爬的数据类型,其中有好几种很复杂的数据,数列对象各种包,这里写几个遇到的一些麻烦。

  1. input end 不规范基本是因为{}没有断好。
  2. 不要使用 if,if,else。应该使用 if,else if,else。
  3. 注意 input 和 textarea。
  4. 如果对象的属性是变量的时候,需要使用 obj[]来获取属性,必要的时候自己来构建一个 str。比如:str=”[parma”+1+”]”,obj[str]。这里的 str=[parma1]。
  5. 在写 ajax 的时候,如果 data 是一个 json 对象,可以在赋值的时候直接添加到 data 里,也可以全部赋值完后统一定义 data。
  6. 使用 JQ 通过变量来获取某个节点的值的时候,不能直接$(name div),应该使用 find,parent 等方法来获取。
  7. 注意使用 return false 的后果。如果在循环中使用 return false 会直接种植循环。其次,return 语句只能在函数中使用,起的地方使用会报 Illegal return statement 错误。
  8. 使用 Object.getOwnPropertyNames(a).length 可以获取对象,数组的长度。

2017-3-6

写完项目的所有接口,用了很多数组的方法,也在 js 写了很多动态创建 html 的代码,从刚开始的不会使用++到现在的比较熟练,感觉还是学到了很多。

2017-3-4

今天写了分页,动态的获取数据库里的信息,发现一开始自己写的太复杂,其实写起来很简单,也学到了怎么通过 this 获取 this 里面的 span 的内容。

$('>span', this).text();

2017-3-2

今天遇见输入 input 时只要点击空格键就会自动提交并刷新表单,解决方法是:

$('input').keydown(function (event) {
  if (event.keyCode == 13) return false;
});

这里的 keyCode==13 是代表回车键。

使用了 confirm(),在 confirm()中二次使用 ajax。

优化了项目中获取数据的表达式,感觉以后自己再写代码的时候要多注意代码的质量,考虑到可维护性,以及算法的优化。

2017-3-1

split(),join()用来数组和字符串的转换

学习了 BOM,window 对象,了解了 window.location 对象,并使用了其中的 href 和 search 的用在了自己的项目里。
使用了 window.open(),window.location.href 等等。

2017-2-28

JQ: focus()方法相当于 Javascript 中的 onfoucs()方法,作用是处理获得焦点的事件。
blue()方法相当于 Javascript 中的 onblur()方法,作用是处理失去焦点的事件。
offset()方法是获取元素在当前视窗的相对偏移。
scrollTop()和 scrollLeft()方法是获取元素的滚动条距顶端的距离和距左侧的距离。这两个方法也可以指定一个参数,控制元素的滚动条滚到到指定位置。

2017-2-27

JQ 的选择器,了解了选择和筛选的区别,children()是筛选子元素的,不会考虑其他后代元素,空格是选择后代的,&lt 是选择子元素的。

next()用于取得匹配元素后面紧邻的同辈元素。
prev()用于取得匹配元素前面紧邻的同辈元素。
siblings()用于取得匹配元素前后的所有同辈元素。(ps:这个函数很有用,可以用来点击按钮的时候改变 class)
closest()方法用于取得最近的匹配元素。

$('#CrawlerTable').delegate('.c-start', 'click', function () {
  var startId = $(this).parents('tr').attr('id');
  $.ajax({
    type: 'POST',
    xhrFields: {
      withCredentials: true,
    },
    crossDomain: true,
    url: dataUrl + '/SpyderPlatform/spyderInfo/start',
    dataType: 'json',
    data: {
      id: startId,
    },
    success: function (data) {
      if (data.result == true) {
        alert('启动成功');
        window.location.reload;
      } else {
        alert('启动失败或者已经启动');
      }
    },
  });
});

这里的 xhrFields 的是用来设置本地 XHR 对象的”名-值”映射,可以在需要时设置”withCredentials”为 true 二人执行跨域名请求。
而 crossDomain 为 true 为跨域请求,false 为同域请求。

2017-2-23

ajxx 的基本格式:

$('#mysave').click(function(){
            $.ajax({
                type:"POST",
                url:{},
                datatype:'json';
                async: false,
                error: function(request) {
                    alert("Connection error");
                },
                success: function(data) {
                    $("#").parent().html(data);
                }
            })
        })

这里的 data 是发送到服务器的数据,如果不是字符串,将自动转换为字符串格式。可以想要防止这种自动转换,可以使用 processData 选项。
dataType 是预期服务器返回的数据类型,如果不指定,JQuery 将自动根据 HTTP 包 MIME 信息返回 responseXML 或 responseText,并作为回调函数参数传递。可用的类型有:xml,html,json,script,jsonp,text。

jQuery 中 bind(),live(),delegate(),on()区别,点击这里.

今天在写项目的时候由于需要动态的创建文本,而文本里面有一些按钮来控制动态效果,如果只用 click,bind 事件来绑定这几个按钮的话,会发现浏览器没有报错也没有执行,查了资料请教了主管后才之后这个时候需要使用 deligate()方法,deligate()方法可以绑定未来的元素,比如脚本新创建的一些元素,而 live()和 deligate()的原理相同,只是 live()是绑定到元素上,而 deligate()可以通关过父级元素绑定到子元素。live()方法已经在 JQ1.7 版本被弃用,所以最后不要再使用,而以上的方法都是通过 on()方法来实现,所以 on()是万能的。

2017-2-22

margin-top,margin-left,margin-right,margin-bottom 是 body 中的属性
th,td 是表格的元素,与之对应的是
padding-top,padding-left,padding-right,padding-bottom,以及 vspace,hspace,cellspacing,cellPadding=0 等元素

今天学习了 input 框的一些属性:placeholder,required 等,还有一个 label 的 for,配合 input 的 id 使用。

JQ 的 clone(),index(),attr(),find(),after().

clone()可以解决一些需要动态创建相同格式的 html 元素。

index()这个函数也很有用,比如当我们点击一个按钮的时候,如果这类按钮有很多个,但是我们需要知道这个按钮的 index,比如点一个按钮,然后会使包裹他的父级 div 消失,因为都是同时出现的,只有合理的设置好 class,这个时候我们就可以通过按钮的 index 来得到 div 的 index,从而操控,但是如果我们要自己写,思路就是点击这个按钮的时候,最关键的就是得到这个按钮的 index,但是如果我们用普通的 js 来写就会有点麻烦,因为要得到按钮的 index,你首先需要遍历所有的这类按钮,然后给每个按钮一个 index,比如 btn.index = i ; 然后再次循环给每个按钮一个 click 事件,但是如果第二次循环给按钮一个 click 事件,那当我们点击这个按钮的时候就不会触发这个 click 函数,所以这时候我们就需要 index()这个函数来写。

就可以通过 index()解决。

 $(document).ready(function(){
 $(".Element").click(function(){        //添加按钮元素
    alert($(.Element).index($(this)[0]));
    })
 })

2017-2-18

这几天学了一点 vue.js,推荐一个比较轻松愉快的入门博客,点这里.

2017-2-15

轻松愉快的一天!一天都在面试,所以晚上放松一天,明天继续努力学习!(晚上找了一些之前几个问题的答案,已附上)

oh my god~!

刚才遇到了被占用端口的问题,通过这个才了解

原来也是我的福昕阅读器占用了我的端口~

2017-2-14

今天是情人节哟,不知道小伙伴们都有没有人陪,我今天又在图书馆呆了一天,今天学习了原型的继承,函数表达式,因为明天的面试,略微的看了 xml,json 和 ajax 技术,没有足够的时间让我准备心里还是有点难过的,晚上具体的看了些 ajax 的代码,希望明天面试顺利,加油!

2017-2-13

今天在图书馆泡了一天,收获的不是一般的多,看了很多 js 的书,大概写了以下一些问题。

  1. 正则表达式的概念
  2. 创建数组时用 new 和不用的区别
  3. new 操作符在 js 中的意义
  4. 如何提升 js 的性能
  5. 函数声明,函数表达式的区别,以及一些扩展(声明提前,变量提前)
  6. URL 和 URI 的区别

好了,现在来一个个的解决。

正则表达式的含义我用一张图来解释。

关于创建数组时用不用 new 需要知道两个概念,就是栈对象和堆对象,在 JS 高程里面的第 119 页详细的介绍了,如果用 new 来创建一个新数组的,那这个数组就是属于堆对象,他不会自动销毁,需要手动释放否则可能会出现内存泄露。如果不用 new 的话,那这就是一个栈对象,这个只存在一行代码的执行瞬间,然后立即被销毁。

new 操作符在 js 中的意思,当用 new 操作符创建一个空对象时,this 指向该空对象,而且这个对象会继承原函数的原型,属性和方法也会加入到 this 引用的对象中。新创建的对象由 this 引用,并且最后隐式的返回 this。

如何提升 js 问题,我发现一个比较不错的博客,推荐给大家,点这里

函数声明,函数表达式的区别其实很简单,就是函数声明的话函数名和函数体会提前,他属于那种随叫随到的,只要你需要了,我就到了。而函数表达式不会提前,他是属于那种只有你到我这里了,你才能见到我,不然休想。再翻其他资料的时候,也看了很多关于变量提前,以及关于这三者混合出现的一些情况。
这里简单的说下当变量声明和函数声明同时提升的时候(变量名和函数变量名相同),函数声明会覆盖变量声明,即最终那个变量显示的结果以函数为准,这个是变量声明而不是变量赋值。其中这个有一道比较好的题目,如果理解了这个应该对这几个名词的区别也了解的差不多了。点这里

URI 是统一资源标识符,而 URL 是统一资源定位符。因此,笼统地说,每个 URL 都是 URI,但不一定每个 URI 都是 URL。这是因为 URI 还包括一个子类,即统一资源名称 (URN),它命名资源但不指定如何定位资源。上面的 mailto、news 和 isbn URI 都是 URN 的示例。
二者的区别在于,URI 表示请求服务器的路径,定义这么一个资源。而 URL 同时说明要如何访问这个资源(http://)。

今天 so tired!这里非常欢迎有大神以及小白来找我讨论,如果我哪里有写错的话也非常愿意听你来给我指导,表示一直缺一个小伙伴一起进步呢,我的微信是 Yhspehy。快来找我玩哈!

blog comments powered by Disqus
目 录