Jonathan


fe

SchemaType

0 条评论 教程 无标签 Jonathan

SchemaType

可以直接声明 schema type 为某一种 type,或者赋值一个含有 type 属性的对象。

const schema1 = new Schema({
  test: String // `test` is a path of type String
})

const schema2 = new Schema({
  test: { type: String } // `test` is a path of type string
})

全部可用

  • required: 布尔值或函数 如果值为真,为此属性添加 required 验证器
  • default: 任何值或函数 设置此路径默认值。如果是函数,函数返回值为默认值
  • select: 布尔值 指定 query 的默认 projections
  • validate: 函数 adds a validator function for this property
  • get: 函数 使用 Object.defineProperty() 定义自定义 getter
  • set: 函数 使用 Object.defineProperty() 定义自定义 setter
  • alias: 字符串 仅mongoose >= 4.10.0。 为该字段路径定义虚拟值 gets/sets

索引相关

可以使用 schema type 选项定义MongoDB indexes。

  • index: 布尔值 是否对这个属性创建索引
  • unique: 布尔值 是否对这个属性创建唯一索引
  • sparse: 布尔值 是否对这个属性创建稀疏索引

String

  • lowercase: 布尔值 是否在保存前对此值调用 .toLowerCase()
  • uppercase: 布尔值 是否在保存前对此值调用 .toUpperCase()
  • trim: 布尔值 是否在保存前对此值调用 .trim()
  • match: 正则表达式 创建验证器检查这个值是否匹配给定正则表达式
  • enum: 数组 创建验证器检查这个值是否包含于给定数组

lowercase 在保存之前把字母都改成小写:

lowercase 属性只作用于字符串

const schema2 = new Schema({
  test: {
    type: String,
    lowercase: true // Always convert `test` to lowercase
  }
})

Number

  • min: 数值 创建验证器检查属性是否大于或等于该值
  • max: 数值 创建验证器检查属性是否小于或等于该值

Date

  • min: Date
  • max: Date

Mac软件下载网站

0 条评论 默认 无标签 Jonathan

Mac 软件下载网站

这里主要是推荐一些软件下载的网站,还有一些 Mac OSX 软件分享网站

正版/介绍

MacUpdate:https://www.macupdate.com/
App Shopper:http://appshopper.com/
类似于 iOS 上 Cydia 一样的第三方软件商店:http://hack-store.com
少数派:http://sspai.com/tag/Mac
Mac 玩儿法:http://www.waerfa.com Freeware

盗版软件下载网站黑名单

上面有大量的开源软件或者免费软件,拒绝盗版从我做起,下面被删除的网站提供大量破解软件下载,欢迎大家监督它们。

玩转苹果:http://www.ifunmac.com
Mac 软件下载站:http://www.pshezi.com
MacPeers:http://www.macpeers.com
Mac 志:http://www.isofts.org
Mac 软件分享:http://www.waitsun.com
Mac 破解软件:https://www.macappstore.net/
卡卡源:http://www.kkroot.com/
AppKed:http://www.macbed.com
苹果软件园:http://www.maczapp.com
马可菠萝:http://www.macbl.com/
MacSky 苹果软件园:http://www.macsky.net/
极致分享:https://alltoshare.com/
麦克社:http://www.macshe.com/
appaddict:https://www.appaddict.org/
未来软件园:http://www.orsoon.com/
Softasm:https://softasm.com/
Mac 精品软件:http://xclient.info/
MacPeers:https://www.macpeers.com
Mac 毒:https://www.macdo.cn
Macx:https://www.macx.cn/
腾牛网:http://www.qqtn.com/mac/r_17_1.html
未来软件园:http://www.orsoon.com/mac/
威锋网:https://bbs.feng.com/forum.php?mod=forumdisplay&fid=19&page=


iconfont 图标当前页面一键加入购物车

0 条评论 教程 教程 Jonathan

图标当前页面一键加入购物车

const iconList = document.querySelectorAll('#magix_vf_main > div.wrap > div.page-collection-detail-wrap > div.collection-detail > ul li')

for(icon of iconList) {
  icon.querySelector('div.icon-cover > span.cover-item.iconfont.cover-item-line.icon-gouwuche1').click()
}

图标名数组(项目页)

const iconList = document.querySelectorAll('#J_project_detail > div.project-iconlist > ul li')

let icons = {}
for(icon of iconList) {
  icons[icon.querySelector('span.icon-name').innerText] = icon.querySelector('span.icon-code.icon-code-show').innerText
}

npm包管理命令

1 条评论 总结 教程 无标签 Jonathan

[toc]

发布npm包

注册npm

使用npm 命令注册:npm adduser

Unable to authenticate, need:Basic // 用户名已被注册

账号登录

npm login

发布包,上传到npm包服务器

npm publish

注意:如果报错:'You do not have permission to publish "mypackage1". Are you logged in as the correct user?'

表示包’mypackage1‘已经在包管理器已经存在被别人用了,需要更该包名称

注意:如果发布时报错:‘no_perms Private mode enable, only admin can publish this module:’

表示当前不是原始镜像,可能用的是其他镜像,如淘宝镜像,

要切换回原始的npm镜像,命令:npm config set registry https://registry.npmjs.org/,如果用了nrm工具,使用命令:nrm use npm 切换

更新包

  1. npm version patch 该命令在原来的版本上自动加1,实际上是将package.json文件中的version值修改了。

  2. npm publish

删除包

删除指定的版本

npm unpublish 包名@版本号

删除整个包

npm unpublish 包名 --force


前端团队代码评审 CheckList 清单

0 条评论 总结 Vue 无标签 Jonathan

前端团队代码评审 CheckList 清单

前言

前端团队有评审代码的要求,但由于每个开发人员的水平不同,技术关注点不同,所以对代码评审的关注点不同,为了保证代码质量,团队代码风格统一,特此拟定一份《前端团队代码评审 CheckList 清单》,这样代码评审人员在评审代码时,可以参照这份清单,对代码进行评审。从而辅助整个团队提高代码质量、统一代码规范。如果你的团队还没有这么一份代码评审 CheckList 清单,也许这正是你需要的;如果你的团队已经有了代码评审参照标准,这份清单也许能起到锦上添花的效果。

一、代码静态检查工具

  1. 1、使用 eslint 工具对 javascript 代码进行检查
  2. 检查的规范继承自 eslint-config-standard 检验规则,具体的规则介绍参照链接:https://cn.eslint.org/docs/rules/ ,这里及以下部分不再重复介绍这些检验规则。
  3. 2、使用 stylelint 工具对 css 样式代码进行检查
  4. 检查的规范继承自 stylelint-config-standard 检验规则,具体的规则介绍参照链接:https://www.npmjs.com/package/stylelint-config-standard ,这里及以下部分不再重复介绍这些检验规则。

二、命名规范

  1. 1、JS 采用 Camel Case 小驼峰式命名
    推荐:
studentInfot
  1. 2、避免名称冗余
// 推荐:
const Car = {
  make: "Honda",
  model: "Accord",
  color: "Blue"
};

// 不推荐:

const Car = {
  carMake: "Honda",
  carModel: "Accord",
  carColor: "Blue"
};
  1. 3、CSS 类名采用 BEM 命名规范
// 推荐:

.block__element{} 
.block--modifier{}
  1. 4、命名符合语义化
    命名需要符合语义化,如果函数命名,可以采用加上动词前缀:

动词 含义
can 判断是否可执行某个动作
has 判断是否含有某个值
is 判断是否为某个值
get 获取某个值
set 设置某个值

// 推荐:

//是否可阅读 
function canRead(){ 
   return true; 
} 
//获取姓名 
function getName{
   return this.name 
} 

三、JS 推荐写法

  1. 1、每个常量都需命名
    每个常量应该命名,不然看代码的人不知道这个常量表示什么意思。
// 推荐:

const COL_NUM = 10;
let row = Math.ceil(num/COL_NUM);

// 不推荐:

let row = Math.ceil(num/10);
  1. 2、推荐使用字面量
    创建对象和数组推荐使用字面量,因为这不仅是性能最优也有助于节省代码量。
// 推荐:

let obj = {   
     name:'tom',     
     age:15,     
     sex:'男' 
} 
// 不推荐:

let obj = {};
obj.name = 'tom';
obj.age = 15;
obj.sex = '男';
  1. 3、对象设置默认属性的推荐写法
// 推荐:

const menuConfig = {
  title: "Order",
  // User did not include 'body' key
  buttonText: "Send",
  cancellable: true
};

function createMenu(config) {
  config = Object.assign(
    {
      title: "Foo",
      body: "Bar",
      buttonText: "Baz",
      cancellable: true
    },
    config
  );

  // config now equals: {title: "Order", body: "Bar", buttonText: "Send", cancellable: true}
  // ...
}

createMenu(menuConfig);

//  不推荐:

const menuConfig = {
  title: null,
  body: "Bar",
  buttonText: null,
  cancellable: true
};

function createMenu(config) {
  config.title = config.title || "Foo";
  config.body = config.body || "Bar";
  config.buttonText = config.buttonText || "Baz";
  config.cancellable =
    config.cancellable !== undefined ? config.cancellable : true;
}

createMenu(menuConfig);
  1. 4、将对象的属性值保存为局部变量
    对象成员嵌套越深,读取速度也就越慢。所以好的经验法则是:如果在函数中需要多次读取一个对象属性,最佳做法是将该属性值保存在局部变量中,避免多次查找带来的性能开销。
// 推荐:

let person = {
    info:{
        sex:'男'
    }
}
function  getMaleSex(){
    let sex = person.info.sex;
    if(sex === '男'){
        console.log(sex)
    }
} 
//  不推荐:

let person = {
    info:{
        sex:'男'
    }
}
function  getMaleSex(){
    if(person.info.sex === '男'){
        console.log(person.info.sex)
    }
} 
  1. 5、字符串转为整型
    当需要将浮点数转换成整型时,应该使用Math.floor()或者Math.round(),而不是使用parseInt()将字符串转换成数字。Math 是内部对象,所以Math.floor()其实并没有多少查询方法和调用时间,速度是最快的。
// 推荐:

let num = Math.floor('1.6');
//  不推荐:

let num = parseInt('1.6');
  1. 6、函数参数
    函数参数越少越好,如果参数超过两个,要使用 ES6的解构语法,不用考虑参数的顺序。
// 推荐:

function createMenu({ title, body, buttonText, cancellable }) {
  // ...
}

createMenu({
  title: 'Foo',
  body: 'Bar',
  buttonText: 'Baz',
  cancellable: true
});

//  不推荐:

function createMenu(title, body, buttonText, cancellable) {
  // ...
}
  1. 7、使用参数默认值
    使用参数默认值 替代 使用条件语句进行赋值。
// 推荐:

function createMicrobrewery(name = "Hipster Brew Co.") {
  // ...
}

//  不推荐:

function createMicrobrewery(name) {
  const breweryName = name || "Hipster Brew Co.";
  // ...
}
  1. 8、最小函数准则
    这是一条在软件工程领域流传久远的规则。严格遵守这条规则会让你的代码可读性更好,也更容易重构。如果违反这个规则,那么代码会很难被测试或者重用 。
  2. 9、不要写全局方法
    在 JavaScript 中,永远不要污染全局,会在生产环境中产生难以预料的 bug。举个例子,比如你在 Array.prototype 上新增一个 diff 方法来判断两个数组的不同。而你同事也打算做类似的事情,不过他的 diff 方法是用来判断两个数组首位元素的不同。很明显你们方法会产生冲突,遇到这类问题我们可以用 ES2015/ES6 的语法来对 Array 进行扩展。
// 推荐:

class SuperArray extends Array {
  diff(comparisonArray) {
    const hash = new Set(comparisonArray);
    return this.filter(elem => !hash.has(elem));        
  }
}
//  不推荐:

Array.prototype.diff = function diff(comparisonArray) {
  const hash = new Set(comparisonArray);
  return this.filter(elem => !hash.has(elem));
};
  1. 10、推荐函数式编程
    函数式变编程可以让代码的逻辑更清晰更优雅,方便测试。
// 推荐:

const programmerOutput = [
  {
    name: 'Uncle Bobby',
    linesOfCode: 500
  }, {
    name: 'Suzie Q',
    linesOfCode: 1500
  }, {
    name: 'Jimmy Gosling',
    linesOfCode: 150
  }, {
    name: 'Gracie Hopper',
    linesOfCode: 1000
  }
];
let totalOutput = programmerOutput
  .map(output => output.linesOfCode)
  .reduce((totalLines, lines) => totalLines + lines, 0)

//  不推荐:

 const programmerOutput = [
  {
    name: 'Uncle Bobby',
    linesOfCode: 500
  }, {
    name: 'Suzie Q',
    linesOfCode: 1500
  }, {
    name: 'Jimmy Gosling',
    linesOfCode: 150
  }, {
    name: 'Gracie Hopper',
    linesOfCode: 1000
  }
];

let totalOutput = 0;

for (let i = 0; i < programmerOutput.length; i++) {
  totalOutput += programmerOutput[i].linesOfCode;
}
  1. 11、使用多态替换条件语句
    为了让代码更简洁易读,如果你的函数中出现了条件判断,那么说明你的函数不止干了一件事情,违反了函数单一原则 ;并且绝大数场景可以使用多态替代
// 推荐:

class Airplane {
  // ...
}
// 波音777
class Boeing777 extends Airplane {
  // ...
  getCruisingAltitude() {
    return this.getMaxAltitude() - this.getPassengerCount();
  }
}
// 空军一号
class AirForceOne extends Airplane {
  // ...
  getCruisingAltitude() {
    return this.getMaxAltitude();
  }
}
// 赛纳斯飞机
class Cessna extends Airplane {
  // ...
  getCruisingAltitude() {
    return this.getMaxAltitude() - this.getFuelExpenditure();
  }
}

//  不推荐:

class Airplane {
  // ...

  // 获取巡航高度
  getCruisingAltitude() {
    switch (this.type) {
      case '777':
        return this.getMaxAltitude() - this.getPassengerCount();
      case 'Air Force One':
        return this.getMaxAltitude();
      case 'Cessna':
        return this.getMaxAltitude() - this.getFuelExpenditure();
    }
  }
}
  1. 12、定时器是否清除
    代码中使用了定时器 setTimeout 和 setInterval,需要在不使用时进行清除。

四、SCSS 推荐写法

  1. 1、变量 $ 使用
    利用scss中的变量配置,可以进行项目的颜色、字体大小统一更改(换肤),有利于后期项目的维护。
// 推荐:

$--color-success: #67C23A;
$--color-warning: #E6A23C;
$--color-danger: #F56C6C;
$--color-info: #909399;
  1. 2、@import 导入样式文件
    scss中的@import规则在生成css文件时就把相关文件导入进来。这意味着所有相关的样式被归纳到了同一个css文件中,而无需发起额外的下载请求,在构建我们自己的组件库时推荐使用。
@import "./base.scss";
@import "./pagination.scss";
@import "./dialog.scss";
@import "./autocomplete.scss";
@import "./dropdown.scss";
@import "./dropdown-menu.scss";
  1. 3、局部文件命名的使用
    scss局部文件的文件名以下划线开头。这样,scss就不会在编译时单独编译这个文件输出css,而只把这个文件用作导入。
  1. 4、父选择器标识符 & 实现BEM 命令规范
    scss的嵌套和父选择器标识符 & 能解决BEM命名的冗长,且使样式可读性更高。
// 推荐:

.el-input {
  display: block;
  &__inner {
     text-align: center;
  }
}
  1. 5、@mixin 混合器的使用
    mixin混合器用来实现大段样式的重用,减少代码的冗余,且支持传参。
@mixin button-size($padding-vertical, $padding-horizontal, $font-size, $border-radius) {
  padding: $padding-vertical $padding-horizontal;
  font-size: $font-size;
  border-radius: $border-radius;
  &.is-round {
    padding: $padding-vertical $padding-horizontal;
  }
}

  @include m(medium) {
    @include button-size($--button-medium-padding-vertical, $--button-medium-padding-horizontal, $--button-medium-font-size, $--button-medium-border-radius);   
  }

  @include m(small) {
    @include button-size($--button-small-padding-vertical, $--button-small-padding-horizontal, $--button-small-font-size, $--button-small-border-radius);
  } 
  1. 6、@extend 指令的使用
    (1)使用@extend产生 DRY CSS风格的代码(Don't repeat yourself)

(2)@mixin主要的优势就是它能够接受参数。如果想传递参数,你会很自然地选择@mixin而不是@extend

// 推荐:

.common-mod {
  height: 250px;
  width: 50%;
  background-color: #fff;
  text-align: center;
}

 .show-mod--right {
   @extend .common-mod;
   float: right;
 }

.show-mod--left {
   @extend .common-mod;
}
  1. 7、#{} 插值的使用
    插值能动态定义类名的名称,当有两个页面的样式类似时,我们会将类似的样式抽取成页面混合器,但两个不同的页面样式的命名名称根据BEM命名规范不能一样,这时我们可使用插值进行动态命名。
// 推荐:

@mixin home-content($class) {
  .#{$class} {
    position: relative;
    background-color: #fff;
    overflow-x: hidden;
    overflow-y: hidden;

    &--left {
      margin-left: 160px;
    }

    &--noleft {
      margin-left: 0;
    }
  }
}
  1. 8、each遍历、map数据类型、@mixin/@include混合器、#{}插值 结合使用
    可通过each遍历、map数据类型、@mixin/@include混合器、#{} 插值 结合使用,从而减少冗余代码,使代码更精简。

推荐:

$img-list: (
   (xlsimg, $papers-excel),
   (xlsximg, $papers-excel),
   (gifimg, $papers-gif),
   (jpgimg, $papers-jpg),
   (mp3img, $papers-mp3),
   (mp4img, $papers-mp3),
   (docimg, $papers-word),
   (docximg, $papers-word),
   (rarimg, $papers-zip),
   (zipimg, $papers-zip),
   (unknownimg, $papers-unknown)
);

@each $label, $value in $img-list {
  .com-hwicon__#{$label} {
    @include commonImg($value);
  }
}
  1. 9、scss 自带函数的应用
    scss自带函数的应用,从而进行相关的计算,例如 mix函数的使用如下。
 @include m(text) {
    &:hover,
    &:focus {
      color: mix($--color-white, $--color-primary, $--button-hover-tint-percent);
      border-color: transparent;
      background-color: transparent;
    }

    &:active {
      color: mix($--color-black, $--color-primary, $--button-active-shade-percent);
      border-color: transparent;
      background-color: transparent;
    }
}
  1. 10、gulp-sass的使用
    gulp-sass插件能实时监测scss代码检查其语法错误并将其编译成css代码,帮助开发人员检查scss语法的准确性,且其是否符合我们的预期,相关配置如下:
gulp.task('gulpsass', function() {
  return gulp.src('src/style/components/hwIcon.scss')
    .pipe(gulpsass().on('error', gulpsass.logError))
    .pipe(gulp.dest('src/style/dest'));
});

gulp.task('watch', function() {
  gulp.watch('src/style/components/hwIcon.scss', ['gulpsass']);
});

五、Vue 推荐写法

  1. 1、组件名为多个单词
    我们开发过程中自定义的组件的名称需要为多个单词,这样做可以避免跟现有的以及未来的HTML元素相冲突,因为所有的 HTML 元素名称都是单个单词的。
// 推荐:

Vue.component('todo-item', {
  // ...
})

export default {
  name: 'TodoItem',
  // ...
}

//  不推荐:

Vue.component('todo', {
  // ...
})

export default {
  name: 'Todo',
  // ...
}
  1. 2、组件的 data 必须是一个函数
    当在组件中使用 data 属性的时候 (除了 new Vue 外的任何地方),它的值必须是返回一个对象的函数。 因为如果直接是一个对象的话,子组件之间的属性值会互相影响。
// 推荐:

export default {
  data () {
    return {
      foo: 'bar'
    }
  }
}

//  不推荐:

export default {
  data: {
    foo: 'bar'
  }
}
  1. 3、Prop定义应该尽量详细
  2. 的定义应该尽量详细,至少需要指定其类型。
// 推荐:

props: {
  status: String
}

// 更好的做法!
props: {
  status: {
    type: String,
    required: true,
    validator: function (value) {
      return [
        'syncing',
        'synced',
        'version-conflict',
        'error'
      ].indexOf(value) !== -1
    }
  }
}

//  不推荐:

props: ['status'] 
  1. 4、为 v-for 设置键值
    v-for 中总是有设置 key 值。在组件上总是必须用 key 配合 v-for,以便维护内部组件及其子树的状态。
// 推荐:

<ul>
  <li
    v-for="todo in todos"
    :key="todo.id">
    {{ todo.text }}
  </li>
</ul>
//  不推荐:

<ul>
  <li v-for="todo in todos">
    {{ todo.text }}
  </li>
</ul>
  1. 5、完整单词的组件名
    组件名应该倾向于完整单词而不是缩写,编辑器中的自动补全已经让书写长命名的代价非常之低了,而其带来的明确性却是非常宝贵的。不常用的缩写尤其应该避免。
// 推荐:

components/ 
|- StudentDashboardSettings.vue 
|- UserProfileOptions.vue 

//  不推荐:

components/ 
|- SdSettings.vue 
|- UProfOpts.vue 
  1. 6、多个特性元素的每个特性分行
    在 JavaScript 中,用多行分隔对象的多个属性是很常见的最佳实践,因为这样更易读。
// 推荐:

<MyComponent
  foo="a"
  bar="b"
  baz="c"
/>

//  不推荐:

<MyComponent foo="a" bar="b" baz="c"/> 
  1. 7、模板中简单的表达式
    组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。复杂表达式会让你的模板变得不那么声明式。我们应该尽量描述应该出现的是什么,而非如何计算那个值。而且计算属性和方法使得代码可以重用。
// 推荐:

<!-- 在模板中 -->
{{ normalizedFullName }}

// 复杂表达式已经移入一个计算属性
computed: {
  normalizedFullName: function () {
    return this.fullName.split(' ').map(function (word) {
      return word[0].toUpperCase() + word.slice(1)
    }).join(' ')
  }
}

//  不推荐:

{{
  fullName.split(' ').map(function (word) {
    return word[0].toUpperCase() + word.slice(1)
  }).join(' ')
}}
  1. 8、简单的计算属性
    应该把复杂计算属性分割为尽可能多的更简单的属性。
// 推荐:

computed: {
  basePrice: function () {
    return this.manufactureCost / (1 - this.profitMargin)
  },
  discount: function () {
    return this.basePrice * (this.discountPercent || 0)
  },
  finalPrice: function () {
    return this.basePrice - this.discount
  }
}

//  不推荐:

computed: {
  price: function () {
    var basePrice = this.manufactureCost / (1 - this.profitMargin)
    return (
      basePrice -
      basePrice * (this.discountPercent || 0)
    )
  }
}
  1. 9、指令缩写
    指令推荐都使用缩写形式,(用 : 表示 v-bind: 、用 @ 表示 v-on: 和用 # 表示 v-slot:)。
// 推荐:

<input
  @input="onInput"
  @focus="onFocus"
>

//  不推荐:

<input
  v-on:input="onInput"
  @focus="onFocus"
>
  1. 10、标签顺序保持一致
    单文件组件应该总是让标签顺序保持为 <template> 、<script>、 <style> 。
// 推荐:

<!-- ComponentA.vue -->

<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>

//  不推荐:

<!-- ComponentA.vue -->

<template>...</template>
<style>/* ... */</style>
<script>/* ... */</script>
  1. 11、组件之间通信
    父子组件的通信推荐使用 prop和 emit ,而不是this.$parent或改变 prop;

兄弟组件之间的通信推荐使用 EventBus(on),而不是滥用 vuex;

祖孙组件之间的通信推荐使用listeners 或 provide / inject(依赖注入) ,而不是滥用 vuex;

  1. 12、页面跳转数据传递
    页面跳转,例如 A 页面跳转到 B 页面,需要将 A 页面的数据传递到 B 页面,推荐使用 路由参数进行传参,而不是将需要传递的数据保存 vuex,然后在 B 页面取出 vuex的数据,因为如果在 B 页面刷新会导致 vuex 数据丢失,导致 B 页面无法正常显示数据。
// 推荐:

let id = ' 123';
this.$router.push({name: 'homeworkinfo', query: {id:id}}); 
    1. 13、script 标签内部声明顺序
    1. 标签内部的声明顺序如下:
    data > prop > components > filter > computed >  watch > 
    钩子函数(钩子函数按其执行顺序)> methods
    1. 14、计算属性 VS 方法 VS 侦听器
      (1)推荐使用计算属性:计算属性基于响应式依赖进行缓存,只在相关响应式依赖发生改变时它们才会重新求值;相比之下,每次调用方法都会再次执行方法;

    (2)推荐使用计算属性:而不是根据 Watch 侦听属性,进行回调; 但是有计算属性做不到的:当需要在数据变化时执行异步或开销较大的操作时,侦听器是最有用的。

    1. 15、v-if VS v-show
      v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。 v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

    相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的属性 display 进行切换。

    // 推荐:

    如果运行时,需要非常频繁地切换,推荐使用 v-show 比较好;如果在运行时,条件很少改变,则推荐使用 v-if 比较好。

    六、团队其它规范

    6.1、尽量不手动操作 DOM
    因为团队现在使用 vue 框架,所以在项目开发中尽量使用 vue 的特性去满足我们的需求,尽量(不到万不得已)不要手动操作DOM,包括:增删改dom元素、以及更改样式、添加事件等。

    6.2、删除弃用代码
    很多时候有些代码已经没有用了,但是没有及时去删除,这样导致代码里面包括很多注释的代码块,好的习惯是提交代码前记得删除已经确认弃用的代码,例如:一些调试的console语句、无用的弃用代码。

    6.3、保持必要的注释
    代码注释不是越多越好,保持必要的业务逻辑注释,至于函数的用途、代码逻辑等,要通过语义化的命令、简单明了的代码逻辑,来让阅读代码的人快速看懂。

    作者:我是你的超级英雄
    链接:https://juejin.im/post/5d1c6550518825330a3bfa01
    来源:掘金


    node.js

    0 条评论 教程 无标签 Jonathan

    [toc]

    url

    使用 url 的 parse 方法

    // 1. 引入 url 模块
    var url = require("url");
    
    // 2. 引入 http 模块
    var http = require("http");
    
    // 3. 用 http 模块创建服务
    /**
     * req 获取 url 信息 (request)
     * res 浏览器返回响应信息 (response)
     */
    http.createServer(function (req, res) {
    
      // 4. 获取服务器请求
      /**
       * 访问地址是:http://localhost:3000/?userName=jsliang&userAge=23
       * 如果你执行 console.log(req.url),它将执行两次,分别返回下面的信息:
       * /  ?userName=jsliang&userAge=23
       * /  /favicon.ico
       * 这里为了防止重复执行,所以排除 req.url == /favicon.ico 的情况
       */
      if(req.url != "/favicon.ico") {
    
        // 5. 使用 url 的 parse 方法
        /**
         * parse 方法需要两个参数:
         * 第一个参数是地址
         * 第二个参数是 true 的话表示把 get 传值转换成对象
         */ 
        var result = url.parse(req.url, true);
        console.log(result);
        /**
         * Url {
         *   protocol: null,
         *   slashes: null,
         *   auth: null,
         *   host: null,
         *   port: null,
         *   hostname: null,
         *   hash: null,
         *   search: '?userName=jsliang&userAge=23',
         *   query: { userName: 'jsliang', userAge: '23' },
         *   pathname: '/',
         *   path: '/?userName=jsliang&userAge=23',
         *   href: '/?userName=jsliang&userAge=23' }
         */
    
        console.log(result.query.userName); // jsliang
    
        console.log(result.query.userAge); // 23
      }
    
      // 设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8
      res.writeHead(200, {
        "Content-Type": "text/html;charset=UTF-8"
      });
    
      // 往页面打印值
      res.write('<h1 style="text-align:center">Hello NodeJS</h1>');
    
      // 结束响应
      res.end();
    
    }).listen(3000);
    
    

    输出 url

    console.log(url);
    
    { 
      Url: [Function: Url],
      parse: [Function: urlParse], // 获取地址信息
      resolve: [Function: urlResolve], // 追加或者替换地址
      resolveObject: [Function: urlResolveObject],
      format: [Function: urlFormat], // 逆向 parse,根据地址信息获取原 url 信息
      URL: [Function: URL],
      URLSearchParams: [Function: URLSearchParams],
      domainToASCII: [Function: domainToASCII],
      domainToUnicode: [Function: domainToUnicode] 
    }
    

    commonJS

    fs 文件管理

    1. fs.stat 检测是文件还是目录
    2. fs.media 创建目录
    3. fs.writeFile 创建写入文件
    4. fs.appendFile 追加文件
    5. fs.readFile 读取文件
    6. fs.readdir 读取目录
    7. fs.rename 重命名
    8. fs.rmdir 删除目录
    9. fs.unlink 删除文件

    通过 fs.stat 检查一个读取的是文件还是目录:

    //  1. fs.stat
    let fs = require('fs');
    fs.stat('index.js', (error, stats) => {
      if(error) {
        console.log(error);
        return false;
      } else {
        console.log(stats);
        /**
         * Console:
         * Stats {
         *  dev: 886875,
         *  mode: 33206,
         *  nlink: 1,
         *  uid: 0,
         *  gid: 0,
         *  rdev: 0,
         *  blksize: undefined,
         *  ino: 844424931461390,
         *  size: 284,
         *  blocks: undefined,
         *  atimeMs: 1542847157494,
         *  mtimeMs: 1543887546361.2158,
         *  ctimeMs: 1543887546361.2158,
         *  birthtimeMs: 1542847157493.663,
         *  atime: 2018-11-22T00:39:17.494Z,
         *  mtime: 2018-12-04T01:39:06.361Z,
         *  ctime: 2018-12-04T01:39:06.361Z,
         *  birthtime: 2018-11-22T00:39:17.494Z }
         */
    
        console.log(`文件:${stats.isFile()}`); 
        // Console:文件:true
    
        console.log(`目录:${stats.isDirectory()}`); 
        // Console:目录:false
    
        return false;
      }
    })
    
    

    通过 fs.mkdir 创建目录:

    //  2. fs.mkdir
    let fs = require('fs');
    
    /**
     * 接收参数
     * path - 将创建的目录路径
     * mode - 目录权限(读写权限),默认 0777
     * callback - 回调,传递异常参数 err
     */
    fs.mkdir('css', (err) => {
      if(err) {
        console.log(err);
        return false;
      } else {
        console.log("创建目录成功!");
        // Console:创建目录成功!
      }
    })
    
    

    通过 fs.rmdir 删除目录

    //  8. fs.rmdir
    let fs = require('fs');
    
    /**
     * 接收参数
     * path - 将创建的目录路径
     * mode - 目录权限(读写权限),默认 0777
     * callback - 回调,传递异常参数 err
     */
    fs.rmdir('css', (err) => {
      if(err) {
        console.log(err);
        return false;
      } else {
        console.log("创建目录成功!");
        // Console:创建目录成功!
      }
    })
    
    

    通过 fs.writeFile 来创建写入文件:

    //  3. fs.writeFile
    let fs = require('fs');
    
    /**
     * filename (String) 文件名称
     * data (String | Buffer) 将要写入的内容,可以是字符串或者 buffer 数据。
     * · encoding (String) 可选。默认 'utf-8',当 data 是 buffer 时,该值应该为 ignored。
     * · mode (Number) 文件读写权限,默认 438。
     * · flag (String) 默认值 'w'。
     * callback { Function } 回调,传递一个异常参数 err。
     */
    fs.writeFile('index.js', 'Hello jsliang', (err) => {
      if(err) {
        console.log(err);
        return false;
      } else {
        console.log('写入成功!');
      }
    })
    
    

    使用 fs.unlink 进行文件的删除

    使用 fs.appendFile 文件追加

    //  4. fs.appendFile
    let fs = require('fs');
    
    fs.appendFile('index.js', '这段文本是要追加的内容', (err) => {
      if(err) {
        console.log(err);
        return false;
      } else {
        console.log("追加成功");
      }
    })
    
    
    fs.readFile 读取文件
    fs.readdir 读取目录
    let fs = require('fs');
    
    // 5. fs.readFile
    fs.readFile('index.js', (err, data) => {
      if(err) {
        console.log(err);
        return false;
      } else {
        console.log("读取文件成功!");
        console.log(data);
        // Console:
        // 读取文件成功!
        // <Buffer 48 65 6c 6c 6f 20 6a 73 6c 69 61 6e 67 e8 bf 99 e6 ae b5 e6 96 87 e6 9c ac e6 98 af e8 a6 81 e8 bf bd e5 8a a0 e7 9a 84 e5 86 85 e5 ae b9>
      }
    })
    
    // 6. fs.readdir 读取目录
    fs.readdir('node_modules', (err, data) => {
      if(err) {
        console.log(err);
        return false;
      } else {
        console.log("读取目录成功!");
        console.log(data);
        // Console:
        // 读取目录成功!
        // [ '03_tool-multiply.js', 'jsliang-module' ]
      }
    })
    
    

    fs.rename 重命名了

    let fs = require('fs');
    
    // 7. fs.rename 重命名
    fs.rename('index.js', 'jsliang.js', (err) => {
      if(err) {
        console.log(err);
        return false;
      } else {
        console.log("重命名成功!");
      }
    })
    
    

    fs.rename 还有更劲爆的功能:剪切

    let fs = require('fs');
    
    // 7. fs.rename 重命名
    fs.rename('jsliang.js', 'node_modules/jsliang.js', (err) => {
      if(err) {
        console.log(err);
        return false;
      } else {
        console.log("剪切成功!");
      }
    })
    
    

    fs流

    // 新建 fs
    const fs = require('fs');
    // 流的方式读取文件
    let fileReadStream = fs.createReadStream('index.js');
    // 读取次数
    let count = 0;
    // 保存数据
    let str = '';
    // 开始读取
    fileReadStream.on('data', (chunk) => {
      console.log(`${++count} 接收到:${chunk.length}`);
      // Console:1 接收到:30
      str += chunk;
    })
    // 读取完成
    fileReadStream.on('end', () => {
      console.log("——结束——");
      console.log(count);
      console.log(str);
    
      // Console:——结束——
      // 1
      // console.log("Hello World!");
    })
    // 读取失败
    fileReadStream.on('error', (error) => {
      console.log(error);
    })
    
    

    在这里,我们通过 fs 模块的 createReadStream 创建了读取流,然后读取文件 index.js,从而最后在控制台输出了:

    1 接收到:259
    ——结束——
    1
    console.log("尽信书,不如无书;尽看代码,不如删掉这些文件。");
    console.log("尽信书,不如无书;尽看代码,不如删掉这些文件。");
    console.log("尽信书,不如无书;尽看代码,不如删掉这些文件。");
    

    其中 console.log() 那三行就是 index.js 的文本内容。
     然后,我们试下流的存入:

    let fs = require('fs');
    let data = 'console.log("Hello World! 我要存入数据!")';
    
    // 创建一个可以写入的流,写入到文件 index.js 中
    let writeStream = fs.createWriteStream('index.js');
    // 开始写入
    writeStream.write(data, 'utf8');
    // 写入完成
    writeStream.end();
    writeStream.on('finish', () => {
      console.log('写入完成!');
      // Console:写入完成
    });
    

    我们打开 index.js,会发现里面的内容变成了 console.log("Hello World! 我要存入数据!"),依次,我们通过流的形式进行了读取和写入的操作。

    作者:jsliang
    链接:https://juejin.im/post/5c1f8e52f265da6170071e43
    来源:掘金

    前端优化

    0 条评论 总结 Vue 教程 无标签 Jonathan

    Object.freeze

    这算是一个性能优化的小技巧吧。在我们遇到一些 big data的业务场景,它就很有用了。尤其是做管理后台的时候,经常会有一些超大数据量的 table,或者一个含有 n 多数据的图表,这种数据量很大的东西使用起来最明显的感受就是卡。但其实很多时候其实这些数据其实并不需要响应式变化,这时候你就可以使用 Object.freeze 方法了,它可以冻结一个对象(注意它不并是 vue 特有的 api)。
    当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter,它们让 Vue 能进行追踪依赖,在属性被访问和修改时通知变化。
    使用了 Object.freeze 之后,不仅可以减少 observer 的开销,还能减少不少内存开销。相关 issue。
    使用方式:this.item = Object.freeze(Object.assign({}, this.item))
    这里我提供了一个在线测速 demo,点我。
    通过测速可以发现正常情况下1000 x 10 rerender 都稳定在 1000ms-2000ms 之间,而开启了Object.freeze的情况下,rerender 都稳住在 100ms-200ms 之间。有接近 10 倍的差距。所以能确定不需要变化检测的情况下,big data 还是要优化一下的。

    sass 将变量给 js

    还是那前面那个换肤来举例子,我们页面初始化的时候,总需要一个默认主题色吧,假设我们在 var.scss中声明了一个 theme:blue,我们在 js 中该怎么获取这个变量呢?我们可以通过 css-modules :export来实现。更具体的解释-How to Share Variables Between Javascript and Sass

        // var.scss
        $theme: blue;
    
        :export {
          theme: $theme;
        }
    
        // test.js
        import variables from '@/styles/var.scss'
        console.log(variables.theme) // blue
    

    当 js 和 css 共享一个变量的时候这个方案还是很实用的。vue-element-admin 中的侧边栏的宽度,颜色等等变量都是通过这种方案来实现共享的。
    其它换肤方案可以参考 聊一聊前端换肤

    作者:花裤衩
    链接:https://juejin.im/post/5c92ff94f265da6128275a85
    来源:掘金

    moment

    1 条评论 总结 教程 无标签 Jonathan

    计算两个时间段的时间差

    const diff = moment(endTime).diff(moment(startTime), 'days')   // 天数差
    

    Oxygen Music

    1 条评论 Vue Vue Oxygen Music Jonathan
    • 2019.04.24 更新朋友界面,同网易云朋友栏目,更多内容虚登录,
    • 2019.04.25 优化朋友栏目,增加验证码登录功能,


    第二阶段总结

    0 条评论 总结 培训总结 Jonathan

    总结

    • 经过两个阶段的培训增强了领悟、创新和推断能力。
    • 掌握自学的方法,学会条理、耐心的处理和完成任务。
    • 思考方式逐渐成熟,逻辑性逐渐规范明确。

    完成每个阶段的任务都能学到很多,在编程中代码不断符合规范,积累了很多代码片段。
    在任务中发现问题、解决问题并总结

    生命周期函数/methods/watch里面不应该使用箭头函数

    vue中生命周期函数, methods, watch 自动绑定 this 上下文到实例中,因此你可以访问数据,对属性和方法进行运算。

    对computed、watch、methods的认知

    1. computed属性的结果会被缓存,依赖的属性如果发生变化才会重新计算,把他当做普通属性来使用;
    2. watch属性,主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作,可以把他看作是computed和methods的结合体;
    3. methods方法表示一个具体的操作,主要书写业务逻辑;

    关于数据的请求

    如果可以的话,最好能在局部根组件里请求一次ajax数据,然后从局部根组件里把接收到的数据分别传给各个局部的子组件,而不是每个局部的子组件都发送一次ajax请求。

    localStorage

    可能用户会有不小的概率关闭了本地自动存储的功能,一般我们使用localStorage的时候 都要使用 try catch 代码块,这样就算用户关闭本地自动存储功能,也不会让整个代码都不能运行,只是没了这个localStorage的功能而已。

    try{
      localStorage.userInfo = userInfo
    } catch(e) {
      console.log(e)
    }

    vuex Module

    Module的话,看得勉强理解,Vuex允许我们将store分割成模块(module)。每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块。
    当应用变得非常复杂时,可以使用Module避免store对象变得相当臃肿。
    我觉得Module具体的应用要在复杂项目中亲自练手过才能熟练,目前还是了解。