使用 import { ref } from 'vue'
XXX.value
使用 import { computed } from 'vue'
1 | const count = ref(1); |
1 | setup(){ |
使用 import {computed, reactive } from 'vue'
1 | setup(){ |
1 | props: { |
1 | const count = ref(0); |
1 | const stop = watchEffect(() => { |
前端面试题
在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。
JavaScript 的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。
先来一个例子:
1 | function fruits() {} |
但是如果我们有一个对象 banana= {color : “yellow”} ,我们不想对它重新定义 say 方法,那么我们可以通过 call 或 apply 用 apple 的 say 方法:
1 | banana = { |
所以,可以看出 call 和 apply 是为了动态改变 this 而出现的,当一个 object 没有某个方法(本栗子中 banana 没有 say 方法),但是其他的有(本栗子中 apple 有 say 方法),我们可以借助 call 或 apply 用其它对象的方法来操作。
对于 apply、call 二者而言,作用完全一样,只是接受参数的方式不太一样。例如,有一个函数定义如下:
1 | var func = function (arg1, arg2) {}; |
其中 this 是你想指定的上下文,他可以是任何一个 JavaScript 对象(JavaScript 中一切皆对象),call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。
JavaScript 中,某个函数的参数数量是不固定的,因此要说适用条件的话,当你的参数是明确知道数量时用 call 。
而不确定的时候用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来遍历所有的参数。
为了巩固加深记忆,下面列举一些常用用法:
1 |
|
1 | var numbers = [5, 458, 120, -215]; |
number 本身没有 max 方法,但是 Math 有,我们就可以借助 call 或者 apply 使用其方法。 验证是否是数组(前提是 toString()方法没有被重写过)
1 | functionisArray(obj){ |
下面就借用一道面试题,来更深入的去理解下 apply 和 call 。 定义一个 log 方法,让它可以代理 console.log 方法,常见的解决方法是:
1 | function log(msg) { |
上面方法可以解决最基本的需求,但是当传入参数的个数是不确定的时候,上面的方法就失效了,这个时候就可以考虑使用 apply 或者 call,注意这里传入多少个参数是不确定的,所以使用 apply 是最好的,方法如下:
1 | function log() { |
接下来的要求是给每一个 log 消息添加一个”(app)”的前辍,比如:
1 | log("hello world"); //(app)hello world |
该怎么做比较优雅呢?这个时候需要想到 arguments 参数是个伪数组,通过 Array.prototype.slice.call 转化为标准数组,再使用数组方法 unshift,像这样:
1 | function log() { |
bind() 方法与 apply 和 call 很相似,也是可以改变函数体内 this 的指向。
MDN 的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
直接来看看具体如何使用,在常见的单体模式中,通常我们会使用 _this , that , self 等保存 this ,这样我们可以在改变了上下文之后继续引用到它
1 | var foo = { |
由于 Javascript 特有的机制,上下文环境在 eventBind:function(){ } 过渡到 $(‘.someClass’).on(‘click’,function(event) { }) 发生了改变,上述使用变量保存 this 这些方式都是有用的,也没有什么问题。当然使用 bind() 可以更加优雅的解决这个问题:
1 | var foo = { |
在上述代码里,bind() 创建了一个函数,当这个 click 事件绑定在被调用的时候,它的 this 关键词会被设置成被传入的值(这里指调用 bind()时传入的参数)。因此,这里我们传入想要的上下文 this(其实就是 foo ),到 bind() 函数中。然后,当回调函数被执行的时候, this 便指向 foo 对象。再来一个简单的栗子:
1 | var bar = function () { |
这里我们创建了一个新的函数 func,当使用 bind() 创建一个绑定函数之后,它被执行的时候,它的 this 会被设置成 foo , 而不是像我们调用 bar() 时的全局作用域。
有个有趣的问题,如果连续 bind() 两次,亦或者是连续 bind() 三次那么输出的值是什么呢?像这样:
1 | var bar = function () { |
答案是,两次都仍将输出 3 ,而非期待中的 4 和 5 。
原因是,在 Javascript 中,多次 bind() 是无效的。
更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。
1 | var obj = { x: 81 }; |
三个输出的都是 81,但是注意看使用 bind() 方法的,他后面多了对括号。
也就是说,区别是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会立即执行函数。
apply 、 call 、bind 三者都是用来改变函数的 this 对象的指向的;
apply 、 call 、bind 三者第一个参数都是 this 要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;
bind 是返回对应函数,便于稍后调用;apply、call 则是立即调用 。
beforeCreate
:实例创建前被调用created
:实例创建后被调用,完成数据观测,属性和方法的运算,watch/event 实际回调,模板渲染成 html(vm.$el 未定义),数据初始化最好在这个阶段完成beforeMount
: 在$el挂载前被调用,相关的 render 函数首次被调用,期间将模块渲染成html,此时vm.$el 还是未定义;mounted
: 在$el挂载后被调用,此时vm.$el 可以调用,不能保证所有的子组件都挂载,要等视图全部更新完毕用 vm.$nextTick()beforeUpdate
:数据更新时调用;updated
:数据更新后调用;activated
:<keep-alive></keep-alive>
包裹的组件激活时调用deactivated
:<keep-alive></keep-alive>
包裹的组件离开时调用beforeDestroy
:实例销毁之前调用,此时实例仍然完全可用;destroyed
:实例销毁之后调用,此时实例的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。用keep-alive
内置组件包裹路由组件,在钩子函数 activated 中更新。
不可以。this 会是 undefind,因为箭头函数中的 this 指向的是定义时的 this,而不是执行时的 this,所以不会指向 Vue 实例的上下文。
1 | watch:{ |
1 | watch:{ |
在选项参数中指定 deep:true。
1 | watch:{ |
1 | <template> |
1 | <template> |
1 | <template> |
1 | <ul ref="mydiv"> |
在子组件中使用this.$parent
来访问
在子组件中使用this.$root
来访问
String、Number、Boolean、Array、Object、Date、Function、Symbol, 此外还可以是一个自定义的构造函数 Personnel,并且通过 instanceof 来验证 propwokrer 的值是否是通过这个自定义的构造函数创建的。
1 | function Personnel(name, age) { |
@click="handleOpen"
默认第一个参数传入 event 对象;@click="handleOpen(0, $event)
,如果自己需要传入参数和 event 对象,则需要使用$event 来获取 event 对象并传入 handleOpen。$event.currentTarget
始终指向事件所绑定的元素,而$event.target
指向事件发生时的元素。
.stop:阻止事件传递
.prevent: 阻止默认事件;
.capture :在捕获的过程监听,没有 capture 修饰符时都是默认冒泡过程 监听;
.self:当前绑定事件的元素才能触发;
.once:事件只会触发一次;
.passive:默认事件会立即触发,不要把.passive 和.prevent 一起使用,因为.prevent 将不起作用。
表单修饰符.number .lazy .trim
要注意顺序很重要,用@click.prevent.self
会阻止所有的点击,而@click.self.prevent
只会阻止对元素自身的点击。
使用按键修饰符 <input @keyup.enter="submit">
按下回车键时候触发 submit 事件
<template>
上;<template>
上。vm.$nextTick(() =>{this.handleadd()}),将 handleadd 回调延迟到下次 DOM 更新循环之后执行。
Object.assign(this.$data,this.$options.data())。
深拷贝与浅拷贝的区别,实现深拷贝的几种方法是面试必问考点
区分两者很容易,简单的来说,假设 b 复制了 a,当修改 a 的值时,b 的值也发生变化,这就是浅拷贝
如果 b 没有发生改变就是深拷贝
浅拷贝例子
1 | let A = [0, 1, 2, 3]; |
1 基本类型–名值存储在栈内存中 let a =1
当 b=a 复制时,栈内存会重新开辟一个内存
所以此时修改 a=2,对 b 并不会造成影响
2 引用数据类型–名存在栈内存中,值存在于堆内存中
当 b=a 进行拷贝时,其实复制的是 a 的引用地址,而并非堆里面的值。
当我们 a[0]=1 时进行数组修改时,由于 a 与 b 指向的是同一个地址,所以自然 b 也受了影响,这就是所谓的浅拷贝了。
要是在堆内存中也开辟一个新的内存专门为 b 存放值,就像基本类型那样就达到深拷贝效果
1 | function deepClone(obj) { |
跟预想的一样,现在 b 脱离了 a 的控制,不再受 a 影响了
缺点:
JSON 对象实现深拷贝的一些问题.无法实现对对象中方法的深拷贝
1 | function deepClone2(obj) { |
缺点:
当对象只有一级属性为深拷贝;
当对象中有多级属性时,二级属性后就是浅拷贝
1 | let obj = { |
浏览器从网络或者硬盘中获取 HTML 字节数据经过一下流程将 html 字节解析为 DOM 树
接下来通过一段 HTML 代码与配图更好的理解“字节 -> 字符 -> 令牌-> 节点对象 -> 对象模型”这个过程
1 | <html> |
浏览器解析遇到 link 标签时,浏览器就开始解析 CSS,像构建 DOM 树一样构建 CSSOM 树。style.css 的代码如下:
1 | body { |
在构建了 DOM 树和 CSSOM 树之后,浏览器只是拥有 2 个相互独立的对象集合,DOM 树描述的文档结构和内容,CSSOM 树描述了对应文档的样式规则,想要渲染出页面,就需要将 DOM 树、CSSOM 树结合在一起,构建渲染树。
渲染树构建好后,浏览器得到了每个节点的内容与样式,下一步就是需要计算每个节点在浏览器窗口的确切位置与大小,即 layout 布局。
布局阶段,从渲染树的根节点开始遍历,采用盒子模型的模式来表示每个节点与其他元素之间的距离,从而确定每个元素在屏幕内的位置与大小。
盒子模型:包括外边距(margin),内边距(padding),边框(border),内容(content)。标准盒子模型 width/height = content;IE 盒子模型 width/height = content + padding + border。
JavaScript 文件加载会阻塞 DOM 树的构建,可以给 script 标签添加异步属性 async,这样浏览器的 HTML 解析就不会被 js 文件阻塞。
浏览器每次遇到 link 标签时,浏览器就需要向服务器发出请求获得 CSS 文件,然后才继续构建 DOM 树和 CSSOM 树,可以合并所有 CSS 成一个文件,减少 HTTP 请求,减少关键资源往返加载的时间,优化渲染速度。
对 HTML、CSS、JavaScript 这些文件去除冗余字符(例如不必要的注释、空格符和换行符等),再进行压缩,减小文件数据大小,加快浏览器解析文件编码。
图片加载较多时,采用懒加载的方案,用户滚动页面可视区时再加载渲染图片
1 | //父类 |
1 | function Person(name) { |
1 | function Person(name) { |
还有很多种继承方式.写多了也记不住,等理解完了再补
创建一个 Person 的实例,必须使用到 new 操作符.以这种方式调用构造函数实际上会经历以下 4 个步骤:
1 | function Base() {} |
这样代码的结果是什么,我们在 Javascript 引擎中看到的对象模型是:
如图所示 new 操作符干了三件事
1 | let obj = {}; |
第一行,我们创建了一个空对象 obj
第二行,我们将这个空对象的__proto__成员指向了 Base 函数对象 prototype 成员对象
第三行,我们将 Base 函数对象的 this 指针替换成 obj,然后再调用 Base 函数,
于是我们就给 obj 对象赋值了一个 id 成员变量,这个成员变量的值是 base
1 | Base.prototype.tostring = function () { |
当我们 Base 原型添加一些方法,那么 new 出来的实例对象,根据__proto__的特性也能够使用 tostring 方法
下面的例子中分别通过构造函数与 class 类实现了一个简单的创建实例的过程。
1 | // ES5构造函数 |
在《JavaScript 模式》这本书中,new 的过程说的比较直白,当我们 new 一个构造器,主要有三步:
改写上面的例子:
1 | // ES5构造函数 |
1 | // 构造器函数 |
Vuex 是一个专为 Vue.js 应用程序开发的状态管理插件。它采用集中式存储管理应用的所有组件的状态,而更改状态的唯一方法是提交 mutation,例 this.$store.commit(‘SET_VIDEO_PAUSE’, video_pause,SET_VIDEO_PAUSE 为 mutations 属性中定义的方法
state、getters、mutations、actions、modules
存储在 state 中,改变 Vuex 中的状态的唯一途径就是显式地提交 (commit) mutation。
使用 mapState 辅助函数, 利用对象展开运算符将 state 混入 computed 对象中
router 是 VueRouter 的一个对象,通过 Vue.use(VueRouter)和 VueRouter 构造函数得到一个 router 的实例对象,他包含了所有的路由包含了许多关键的对象和属性
route 是一个跳转的路由对象,每一个路由都会有一个 route 对象,是一个局部的对象,可以获取对应的 name,path,params,query 等
$route.path
$route.params
$route.query
$route.router
$route.matched
$route.name
$route.path, $route.params, $route.name, $route.query 这几个属性,主要用于接收路由传递的参数
v-show
,切换元素的 display 属性,来控制元素显示隐藏,初始化会渲染,适用频繁显示隐藏的元素,不能用在 template 上;
v-if
,通过销毁并重建组件,来控制组件显示隐藏,初始化不会渲染,不适用频繁显示隐藏的组件,可以用在 template 上
v-else-if
,必须和 v-if
一起使用
v-else
,必须和 v-if
一起使用;
v-for
,将 Array、Object、Number、String 数据循环渲染元素或者组件,渲染组件必须带上 key,key 要为数据中每项特定值比如 ID;
1 | <div v-for="(item,index) in Array">{{index}}-{{item}}</div> |
v-on
,缩写@,监听事件,如:@click、@submit、@dblclick
1 | <div @click="a"></div> |
1 | //阻止冒泡 |
1 | <myVue @click.native="d"></myVue> |
1 | <myVue @diy-event="f"></myVue> //组件中这样触发 this.$emit('diyEvent',data) |
v-bind,缩写:,绑定动态属性;
v-model,限制应用在 input textarea select 表单 元素和组件上创建双向绑定,修饰符 v-model.lazy 懒监听、v-model.number 将值转成有效的数字、v-model.trim 过滤首尾空格;
v-text,<div v-text="data"></div>等同<div></div>
v-html,直接输出 HTML,不会按 Vue 模板编译,会有 XSS 攻击分析,不要用在用户提交内容上;
计算属性是基于它们的响应式依赖进行缓存的,只在相关响应式依赖发生改变时它们才会重新求值。
计算属性的 getter 和 setter 是什么,有什么用。
1 | <template> |
push()、pop()、shift()、unshift()、splice()、sort()、reverse()这些方法会改变被操作的数组;
filter()、concat()、slice()这些方法不会改变被操作的数组,返回一个新的数组;
以上方法都可以触发视图更新。
利用索引直接设置一个数组项,例:this.array[index] = newValue
直接修改数组的长度,例:this.array.length = newLength
以上两种方法不可以触发视图更新
在处于同一节点上,因为 v-for 的优先级比 v-if 更高,v-if 将分别重复运行于每个 v-for 循环中。如果要实现渲染满足条件的 li 节点时,可以这样用
1 | <ul> |
父组件到子组件的通信用 props 来完成。
子组件到父组件的通信,通过在父组件中自定义事件,在子组件用 this.$emit(‘父组件自定义事件’,’要传到父组件的数据’)实现
使用$bus 方法实现组件通信
1 | <template> |
1 | <template> |
空
这次面试让我知道了自己几斤几两.
]]>参考链接 https://juejin.im/post/5d136700f265da1b7c6128db
参考链接 https://www.cnblogs.com/ranyonsue/p/11201730.html
参考链接 https://blog.csdn.net/qq_27674439/article/details/99095336
参考链接 https://juejin.im/post/5dba91e4518825647e4ef18b
1 | function Reat(x, y, width, height, color) { |
1 | let ctx = canvas.getContext("2d"); |
1 | function Snake() { |
1 | //键盘事件传值 |
1 | food = isfood(); |
1 | function getNum(min, max) { |
1 | function isRect(rect1, rect2) { |
1 | function animate() { |
1 | function start() { |
1 | function stop() { |
fillStyle = color
设置图形的填充颜色。strokeStyle = color
设置图形轮廓的颜色
color 可以表示为 css 颜色值得字符串,渐变对象,或者图像对象默认都是黑色.重复赋值,新的生效
通过设置 globalAlpha 属性或者使用一个 rgba 设置透明度
这个属性影响到 canvas 里所有图形的透明度,有效的值范围是 0.0 (完全透明)到 1.0(完全不透明),默认是 1.0。
globalAlpha 属性在需要绘制大量拥有相同透明度的图形时候相当高效。
1 | function draw() { |
1 | function draw() { |
lineWidth = value
设置线条宽度。lineCap = type
设置线条末端样式。lineJoin = type
设定线条与线条间接合处的样式。miterLimit = value
限制当两条线相交时交接处最大长度;线条交接处内角顶点到外角顶点的长度。getLineDash()
返回一个包含当前虚线样式,长度为非负偶数的数组。setLineDash(segments)
设置当前虚线样式。lineDashOffset = value
设置虚线样式的起始偏移量。
这个属性设置当前绘线的粗细。属性值必须为正数。默认值是 1.0。线宽是指给定路径的中心到两边的粗细。
1 | function draw() { |
属性 lineCap 的值决定了线段端点显示的样子。它可以为下面的三种的其中之一:butt,round 和 square。默认是 butt。
1 | function draw() { |
lineJoin 的属性值决定了图形中两线段连接处所显示的样子。它可以是这三种之一:round, bevel 和 miter。默认是 miter。
1 | function draw() { |
miterLimit 属性就是用来设定外延交点与连接点的最大距离,如果交点距离大于此值,连接效果会变成了 bevel。
1 | function draw() { |
createLinearGradient(x1, y1, x2, y2)
createLinearGradient 方法接受 4 个参数,表示渐变的起点 (x1,y1) 与终点 (x2,y2)。createRadialGradient(x1, y1, r1, x2, y2, r2)
createRadialGradient 方法接受 6 个参数,前三个定义一个以 (x1,y1) 为原点,半径为 r1 的圆,后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆。
1 | function draw() { |
1 | function draw() { |
好记性不如烂笔头,跟着文档一顿敲
]]>Git 常用命令速查
git branch 查看本地所有分支
git status 查看当前状态
git commit 提交
git branch -a 查看所有的分支
git branch -r 查看远程所有分支
git commit -am “init” 提交并且加注释
git remote add origin git@192.168.1.119:ndshow
git push origin master 将文件给推到服务器上
git remote show origin 显示远程库 origin 里的资源
git push origin master:develop
git push origin master:hb-dev 将本地库与服务器上的库进行关联
git checkout –track origin/dev 切换到远程 dev 分支
git branch -D master develop 删除本地库 develop
git checkout -b dev 建立一个新的本地分支 dev
git merge origin/dev 将分支 dev 与当前分支进行合并
git checkout dev 切换到本地 dev 分支
git remote show 查看远程库
git add .
git rm 文件名(包括路径) 从 git 中删除指定文件
git clone git://github.com/schacon/grit.git 从服务器上将代码给拉下来
git config –list 看所有用户
git ls-files 看已经被提交的
git rm [file name] 删除一个文件
git commit -a 提交当前 repos 的所有的改变
git add [file name] 添加一个文件到 git index
git commit -v 当你用-v 参数的时候可以看 commit 的差异
git commit -m “This is the message describing the commit” 添加 commit 信息
git commit -a -a 是代表 add,把所有的 change 加到 git index 里然后再 commit
git commit -a -v 一般提交命令
git log 看你 commit 的日志
git diff 查看尚未暂存的更新
git rm a.a 移除文件(从暂存区和工作区中删除)
git rm –cached a.a 移除文件(只从暂存区中删除)
git commit -m “remove” 移除文件(从 Git 中删除)
git rm -f a.a 强行移除修改后文件(从暂存区和工作区中删除)
git diff –cached 或 $ git diff –staged 查看尚未提交的更新
git stash push 将文件给 push 到一个临时空间中
git stash pop 将文件从临时空间 pop 下来
-——————————————————–
git remote add origin git@github.com:username/Hello-World.git
git push origin master 将本地项目给提交到服务器中
-———————————————————-
git pull 本地与服务器端同步
-—————————————————————-
git push (远程仓库名) (分支名) 将本地分支推送到服务器上去。
git push origin serverfix:awesomebranch
-—————————————————————–
git fetch 相当于是从远程获取最新版本到本地,不会自动 merge
git commit -a -m “log_message” (-a 是提交所有改动,-m 是加入 log 信息) 本地修改同步至服务器端 :
git branch branch_0.1 master 从主分支 master 创建 branch_0.1 分支
git branch -m branch_0.1 branch_1.0 将 branch_0.1 重命名为 branch_1.0
git checkout branch_1.0/master 切换到 branch_1.0/master 分支
du -hs
git branch 删除远程 branch
git push origin :branch_remote_name
git branch -r -d branch_remote_name
-———————————————————-
初始化版本库,并提交到远程服务器端
mkdir WebApp
cd WebApp
git init 本地初始化
touch README
git add README 添加文件
git commit -m ‘first commit’
git remote add origin git@github.com:daixu/WebApp.git
增加一个远程服务器端
上面的命令会增加 URL 地址为‘git@github.com:daixu/WebApp.git’,名称为 origin 的远程服务器库,以后提交代码的时候只需要使用 origin 别名即可
命令 | 简要说明 |
---|---|
git add | 添加至暂存区 |
git add–interactive | 交互式添加 |
git apply | 应用补丁 |
git am | 应用邮件格式补丁 |
git annotate | 同义词,等同于 git blame |
git archive | 文件归档打包 |
git bisect | 二分查找 |
git blame | 文件逐行追溯 |
git branch | 分支管理 |
git cat-file | 版本库对象研究工具 |
git checkout | 检出到工作区、切换或创建分支 |
git cherry-pick | 提交拣选 |
git citool | 图形化提交,相当于 git gui 命令 |
git clean | 清除工作区未跟踪文件 |
git clone | 克隆版本库 |
git commit | 提交 |
git config | 查询和修改配置 |
git describe | 通过里程碑直观地显示提交 ID |
git diff | 差异比较 |
git difftool | 调用图形化差异比较工具 |
git fetch | 获取远程版本库的提交 |
git format-patch | 创建邮件格式的补丁文件。参见 git am 命令 |
git grep | 文件内容搜索定位工具 |
git gui | 基于 Tcl/Tk 的图形化工具,侧重提交等操作 |
git help | 帮助 |
git init | 版本库初始化 |
git init-db* | 同义词,等同于 git init |
git log | 显示提交日志 |
git merge | 分支合并 |
git mergetool | 图形化冲突解决 |
git mv | 重命名 |
git pull | 拉回远程版本库的提交 |
git push | 推送至远程版本库 |
git rebase | 分支变基 |
git rebase–interactive | 交互式分支变基 |
git reflog | 分支等引用变更记录管理 |
git remote | 远程版本库管理 |
git repo-config* | 同义词,等同于 git config |
git reset | 重置改变分支“游标”指向 |
git rev-parse | 将各种引用表示法转换为哈希值等 |
git revert | 反转提交 |
git rm | 删除文件 |
git show | 显示各种类型的对象 |
git stage* | 同义词,等同于 git add |
git stash | 保存和恢复进度 |
git status | 显示工作区文件状态 |
git tag | 里程碑管理 |
命令 | 简要说明 |
---|---|
git commit-tree | 从树对象创建提交 |
git hash-object | 从标准输入或文件计算哈希值或创建对象 |
git ls-files | 显示工作区和暂存区文件 |
git ls-tree | 显示树对象包含的文件 |
git mktag | 读取标准输入创建一个里程碑对象 |
git mktree | 读取标准输入创建一个树对象 |
git read-tree | 读取树对象到暂存区 |
git update-index | 工作区内容注册到暂存区及暂存区管理 |
git unpack-file | 创建临时文件包含指定 blob 的内容 |
git write-tree | 从暂存区创建一个树对象 |
命令 | 简要说明 |
---|---|
git check-ref-format | 检查引用名称是否符合规范 |
git for-each-ref | 引用迭代器,用于 shell 编程 |
git ls-remote | 显示远程版本库的引用 |
git name-rev | 将提交 ID 显示为友好名称 |
git peek-remote* | 过时命令,请使用 git ls-remote |
git rev-list | 显示版本范围 |
git show-branch | 显示分支列表及拓扑关系 |
git show-ref | 显示本地引用 |
git symbolic-ref | 显示或者设置符号引用 |
git update-ref | 更新引用的指向 |
git verify-tag | 校验 GPG 签名的 Tag |
命令 | 简要说明 |
---|---|
git count-objects | 显示松散对象的数量和磁盘占用 |
git filter-branch | 版本库重构 |
git fsck | 对象库完整性检查 |
git fsck-objects* | 同义词,等同于 git fsck |
git gc | 版本库存储优化 |
git index-pack | 从打包文件创建对应的索引文件 |
git lost-found* | 过时,请使用 git fsck –lost-found 命令 |
git pack-objects | 从标准输入读入对象 ID,打包到文件 |
git pack-redundant | 查找多余的 pack 文件 |
git pack-refs | 将引用打包到 .git/packed-refs 文件中 |
git prune | 从对象库删除过期对象 |
git prune-packed | 将已经打包的松散对象删除 |
git relink | 为本地版本库中相同的对象建立硬连接 |
git repack | 将版本库未打包的松散对象打包 |
git show-index | 读取包的索引文件,显示打包文件中的内容 |
git unpack-objects | 从打包文件释放文件 |
git verify-pack | 校验对象库打包文件 |
命令 | 简要说明 |
---|---|
git fetch-pack | 执行 git fetch 或 git pull 命令时在本地执行此命令,用于从其他版本库获取缺失的对象 |
git receive-pack | 执行 git push 命令时在远程执行的命令,用于接受推送的数据 |
git send-pack | 执行 git push 命令时在本地执行的命令,用于向其他版本库推送数据 |
git upload-archive | 执行 git archive –remote 命令基于远程版本库创建归档时,远程版本库执行此命令传送归档 |
git upload-pack | 执行 git fetch 或 git pull 命令时在远程执行此命令,将对象打包、上传 |
命令 | 简要说明 |
---|---|
git imap-send | 将补丁通过 IMAP 发送 |
git mailinfo | 从邮件导出提交说明和补丁 |
git mailsplit | 将 mbox 或 Maildir 格式邮箱中邮件逐一提取为文件 |
git request-pull | 创建包含提交间差异和执行 PULL 操作地址的信息 |
git send-email | 发送邮件 |
命令 | 简要说明 |
---|---|
git daemon | 实现 Git 协议 |
git http-backend | 实现 HTTP 协议的 CGI 程序,支持智能 HTTP 协议 |
git instaweb | 即时启动浏览器通过 gitweb 浏览当前版本库 |
git shell | 受限制的 shell,提供仅执行 Git 命令的 SSH 访问 |
git update-server-info | 更新哑协议需要的辅助文件 |
git http-fetch | 通过 HTTP 协议获取版本库 |
git http-push | 通过 HTTP/DAV 协议推送 |
git remote-ext | 由 Git 命令调用,通过外部命令提供扩展协议支持 |
git remote-fd | 由 Git 命令调用,使用文件描述符作为协议接口 |
git remote-ftp | 由 Git 命令调用,提供对 FTP 协议的支持 |
git remote-ftps | 由 Git 命令调用,提供对 FTPS 协议的支持 |
git remote-http | 由 Git 命令调用,提供对 HTTP 协议的支持 |
git remote-https | 由 Git 命令调用,提供对 HTTPS 协议的支持 |
git remote-testgit | 协议扩展示例脚本 |
命令 | 简要说明 |
---|---|
git archimport | 导入 Arch 版本库到 Git |
git bundle | 提交打包和解包,以便在不同版本库间传递 |
git cvsexportcommit | 将 Git 的一个提交作为一个 CVS 检出 |
git cvsimport | 导入 CVS 版本库到 Git。或者使用 cvs2git |
git cvsserver | Git 的 CVS 协议模拟器,可供 CVS 命令访问 Git 版本库 |
git fast-export | 将提交导出为 git-fast-import 格式 |
git fast-import | 其他版本库迁移至 Git 的通用工具 |
git svn | Git 作为前端操作 Subversion |
命令 | 简要说明 |
---|---|
git merge-base | 供其他脚本调用,找到两个或多个提交最近的共同祖先 |
git merge-file | 针对文件的两个不同版本执行三向文件合并 |
git merge-index | 对 index 中的冲突文件调用指定的冲突解决工具 |
git merge-octopus | 合并两个以上分支。参见 git merge 的 octopus 合并策略 |
git merge-one-file | 由 git merge-index 调用的标准辅助程序 |
git merge-ours | 合并使用本地版本,抛弃他人版本。参见 git merge 的 ours 合并策略 |
git merge-recursive | 针对两个分支的三向合并。参见 git merge 的 recursive 合并策略 |
git merge-resolve | 针对两个分支的三向合并。参见 git merge 的 resolve 合并策略 |
git merge-subtree | 子树合并。参见 git merge 的 subtree 合并策略 |
git merge-tree | 显式三向合并结果,不改变暂存区 |
git fmt-merge-msg | 供执行合并操作的脚本调用,用于创建一个合并提交说明 |
git rerere | 重用所记录的冲突解决方案 |
命令 | 简要说明 |
---|---|
git bisect–helper | 由 git bisect 命令调用,确认二分查找进度 |
git check-attr | 显示某个文件是否设置了某个属性 |
git checkout-index | 从暂存区拷贝文件至工作区 |
git cherry | 查找没有合并到上游的提交 |
git diff-files | 比较暂存区和工作区,相当于 git diff –raw |
git diff-index | 比较暂存区和版本库,相当于 git diff –cached –raw |
git diff-tree | 比较两个树对象,相当于 git diff –raw A B |
git difftool–helper | 由 git difftool 命令调用,默认要使用的差异比较工具 |
git get-tar-commit-id | 从 git archive 创建的 tar 包中提取提交 ID |
git gui–askpass | 命令 git gui 的获取用户口令输入界面 |
git notes | 提交评论管理 |
git patch-id | 补丁过滤行号和空白字符后生成补丁唯一 ID |
git quiltimport | 将 Quilt 补丁列表应用到当前分支 |
git replace | 提交替换 |
git shortlog | 对 git log 的汇总输出,适合于产品发布说明 |
git stripspace | 删除空行,供其他脚本调用 |
git submodule | 子模组管理 |
git tar-tree | 过时命令,请使用 git archive |
git var | 显示 Git 环境变量 |
git web–browse | 启动浏览器以查看目录或文件 |
git whatchanged | 显示提交历史及每次提交的改动 |
git-mergetool–lib | 包含于其他脚本中,提供合并/差异比较工具的选择和执行 |
git-parse-remote | 包含于其他脚本中,提供操作远程版本库的函数 |
git-sh-setup | 包含于其他脚本中,提供 shell 编程的函数库 |
在 Three.js 中要渲染物体到网页中,需要三个组建:场景(scene),相机(camera)和渲染器(renderer).必须有着三个东西,才能将物体渲染到网页中
创建这三要素的代码如下:
1 | var scene = new THREE.Scene(); //场景 |
在 Threejs 中场景只有一种,用 var scene = new THREE.Scene(); 构建
相机决定了场景中那个角度的景色会显示出来,相机就像人的眼睛一样,人站在不同位置,抬头或者低头都能够看到不同的景色。
场景只有一种,但是相机却又很多种。和现实中一样,不同的相机确定了呈相的各个方面。比如有的相机适合人像,有的相机适合风景,专业的摄影师根据实际用途不一样,选择不同的相机。对程序员来说,只要设置不同的相机参数,就能够让相机产生不一样的效果。
在 Threejs 中有多种相机,这里介绍两种,它们是:
透视相机(THREE.PerspectiveCamera)、这里我们使用一个透视相机,透视相机的参数很多,这里先不详细讲解。后面关于相机的那一章,我们会花大力气来讲。定义一个相机的代码如下所示:
1 | var camera = new THREE.PerspectiveCamera( |
使用 babylonjs 创建盒子
1 | var box = BABYLON.MeshBuilder.CreateBox("box", {}, scene); //默认盒子; |
盒子第二个基本属性参数可以是下面的值:
选型 | 值 | 默认值 |
---|---|---|
size | 盒子边长大小 | 1 |
height | 盒子的高度 | size |
width | 盒子的宽度 | size |
depth | 盒子的深度 | size |
faceColors | 盒子 6 个面的颜色,是一个 6 个元素的 Color4 数组 | 每个面默认白色 Color4(1, 1, 1, 1) |
faceUV | 盒子 6 个面的法向量 | 默认法向量 UVs(0, 0, 1, 1) |
updatable | 是否可以更新 | false 就是不可以改变其属性 |
sideOrientation | (number) 盒子绘里面,还是外面 | DEFAULTSIDE(缺省面) |
使用 babylonjs 创建一个球体
1 | var sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {}, scene); //默认球体 |
参数一:球体的名字
参数二:球体的基本属性
参数三:它将放到的那个场景的变量
参数二是一个元组,可取值如下:
选型 | 值 | 默认值 |
---|---|---|
segments | 细分段数 | 32 |
diameter | 圆的半径 | 1 |
diameterX | x 轴径大小, 如果写了会重写 diameter 参数 | diameter |
diameterY | y 轴径大小, 如果写了会重写 diameter 参数 | diameter |
diameterZ | z 轴径大小, 如果写了会重写 diameter 参数 | diameter |
arc | 这是一个比较难的参数,建议你想放弃理解 | 1 |
slice | 这是一个比较难的参数,建议你想放弃理解 | 1 |
updatable | 这个网格是否改变属性 | false |
sideOrientation | (number) 盒子绘里面,还是外面 | DEFAULTSIDE |
使用 babylonjs 创建一个平面
1 | var plane = BABYLON.MeshBuilder.CreatePlane("plane", {}, scene); // default plane |
选型 | 值 | 默认值 |
---|---|---|
size | 平面的长宽高 | 1 |
width | 单独设置平面的长 | size |
height | 单独设置平面的宽 | size |
updatable | 这个网格是否可以更新 | false |
sideOrientation | 盒子绘里面,还是外面 | DEFAULTSIDE |
frontUVs | 正面的法向量数组 | Vector4(0,0, 1,1) |
backUVs | (Vector4[]) 背面的法向量数组 | Vector4(0,0, 1,1) |
sourcePlane | (Plane) source plane (maths) the mesh will be transformed to | null |
Model(模型):是应用程序中用于处理应用程序数据逻辑的部分.通常模型对象负责在数据库中存取数据。
1 | 比如我们人类有一双手,一双眼睛,一个脑袋,没有尾巴,这就是模型,Model定义了这个模块的数据模型。 |
View(视图):是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。
1 | View,视图,简单来说,就是我们在界面上看见的一切。 |
Controller(控制器):是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
1 | Controller是MVC中的数据和视图的协调者,也就是在Controller里面把Model的数据赋值给View来显示 |
各部分之间的通信方式如下。 所有通信都是单向的。
MVVM 模式将 Controller 改名为 ViewModel.
它采用双向绑定(data-binding):View 的变动,自动反映在 ViewModel,反之亦然。
]]>防抖和节流目前是前端开发中最重要的 2 个函数
在输入框中输入自己搜索的内容
但是事实上不根本不需要怎么多次请求
监听页面滚动事件
鼠标移动事件
按钮点击事件
基本功能
代码实现
1 | function debounce(fn, time) { |
优化参数和 this
通常 input 事件触发都会带有参数传递,而且触发函数的 this 指向当前元素节点
上方代码的 fn 函数是个普通的函数,this 指向 window,且没有携带参数
1 | function debounce(fn, time) { |
基本功能
使用时间戳方式来实现
1 | function throttle(fn, interval) { |
变量的作用域
要理解闭包,首先必须理解 Javascript 特殊的变量作用域。
变量的作用域无非就是两种:全局变量和局部变量。
Javascript 特殊之处,就在于函数内部可以直接读取全局变量。
1 | var n = 999; |
在函数外部自然无法读取函数内的局部变量。
1 | function f1() { |
函数内部声明变量的时候,一定要使用 var/let/const 命令。如果不用的话,你实际上声明了一个全局变量!
1 | function f1() { |
从外部读取局部变量
在函数的内部,再定义一个函数。
1 | function f1() { |
闭包的概念
上述事例代码 f2 就是闭包.我的理解是,闭包就是能够读取其他函数内部变量的函数。
由于在 Javascript 语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成”定义在一个函数内部的函数”.闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包的用途
一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
1 | function f1() { |
在这段代码中,result 就是闭包 f2 函数它一共运行了两次,第一次的值是 999,第二次的值是
1000。这证明了,函数 f1 中的局部变量 n 一直保存在内存中,并没有在 f1 调用后被自动清除。
为什么会这样呢?因就在于 f1 是 f2 的父函数,而 f2 被赋给了一个全局变量,这导致 f2 始终在内存中,而 f2 的存在依赖于 f1,因此 f1 也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
这段代码中另一个值得注意的地方,就是”nAdd=function(){n+=1}”这一行,首先在 nAdd 前面没有使用 var 关键字,因此 nAdd 是一个全局变量,而不是局部变量。其次,nAdd 的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以 nAdd 相当于是一个 setter,可以在函数外部对函数内部的局部变量进行操作。
使用闭包的注意点
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,
闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value)
思考题
1 | var name = "The Window"; |
1 | var name = "The Window"; |
prototype
每个函数都要一个 prototype 属性
每个 JavaScript 对象(null 除外)在创建的时候就会关联另一个对象.这个对象就是我们所说的原型,每一个对象都会从原型”继承”属性。
1 | function Person() {} |
proto
每一个 JavaScript 对象(null 除外)都具有一个属性,叫 proto,这个属性会指向该对象原型
1 | function Person() {} |
constructor
每一个原型都有一个 constructor 属性指向关联的构造函数 实例原型指向构造函数
1 | function Person() {} |
1 | function Person() {} |
**实例与原型
1 | function Person() {} |
在这个例子中,我们给实例对象 person 添加了 name 属性,当我们打印 person.name 的时候,结果自然为 Daisy。
但是当我们删除了 person 的 name 属性时,读取 person.name,从 person 对象中找不到 name 属性就会从 person 的原型也就是 person.proto ,也就是 Person.prototype 中查找,幸运的是我们找到了 name 属性,结果为 Kevin。
原型与原型
1 | var obj = new Object(); |
原型链
最终指向 nullconsole.log(Object.prototype.__proto__ === null) // true
总结
1 | person.__proto__ = Person.prototype; |
1 在 javascript 中,下列不属于数组方法的是()
2 白屏时间 first paint 和可交互时间 dom ready 的关系是?
3 页面有一个按钮 button id 为 button1,通过原生的 js 如何禁用?()
4 关于 JavaScript 里的 xml 处理,以下说法正确的是 ()
什么是 XML?
XML 与 HTML 的主要差异
5 如何获取下面表单 select 域的选择部分的文本?()
1 | window.onload = function () { |
6 解释型语言的特性有什么?
1 | 解释性语言和编译性语言的定义: |
7 只能输入零和非零开头的数字,正确的正则表达式是()
1 | 只能输入零/非零开头的数字 |
8 以下哪些方法会返回一个数组?
1 | A.Object.keys() |
网页在生成的时候,至少会渲染一次,在用户访问的过程中,还会不断重新渲染.
重新渲染需要重复之前的第四步(重新生成布局)+第五步(重新绘制)或者只有第五个步(重新绘制)。
只改变元素外观,不会引起网页重排,但当浏览器重排之后,将会重新绘制重排影响的部分
“重绘”不一定会出现”重排”,”重排”必然会出现”重绘”
概念
当 DOM 的变化影响了元素的几何信息(DOM 对象的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。
常见引起重排属性和方法
任何会改变元素几何信息(元素的位置和尺寸大小)的操作,都会触发重排
常见引起重排属性和方法 | |||
---|---|---|---|
width | height | margin | padding |
display | border | position | overflow |
clientWidth | clientHeight | clientTop | clientLeft |
offsetWidth | offsetHeight | offsetTop | offsetLeft |
scrollWidth | scrollHeight | scrollTop | scrollLeft |
scrollIntoView() | scrollTo() | getComputedStyle() | — |
getBoundingClientRect() | scrollIntoViewIfNeeded() | — | — |
由于浏览器渲染界面是基于流失布局模型的,所以触发重排时会对周围 DOM 重新排列,影响的范围有两种:
全局范围重排:
1 | <body> |
局部范围重排
把一个 dom 的宽高之类的几何信息定死,然后在 dom 内部触发重排,就只会重新渲染该 dom 内部的元素,而不会影响到外界。
概念
当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。
常见的引起重绘的属性:
color | border-style | visibility | background |
text-decoration | background-image | background-position | background-repeat |
outline-color | outline | outline-style | border-radius |
outline-width | box-shadow | background-size |
1 | div.style.left = "10px"; |
这段代码理论上会触发 4 次重排+重绘,因为每一次都改变了元素的几何属性,实际上最后只触发了一次重排,这都得益于浏览器的渲染队列机制:
当我们修改了元素的几何属性,导致浏览器触发重排或重绘时。它会把该操作放进渲染队列,等到队列中的操作到了一定的数量或者到了一定的时间间隔时,浏览器就会批量执行这些操作。
1 | div.style.left = "10px"; |
这段代码会触发 4 次重排+重绘,因为在console
中你请求的这几个样式信息,无论何时浏览器都会立即执行渲染队列的任务,即使该值与你操作中修改的值没关联。
因为队列中,可能会有影响到这些值的操作,为了给我们最精确的值,浏览器会立即重排+重绘。
强制刷新队列的 style 样式请求
在开发中,应该谨慎的使用这些 style 请求,注意上下文关系,避免一行代码一个重排,这对性能是个巨大的消耗
1 | div.style.left = "10px"; |
还是上面触发 4 次重排+重绘的代码,这次只触发了一次重排:
在第一个console
的时候,浏览器把之前上面四个写操作的渲染队列都给清空了。剩下的 console,因为渲染队列本来就是空的,所以并没有触发重排,仅仅拿值而已。
建议通过改变 class 或者 csstext 属性集中改变样式
1 | // bad |
1 | // bad 强制刷新 触发两次重排 |
在要多次
操作 dom 之前,通过 display 隐藏 dom,当操作完成之后,才将元素的 display 属性为可见,因为不可见的元素不会触发重排和重绘。这样就只会触发 2 次
1 | dom.display = "none"; |
通过使用 DocumentFragment 创建一个 dom 碎片,在它上面批量操作 dom,操作完成之后,再添加到文档中,这样只会触发一次重排。
position 属性为 absolute 或 fixed 的元素,重排开销比较小,不用考虑它对其他元素的影响
可以把动画效果应用到 position 属性为 absolute 或 fixed 的元素上,这样对其他元素影响较小
启用 GPPU 加速
GPU(图像加速器)
GPU 硬件加速是指应用 GPU 的图形性能对浏览器中的一些图形操作交给 GPU 来完成,因为 GPU 是专门为处理图形而设计,所以它在速度和能耗上更有效率。
GPU 加速通常包括以下几个部分:Canvas2D,布局合成, CSS3 转换(transitions),CSS3 3D 变换(transforms),WebGL 和视频(video)。
1 | /* |
重排也是导致 DOM 脚本执行效率低的关键因素之一,重排与重绘作为大厂经常出现的面试题,并且涉及的性能优化,这是前端必须掌握的基本概念/技能之一(敲黑板!)。
重排会不断触发这是不可避免的,但我们在开发时,应尽量按照文中的建议来组织代码,这种优化,需要平时有意识的去做,一点一滴的去做,希望大家重视一下。
]]>作者:OBKoro1 来源:掘金
链接:https://juejin.im/post/5c15f797f265da61141c7f86
canvas 标签只有 2 个属性,宽度和高度,在没设置宽度高度时,初始化宽度为 300 和 150 像素,
该元素可以使用 CSS 来定义大小,但在绘制时图像会伸缩以适应它的框架尺寸:如果 CSS 的尺寸与初始画布的比例不一致,它会出现扭曲.
canvas 元素默认是空白的,为了使用 canvas 需要找到渲染上下文,然后进行绘制它有一个 getcontext()
方法.通过这个方法获得渲染上下文进行绘画
fillRect(x,y,width,height)
绘制一个填充的矩形strokeRect(x,y,width,height)
绘制一个矩形边框clearRect(x,y,width,height)
清除指定矩形区域,让清除部分完全透明。
矩形例子
1 | var canvas = document.getElementById("canvas"); |
图形的基本元素是路径,路径通过不同颜色和宽度的线段或曲线连接形成不同的形状的集合
一个路径,甚至一个子路径,都是闭合的。使用路径绘制图形需要一些额外的步骤。
beginPath()
新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。closePath()
闭合路径之后图形绘制命令又重新指向到上下文中。stroke()
以线条形式绘制fill()
填充路径绘制
当前路径为空,即调用 beginPath()之后,或者 canvas 刚建的时候,第一条路径构造命令通常被视为是 moveTo(),无论实际上是什么。出于这个原因,你几乎总是要在设置路径之后专门指定你的起始位置。
闭合路径 closePath(),不是必需的。这个方法会通过绘制一条从当前点到开始点的直线来闭合图形。如果图形是已经闭合了的,即当前点为开始点,该函数什么也不做。
当你调用 fill()函数时,所有没有闭合的形状都会自动闭合,所以你不需要调用 closePath()函数。但是调用 stroke()时不会自动闭合。
moveTo(x,y)
将笔触移动到指定的坐标 x 以及 y 上。(定义路径起点)
当 canvas 初始化或者 beginPath()调用后,你通常会使用 moveTo()函数设置起点。我们也能够使用 moveTo()绘制一些不连续的路径。看一下下面的笑脸例子。我将用到 moveTo()方法(红线处)的地方标记了。lineTo(x, y)
绘制一条从当前位置到指定 x 以及 y 位置的直线。
该方法有两个参数:x 以及 y ,代表坐标系中直线结束的点。开始点和之前的绘制路径有关,之前路径的结束点就是接下来的开始点,开始点也可以通过 moveTo()函数改变。arc(x,y,radius,startAngle,endAngle,anticlockwise)
画一个以(x,y)为圆心的以 radius 为半径的圆弧(圆),从 startAngle 开始到 endAngle 结束,按照 anticlockwise 给定的方向(默认为顺时针)来生成。arcTo(x1, y1, x2, y2, radius)
据给定的控制点和半径画一段圆弧,再以直线连接两个控制点。
arc 方法,该方法有六个参数:x,y 为绘制圆弧所在圆上的圆心坐标。radius 为半径。startAngle 以及 endAngle 参数用弧度定义了开始以及结束的弧度。这些都是以 x 轴为基准。参数 anticlockwise 为一个布尔值。为 true 时,是逆时针方向,否则顺时针方向。
arc()函数中表示角的单位是弧度,不是角度。角度与弧度的 js 表达式:弧度=(Math.PI/180)*角度。
1 | var canvas = document.getElementById("canvas"); |
贝塞尔曲线一般用来绘制复杂有规律的图形。quadraticCurveTo(cp1x, cp1y, x, y)
绘制二次贝塞尔曲线,cp1x,cp1y 为一个控制点,x,y 为结束点。bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
绘制三次贝塞尔曲线,cp1x,cp1y 为控制点一,cp2x,cp2y 为控制点二,x,y 为结束点。
二次贝塞尔曲线有一个开始点(蓝色)、一个结束点(蓝色)以及一个控制点(红色),而三次贝塞尔曲线有两个控制点。
参数 x、y 在这两个方法中都是结束点坐标。cp1x,cp1y 为坐标中的第一个控制点,cp2x,cp2y 为坐标中的第二个控制点。
1 | var canvas = document.getElementById("canvas"); |
1 | use mydata |
1 | db.mydata.insert({"name":李四}) |
1 | use mydata 切换到要被删除的数据库 |
1 | use mydata 创建数据库 |
字段 | 类型 | 描述 |
---|---|---|
capped | 布尔 | 可选,如果为true,创建固定集合,固定集合是指由着固定大小的集合当达到最大值时,它会自动覆盖最早的文档。当该值为 true 时,必须指定 size 参数 |
autoIndexId | 布尔 | (可选)如为 true,自动在 _id 字段创建索引。默认为 false。 |
size | 数值 | (可选)为固定集合指定一个最大值,以千字节计(KB)。如果 capped 为 true,也需要指定该字段。 |
max | 数值 | (可选)指定固定集合中包含文档的最大数量。 |
创建固定集合 mycol,整个集合空间大小 6142800 KB, 文档最大个数为 10000 个。
1 | db.createCollection("mycol", { capped : true, autoIndexId : true, size : |
在 MongoDB 中,你不需要创建集合。当你插入一些文档时,MongoDB 会自动创建集合。
1 | db.mycol2.insert({"name" : "菜鸟教程"}) |
1
2
3
4
5
db.col.insert({
title: 'MongoDB ',
content:'一个nosql数据库',
text:'文档的数据结构和 JSON 基本一样。'
})
我们也可以将数据定义为一个变量
1 | document=({ |
执行插入操作:
1 | db.col.insert(document)WriteResult({"nInserted":1}) |
1 | var document = db.collection.insertOne({"a": 3}) |
1 | > var res = db.collection.insertMany([{"b": 3}, {'c': 4}]) |
1 | db.collection.update( |
1 | db.col.update({'title':'MongoDB'},{$set:{'title':'mongodb'}}) |
1 | db.collection.remove( |
vuex 顾名思义是一款为 vue 而生的状态管理工具。
vue 本身自带着 store 模式,其实就是全局注册一个对象,实现数据共享。适合小型数据量少的项目。
vuex 适合复杂的单页面应用,涉及到多层次嵌套,多层次组件传值,不同视图对一个状态或者接口的处理。
vuex 工作原理
npm install –save vuex
vuex 中的数据源,我们需要保存的数据就保存在这里,可以在页面通过 this.$store.state 来获取我们定义的数据;
Getter 相当于 vue 中的 computed 计算属性,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被
重新计算,这里我们可以通过定义 vuex 的 Getter 来获取,Getters 可以用于监听、state 中的值的变化,返回计算后的结果
数据我们在页面是获取到了,但是如果我们需要修改值怎么办?如果需要修改 store 中的值唯一的方法就是提交 mutation 来修改
官方并不介意我们这样直接去修改 store 里面的值,而是让我们去提交一个 actions,在 actions 中提交 mutation 再去修改状态值,
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
mapState 、mapGetters 、 mapMutations 、mapActions
调用 | 方法 | 方法 |
---|---|---|
state | this.$store.state | mapState |
getters | this.$store.getters | mapGetters |
mutations | this.$store.cmmit | mapMutations |
actions | this.$store.dispatch | mapActions |
mapState
和mapGetter
的使用只能在 computed 计算属性中,mapMutations
和mapActions
使用的时候只能在 methods 中调用否则报错
index.js
1 | import Vue from "vue"; |
app.vue
1 | <template> |
使用辅助函数简化代码
1 | <template> |
1 | //安装 |
1 | <div class="course-item" v-for="course in courses" :key="course.id"> |
方法 1
1 | <template> |
方法 2
1 | <template> |
]]>this.$router.go(-1); 返回上一级
1 | //传递死数据 |
1 | //传递父组件动态数据 |
父子组件使用自定义事件
1 | <div id="app"> |
1 | <script> |
1 | <div id="app"> |
]]>在子组件中,可以使用 this.$parent直接访问该组件的父实例或组件,
父组件页可以通过this.$children 访问他所有的子组件,
而且可以递归向上或向下无限访问,直到根实例或最内层的组件。