0%

在使用 Vuejs 开发 SPA 页面时,我创建了一个父组件以及子组件,然后通过父组件去调用子组件时,报如下错误:

1
Vue.js “Maximum call stack size exceeded” error.

示例代码:

Panel.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<template>
<div id="panel">
<div class="panel">
<ul>
<li v-for="shelf in shelfs">
<panel-body :shelf="shelf" :selected.sync="selected"></panel-body>
</li>
</ul>
</div>
</div>
</template>

<script>
import PanelBody from '../components/PanelBody'
export default {
name: 'panel-body',
components: {
'panel-body': PanelBody
},
data: () => ({
shelfs: [{
name: 'shelf 1',
books: [{
title: 'Lorem ipum'
}, {
title: 'Dolor sit amet'
}]
}, {
name: 'shelf 2',
books: [{
title: 'Ipsum lorem'
}, {
title: 'Amet sit dolor'
}]
}],
selected: {}
})
}
</script>

PanelBody.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
<div id="panel-body">
<a href="#" v-on:click.prevent.stop="select">{{ shelf.name }}</a>
<ul v-show="isSelected">
<li v-for="book in shelf.books">{{ book.title }}</li>
</ul>
</div>
</template>

<script>
export default {
name: 'panel-body',
props: ['shelf', 'selected'],
computed: {
isSelected: function () {
return this.selected === this.shelf
}
},
methods: {
select: function () {
this.selected = this.shelf
}
}
}
</script>

错误原因:

Maximum call stack size exceeded

错误出处:

1
2
3
4
5
6
import PanelBody from '../components/PanelBody'
export default {
name: 'panel-body',
components: {
'panel-body': PanelBody
},

错误解决:
你定义你的父组件名称:“panel-body”。只要将名称改成:“panel”或者其他不与子组件引用名一样,你就能删除你的循环引用,从而不再报错。

注:Vue2.0 中文文档 ,如果对自己英文有信心,也可以直接阅读 英文文档

起步:从了解 Vue 开始

  1. 扎实的 JavaScript / HTML / CSS 基本功。这是前置条件。

  2. 通读官方教程 (guide) 的基础篇。不要用任何构建工具,就只用最简单的 <script>,把教程里的例子模仿一遍,理解用法。不推荐上来就直接用 vue-cli 构建项目,尤其是如果没有 Node/Webpack 基础。

  3. 照着官网上的示例,自己想一些类似的例子,模仿着实现来练手,加深理解。

  4. 阅读官方教程进阶篇的前半部分,到『自定义指令 (Custom Directive) 』为止。着重理解 Vue 的响应式机制和组件生命周期。『渲染函数(Render Function)』如果理解吃力可以先跳过。

  5. 阅读教程里关于路由和状态管理的章节,然后根据需要学习 vue-router 和 vuex。同样的,先不要管构建工具,以跟着文档里的例子理解用法为主。

  6. 走完基础文档后,如果你对于基于 Node 的前端工程化不熟悉,就需要补课了。下面这些严格来说并不是 Vue 本身的内容,也不涵盖所有的前端工程化知识,但对于大型的 Vue 工程是前置条件,也是合格的『前端工程师』应当具备的知识。

前端生态/工程化

  1. 了解 JavaScript 背后的规范,ECMAScript 的历史和目前的规范制定方式。学习 ES2015/16 的新特性,理解 ES2015 modules,适当关注还未成为标准的提案

  2. 学习命令行的使用。建议用 Mac。

  3. 学习 Node.js 基础。建议使用 nvm 这样的工具来管理机器上的 Node 版本,并且将 npm 的 registry 注册表配置为淘宝的镜像源至少要了解 npm 的常用命令,npm scripts 如何使用,语义化版本号规则,CommonJS 模块规范(了解它和 ES2015 Modules 的异同),Node 包的解析规则,以及 Node 的常用 API。应当做到可以自己写一些基本的命令行程序。注意最新版本的 Node (6+) 已经支持绝大部分 ES2015 的特性,可以借此巩固 ES2015。

  4. 了解如何使用 / 配置 Babel 来将 ES2015 编译到 ES5 用于浏览器环境。

  5. 学习 Webpack。Webpack 是一个极其强大同时也复杂的工具,作为起步,理解它的『一切皆模块』的思想,并基本了解其常用配置选项和 loader 的概念/使用方法即可,比如如何搭配 Webpack 使用 Babel。学习 Webpack 的一个挑战在于其本身文档的混乱,建议多搜索搜索,应该还是有质量不错的第三方教程的。英文好的建议阅读 Webpack 2.0 的文档

阅读全文 »

注:2.0 已经有 中文文档 。如果对自己英文有信心,也可以直接阅读 英文文档
此指南仅供参考,请根据自身实际情况灵活调整。
欢迎转载,请注明出处。

起步

  1. 扎实的 JavaScript / HTML / CSS 基本功。这是前置条件。

  2. 通读官方教程 (guide) 的基础篇。不要用任何构建工具,就只用最简单的 <script>,把教程里的例子模仿一遍,理解用法。不推荐上来就直接用 vue-cli 构建项目,尤其是如果没有 Node/Webpack 基础。

  3. 照着官网上的示例,自己想一些类似的例子,模仿着实现来练手,加深理解。

  4. 阅读官方教程进阶篇的前半部分,到『自定义指令 (Custom Directive) 』为止。着重理解 Vue 的响应式机制和组件生命周期。『渲染函数(Render Function)』如果理解吃力可以先跳过。

  5. 阅读教程里关于路由和状态管理的章节,然后根据需要学习 vue-router 和 vuex。同样的,先不要管构建工具,以跟着文档里的例子理解用法为主。

  6. 走完基础文档后,如果你对于基于 Node 的前端工程化不熟悉,就需要补课了。下面这些严格来说并不是 Vue 本身的内容,也不涵盖所有的前端工程化知识,但对于大型的 Vue 工程是前置条件,也是合格的『前端工程师』应当具备的知识。

前端生态/工程化

  1. 了解 JavaScript 背后的规范,ECMAScript 的历史和目前的规范制定方式。学习 ES2015/16 的新特性,理解 ES2015 modules,适当关注还未成为标准的提案

  2. 学习命令行的使用。建议用 Mac。

  3. 学习 Node.js 基础。建议使用 nvm 这样的工具来管理机器上的 Node 版本,并且将 npm 的 registry 注册表配置为淘宝的镜像源至少要了解 npm 的常用命令,npm scripts 如何使用,语义化版本号规则,CommonJS 模块规范(了解它和 ES2015 Modules 的异同),Node 包的解析规则,以及 Node 的常用 API。应当做到可以自己写一些基本的命令行程序。注意最新版本的 Node (6+) 已经支持绝大部分 ES2015 的特性,可以借此巩固 ES2015。

  4. 了解如何使用 / 配置 Babel 来将 ES2015 编译到 ES5 用于浏览器环境。

  5. 学习 Webpack。Webpack 是一个极其强大同时也复杂的工具,作为起步,理解它的『一切皆模块』的思想,并基本了解其常用配置选项和 loader 的概念/使用方法即可,比如如何搭配 Webpack 使用 Babel。学习 Webpack 的一个挑战在于其本身文档的混乱,建议多搜索搜索,应该还是有质量不错的第三方教程的。英文好的建议阅读 Webpack 2.0 的文档

Vue 进阶

  1. 有了 Node 和 Webpack 的基础,可以通过 vue-cli 来搭建基于 Webpack ,并且支持单文件组件的项目了。建议用 webpack-simple 这个模板开始,并阅读官方教程进阶篇剩余的内容以及 vue-loader 的文档,了解一些进阶配置。有兴趣的可以自己亲手从零开始搭一个项目加深理解。

  2. 根据 例子 尝试在 Webpack 模板基础上整合 vue-router 和 vuex

  3. 深入理解 Virtual DOM 和『渲染函数 (Render Functions)』这一章节(可选择性使用 JSX),理解模板和渲染函数之间的对应关系,了解其使用方法和适用场景。

  4. (可选)根据需求,了解服务端渲染的使用(需要配合 Node 服务器开发的知识)。其实更重要的是理解它所解决的问题并搞清楚你是否需要它。

  5. 阅读开源的 Vue 应用、组件、插件源码,自己尝试编写开源的 Vue 组件、插件。

  6. 参考 贡献指南 阅读 Vue 的源码,理解内部实现细节。(需要了解 Flow

  7. 参与 Vue GitHub issue 的定位 -> 贡献 PR -> 加入核心团队 -> 升任 CTO -> 迎娶白富美…(误


> 转自:[尤大大的新手向:Vue 2.0 的建议学习顺序](https://zhuanlan.zhihu.com/p/23134551)

  1. 通过命令 git init 把这个目录变成 git 可以管理的仓库(先进入项目文件夹)
    1
    git init
  2. 把文件添加到版本库中,使用命令 git add .添加到暂存区里面去,不要忘记后面的小数点“.”,意为添加文件夹下的所有文件
    1
    git add .
  3. 用命令 git commit 告诉 Git,把文件提交到仓库。引号内为提交说明
    1
    git commit -m 'first commit'
  4. 关联到远程库 git remote add origin 你的远程库地址
    1
    git remote add origin https://github.com/cade8800/ionic-demo.git
  5. 获取远程库与本地同步合并(如果远程库不为空必须做这一步,否则后面的提交会失败)
    1
    git pull --rebase origin master
  6. 把本地库的内容推送到远程,使用 git push 命令,实际上是把当前分支 master 推送到远程。执行此命令后会要求输入用户名、密码,验证通过后即开始上传。
    1
    git push -u origin master
  • 状态查询命令
    1
    git status



借助“网络”偏好设置中的“位置”功能,您可以在不同的网络设置组之间快速切换。

在不同的网络设置组(位置)之间切换的功能在以下情况下非常有用:

  • 您在工作场所和家中使用相同类型的网络(如以太网),但在工作场所使用的设置不允许您的 Mac 自动连接到家中所用的相同类型网络。
  • 您的 Mac 在工作场所和家中连接到多种类型的网络服务(如 Wi-Fi 和以太网),但是,在工作场所,您希望您的 Mac 先尝试连接到以太网网络,而在家中,则希望先尝试连接到 Wi-Fi 网络。换言之,您希望针对每个位置设置不同的服务顺序。
  • 您的 Mac 无法连接到网络,并且您想要快速重设您的网络设置以用于测试,同时不丢失当前的网络设置。

在上述每个示例中,“网络”偏好设置中的“位置”功能均可发挥作用。以下步骤适用于使用 OS X v10.6 或更高版本的 Mac 电脑。


如何创建新的网络位置

  1. 选取苹果菜单 () >“系统偏好设置”,然后点按“网络”。

  2. “位置”弹出式菜单中会显示您当前所选网络设置组的名称。默认位置名称为“自动”。从该菜单中选取“编辑位置”。

  3. 此时,将打开一个位置对话框。点按位置列表下方的 “添加”按钮,然后为新位置键入一个名称,如“工作”或“家庭”或“移动”:

  4. 点按“完成”。“位置”菜单现在应显示新位置的名称。点按“应用”后,您对网络设置所做的全部更改都将存储到该位置。您之前位置中的网络设置在您离开时会保留,因此您可以随时切换回来。

  5. 点按“应用”以存储您的设置,并从之前的位置切换到新的位置。您的 Mac 会自动尝试为每种类型的网络确定正确的设置。如果您需要进一步调整设置,请记得再次点按“应用”。如果您的新设置不允许您连接到您的网络,请点按“向导”。

阅读全文 »

在使用 axios 时,注意到配置选项中包含 params 和 data 两者,以为他们是相同的,实则不然。

因为 params 是添加到 url 的请求字符串中的,用于 get 请求。

而 data 是添加到请求体(body)中的, 用于 post 请求。

比如对于下面的 get 请求:

1
2
3
4
5
6
7
axios({
method: 'get',
url: 'https://onana.cn/openapi/api?info=20ff1803ff65429b8',
params: {
info: '西安天气'
}
})

如果我们将 params 修改为 data,那么是不能请求成功的,因为 get 请求中不存在 data 这个选项。

Tip:

HTTP 请求过程中

  • GET 请求:表单参数以 name=value&name1=value1 的形式附到 url 的后面

  • POST 请求:表单参数是在请求体中,也是 name=value&name1=value1 的形式在请求体中。

  • POST 表单请求提交时,使用的 Content-Type 是 application/x-www-form-urlencoded,而使用原生 AJAX 的 POST 请求如果不指定请求头 RequestHeader,默认使用的 Content-Type 是 text/plain;charset=UTF-8。在 html 中 form 的 Content-type 默认值:Content-type:application/x-www-form-urlencoded。如果使用 ajax 请求,在请求头中出现 request payload 导致参数的方式改变了,那么解决办法就是:

    headers: {‘Content-Type’:’application/x-www-form-urlencoded’}

这样,问题就可以解决。


let 命令 和 const 命令

let 命令:

let 用于声明变量,但是所有声明的变量只在 let 命令所在的代码块有效。
let 不允许在同以作用域中重复声明变量。
let 不存在变量提升,所以变量一定要在声明后使用,否则会报错。

const 命令:

const 命令用来声明常量,一旦声明,其值就不能改变,即 const 一旦声明常量就必须立刻初始化,不能留到以后赋值。
const 命令只是保证变量名指向的地址不变,并步保证该地址的数据不变。

相同点:

let 和 const 命令声明的变量都只在它们所在的块级作用域中才有效。
如果区块中存在 let 和 const 命令,则这个区块对这些命令声明的变量从一开始就形成封闭作用域。

变量的解构赋值

ES6 允许按照一定的模式,从数组和对象中提取值,对变量进行赋值,称为解构。

数组

1
2
3
4
5
let [a, b, c,d] = [“aa”, “bb”, 77,88];  //数组结构
let [a,b,[c,d],e] =[“aa”,’bb’,[33,44],55]; //嵌套数组解构
let [a,b,,e] =[“aa”,’bb’,[33,44],55]; //空缺变量
let [a,b,,e,f] =[“aa”,’bb’,[33,44],55]; //多余变量
let [a,b,,e,f=’hello’] =[“aa”,’bb’,[33,44],55]; //默认值

对象解构

1
2
3
4
5
6
7
8
9
10
11
12
13
let obj = { uid: 121, uname: '张三' };
let obj = new Object();
obj.uid = 111;
obj.uname = '张三';
let { uid: id, uname: name } = obj; //顺序改变无影响
console.log(name); //张三

//小括号:
let uid, uname;
({ uid, uname } = obj); //必须有小括号,否则{}就会被解读为语句块
console.log(uname); //张三

// PS: 可嵌套 ,可有默认值

字符串解构

1
2
let [a, b, c, d] = '倚天屠龙';
console.log(a, b, c, d);

函数参数解构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let obj = { uid: 121, uname: '张三' };
function analysis({ uid, uname }) {
console.log(uid);
console.log(uname);
}

//-------以下也正确
function analysis({ uname }) {
console.log(uname);
}

analysis(obj);

// PS: 参数中数组、字符串、默认值、缺位均支持 。

数组操作 Array

forEach()

方法对数组的每个元素执行一次提供的函数。

1
2
3
4
5
6
7
8
9
let array1 = ['a', 'b', 'c'];

array1.forEach(function(element) {
console.log(element);
});

// expected output: "a"
// expected output: "b"
// expected output: "c"

filter()

方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。

1
2
3
4
5
let words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);
console.log(result);

// expected output: Array ["exuberant", "destruction", "present"]

map()

方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ES6
let numbers = [1, 5, 10, 15];
let doubles = numbers.map(x => x ** 2);

// doubles is now [1, 25, 100, 225]
// numbers is still [1, 5, 10, 15]

const numbers = [2, 4, 8, 10];
let halves = numbers.map(x => x / 2);

let numbers = [1, 4, 9];
let roots = numbers.map(Math.sqrt);

// roots is now [1, 2, 3]
// numbers is still [1, 4, 9]

includes()

方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回 false。

1
2
3
4
5
6
7
8
9
10
11
12
let array1 = [1, 2, 3];

console.log(array1.includes(2));
// expected output: true

let pets = ['cat', 'dog', 'bat'];

console.log(pets.includes('cat'));
// expected output: true

console.log(pets.includes('at'));
// expected output: false

箭头函数表达式

语法比函数表达式更短,并且没有自己的 this,arguments,super 或 new.target。这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数。

1
2
3
4
5
6
7
8
9
10
11
var materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];

materials.map(function(material) {
return material.length;
}); // [8, 6, 7, 9]

materials.map(material => {
return material.length;
}); // [8, 6, 7, 9]

materials.map(material => material.length); // [8, 6, 7, 9]

import

import 语句用于导入由另一个模块导出的绑定。无论是否声明了 strict mode ,导入的模块都运行在严格模式下。import 语句不能在嵌入式脚本中使用。

1
2
3
4
5
6
7
8
9
import defaultExport from "module-name";
import * as name from "module-name";
import { export } from "module-name";
import { export as alias } from "module-name";
import { export1 , export2 } from "module-name";
import { export1 , export2 as alias2 , [...] } from "module-name";
import defaultExport, { export [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";

defaultExport

  • 将引用模块默认导出的名称。

module-name

  • 要导入的模块。这通常是包含模块的.js 文件的相对或绝对路径名,不包括.js 扩展名。某些打包工具可以允许或要求使用该扩展;检查你的运行环境。只允许单引号和双引号的字符串。

name

  • 引用时将用作一种命名空间的模块对象的名称。

export, exportN

  • 要导入的导出名称。

alias, aliasN

  • 将引用指定的导入的名称。

Promise

Promise 对象

  • Promise 的含义
  • 基本用法
  • Promise.prototype.then()
  • Promise.prototype.catch()
  • Promise.prototype.finally()
  • Promise.all()
  • Promise.race()
  • Promise.resolve()
  • Promise.reject()
  • 应用
  • Promise.try()

Sass/Less/PostCSS

Sass

世界上最成熟、最稳定、最强大的专业级 CSS 扩展语言!

Less

一种 动态 样式 语言.
LESS 将 CSS 赋予了动态语言的特性,如 变量, 继承, 运算, 函数. LESS 既可以在 客户端 上运行 (支持 IE 6+, Webkit, Firefox),也可以借助 Node.js 或者 Rhino 在服务端运行。

需求

1
2
3
var arr1 = [1, 2, 2, 3, 4, 5];
var arr2 = [1, 2];
求两数据的不同值,结果为[3, 4, 5]

方案一

调用第三方工具:underscore

1
2
3
4
var arr1 = [1, 2, 2, 3, 4, 5];
var arr2 = [1, 2];
_.difference(arr1, arr2);
=> [3, 4, 5]

方案二

手写常规办法,创建临时数组

1
2
3
4
5
6
7
8
9
10
// past
var arr1 = [1, 2, 2, 3, 4, 5];
var arr2 = [1, 2];
var temp = [];
for (var i = 0; i < arr1.length; i++) {
if (arr2.indexOf(arr1[i]) === -1) {
temp.push(arr1[i]);
}
}
console.log(temp);

方案三

调用 es6 的数组操作 api

1
2
3
4
// es6
let arr1 = [1, 2, 2, 3, 4, 5];
let arr2 = [1, 2];
console.log(arr1.filter(item => !arr2.includes(item)));

就酱~