js基础(7)

33、JS中的本地存储

把一些信息存储在当前浏览器指定域下的某一个地方(存储到物理硬盘中)
1、不能跨浏览器传输:在谷歌浏览器中存储的信息,在IE浏览器中无法获取,因为本地存储是存在当前浏览器中的某个具体位置的
2、不能跨域传输:在京东域下存储的信息,在淘宝域下不能获取到(也是为了保证安全);
3、本地存储并不安全:会导致客户端一些存储的信息泄露;

本地存储的方案

传统:cookie、session

  • cookie:把信息存储到客户端的浏览器中(但是项目服务器端也是可以获取COOKIE的)
  • session:把信息存储到服务器上(服务器存储)

HTML5新增加的API:webStorage(不兼容低版本浏览器,常用于移动端的开发)

  • localStorage:永久存储到客户端的本地
  • sessionStorage:信息的会话存储,会话窗口存在信息也存在,会话窗口关闭信息就消失了(刷新页面不会清除)

cookie、localStorage、sessionStorage的使用和区别

webStorage:localStorage、sessionStorage
以下方法localStorage、sessionStorage 都可以用且用法相同

1、localStorage.setItem([key],[value]):

  • 向客户端的本地存储一条记录;存储的[value]需要是字符串格式的,如果编写的不是字符串,浏览器也会默认转化为字符串然后再进行存储;同源下存储的[key]是不会重复的,如果之前有的话,是把存储的信息值重新的进行修改;

2、localStorage.getItem([key]):获取之前存储的指定属性名所对应的属性值
3、localStorage.removeItem([key]):移除key对应的存储记录
4、localStorage.clear():把当前源下所有的存储记录都移除掉
5、localStorage.length:获取存储的记录条数
6、localStorage.key(index):按照存储的先后顺序获取索引为index这一项的属性名是什么

cookie:document.cookie可以设置、获取cookie的值;
使用cookie需要导入自己写的cookie.js方法如下

cookieRender.set({
            name: 'age',
            value: 7
        });

cookieRender.get('age')
cookieRender.remove('age')

localStorage和sessionStorage的区别:

1、localStorage属于永久存储到本地,不管是刷新页面还是关掉页面或者是关掉浏览器,存储的内容都不会消失,只有我们自己手动的去删除才会消失(不管是杀毒软件还是浏览器自带的清除历史记录功能都不能把localStorage存储的内容移除掉)
2、sessionStorage属于临时的会话存储,只要当前的页面不关闭,信息就可以存储下来,但是页面一但关闭,存储的信息就会自动清除(F5刷新页面只是把当前的DOM结构等进行重新的渲染,会话并没有关闭)

cookie 和 localStorage的区别:

1、兼容问题:cookie兼容所有的浏览器,但是localStorage不兼容IE6~8
2、大小限制

  • cookie存储内容的大小是有限制的,一般同源下只能存储4KB的内容;
  • localStorage存储的内容也有大小限制,一般同源下只能存储5MB;

3、过期时间:cookie存储的内容是有过期时间的,而localStorage是永久存储到本地,使用杀毒软件或者浏览器自带的清除垃圾的功能都可能会把存储的cookie给删除掉,localStorage清除不掉
4、是否支持手动禁用:用户可能出于安全的角度禁用cookie(无痕浏览器),但是不能禁止localStorage。
5、处理机制:

  • cookie不是完全的本地存储,在我们使用cookie的时候,需要客户端和服务器端进行相关的通信处理(cookie总会在客户端和服务器端来回进行传输)
  • localStorage完整的本地存储,和服务器没关系;

两种方式共同的弊端:
1、安全性
不管是cookie还是localStorage都是本地明文存储;(可通过控制台->Application 看到存储的内容)
对于重要的信息我们一般不要存储到本地,如果非要存储的话我们需要把存储的信息进行加密
->可逆转加密:加密完成还可以解密回来
->不可逆转加密:MD5
2、大小存在限制
3、不能跨域(跨浏览器:在谷歌下存储的信息,在IE中无法直接获取);

服务器存储

把信息存储在指定的服务器中:真实项目中大部分都是基于服务器存储的;

真实项目中的本地存储都使用哪些东西?

cookie:
1、记住用户名密码或者是自动登录;
2、用户的部分信息,当用户登录成功后我们会把用户的一些信息记录到本地cookie中,这样在项目中的任何页面都可以知道当前登录的用户是哪一个了;
3、购物车...(存储少量信息或者是需要浏览器兼容的都需要使用cookie来进行存储)

localStorage:
1、在PC端我们可以用其存储 某一个JS或者CSS中的源代码(性能优化);
2、还可以把一些不需要经常更新的数据存储到本地,存储的时候可以设置一个存储的时间,以后重新刷新页面,看一下时间有没有超过预定的时间,如果已经超过了,我们重新获取最新数据,没超过我们使用本地数据;

34、Git

分布式版本控制系统,它是由linux(全球比较大得服务器系统)创始人花了两周时间使用C语言编写的工具(在git窗口中一般都是执行Linux命令)
什么是版本控制系统
没有版本控制系统之前,后面修改的内容会替换原有的内容,原有的内容没有做保存,以后想找都找不到;
版本控制系统的优势
1、备份文件
2、记录历史
3、回到过去
4、多段共享
5、团队协作
常用的版本控制系统
git:分布式版本控制系统
svn:集中式版本控制系统
git和svn 的区别:

  • 1、git属于分布式版本控制系统,也就是每个开发人员从中心版本库/服务器上chect out代码后会在自己的机器上克隆一个自己的版本库。无网络的时候也可以提交文件,查看历史版本记录而svn属于集中式版本控制系统(离开服务器就无法工作);
  • 2、GIT把内容按元数据方式存储,而SVN是按文件:.git目录是处于你的机器上的一个克隆版的版本库,它拥有中心版本库上所有的东西;
  • 3、Git没有一个全局版本号,而SVN有:目前为止这是跟SVN相比Git缺少的最大的一个特征。
  • 4、Git下载下来后,在本地不必联网就可以看到所有的log,很方便学习,SVN却需要联网;
  • 5、git没有严格的权限管理控制,svn则有;

集中式和分布式版本控制系统的区别:

集中式版本控制系统:所有的版本备份和历史记录都在中央服务器上,每个人的电脑仅仅是一个开发代码的地方而已;如果想要查看历史记录,我们必须联网访问到中央服务器才可以;
分布式版本控制系统:每个人都是一个单独的管理系统,在自己的本地就可以创建一个仓库,可以记录版本和历史,我们也可以像集中式一样,建立一个中央服务器,每个人可以把自己本地的信息推送到中央服务器上(仅仅是为了方便团队之间互相观看)

1.初始化仓库

建立一个文件夹,在文件夹中打开Git Bash Here,输入git init。执行完成之后,会在当前文件夹下自动生成一个.git的文件夹,说明当前文件夹就是一个本机独立的git版本控制仓库;

git status :查看当前工作区中文件的状态(是在暂存区还是在历史区)

把工作区中的内容提交到暂存区:

暂存区是临时存储,不会生成版本和历史记录的
git add xxx: 把指定的文件提交到暂存区
git add -u:把所有修改的文件(修改和删除的,新增的不包含)都提交到暂存区;
git add . :把所有修改的文件(修改和新增的,删除的不包含)都提交到暂存区;
git add -A:把所有修改的文件(修改、删除、新增的都包含)都提交到暂存区;

  • 代码为红色:文件还没提交到暂存区
  • 代码为绿色:文件已经提交到暂存区未提交到历史区

将暂存区中的内容撤回:

git rm --cached xxx(文件名需要加后缀):将提交到暂存区的xxx文件撤回
git rm --cached . -r :将所有提交到暂存区的文件撤回
git checkout .:把暂存区的内容撤回到工作区(会覆盖现有工作区中的内容,无法找回)
git reset HEAD .:把当前暂存区的内容回滚为上一次暂存区的内容

把暂存区中的内容提交到历史区:

提交到历史区的版本会生成相关版本的历史记录,如果以后想要回滚到某一次的代码,可以用git命令迁出对应的版本
git commit -m'xxx':把暂存区的内容提交到历史区,后面的内容都是对本次提交新版本的说明xxx为说明

把历史区中的文件上传到gitHub对应的仓库中

git push origin master

比较每个区域的不同

工作区VS暂存区:git diff
工作区VS历史区:git diff master
暂存区VS历史区:git diff --cached

将工作区的内容回滚到历史区中的某一个版本

git log 用来查看commit的每一个版本
git reflog:如果有回滚,则需要用此命令来查看每次commit的版本
git reset --hard 版本号 (最少7位):将暂存区和工作区的内容回滚到commit的某一个版本

细节:

不管是从工作区提交到暂存区还是从暂存区提交到历史区,每一个区域当前的内容是一直保存下来的,不会消失;
git log/git reflog 都是查看历史提交记录,

根提交(root-commit)

第一次提交到历史区域:如果我们创建一个新的仓库,但是没有做过根提交,此时我们仓库中没有任何的分支,哪怕是master;也就不存在分支切换

团队协作与分支

中央服务器(中央仓库)

公司内部都会有一个内部的中央git仓库管理服务器,我们也可以使用免费的git仓库(github)来作为我们的中央服务器仓库:
如何把本地代码推送到远程仓库上:
1.先与gitHub仓库保持链接

  • git remote add name(name可以自己修改) 地址
  • git remote rm name 移除这个链接通道
  • git remote -v:查看当前仓库链接的所有通道

2.把本地仓库的代码和版本信息推送到远程仓库上

  • git push origin master 把本机代码推送到github远程仓库上
  • git pull origin master 把远程仓库中的

一个项目中,我们一般会有以下 这样的文件

git:在当前项目中创建git仓库生成的文件(很重要)
.idea:使用webStrom开发,默认生成的文件,记录ws的一些信息(没用)
.gitignore:我们一般手动在当前项目中创建一个后缀名是gitignore的文件,这个文件中记录了每一次git提交的时候忽略不管的文件或者文件夹(可在ws中创建这个文件)
Readme.md:这个文件选择性增加,通过这个文件可以对当前的项目进行详细的描述(使用markdown编写)

在真正项目中们一般都是需要团队协作开发的,也就是会存在一个中央远程仓库,如何把gitHub上的远程仓库上的文件复制到本地,执行命令如下

git clone 远程仓库地址

克隆到本地之后就可以继续开发了,开发完成后需要把开发的内容同步到远程仓库上,还是按照之前的老步骤操作即可

git add .
git commit -m'备注'
git push origin master
更新讲义的时候只需要输入以下代码
git pull origin master

主分支模式下的团队协作

作为开发者每次提交代码之前都要先pull一下

[如果远程仓库和本地仓库不是同一个文件同一行代码冲突]

  • git会自动帮我们合并仓库中的代码与我们工作区的代码

[如果同一个文件的同一行代码冲突]

  • 找到冲突的文件,留下自己想要的代码
  • 不管之前是否commit过,都要重新的commit,然后push即可

单独分支的管理

1、每天创建一个dev分支,并且切换到这个分支上

git branch :查看现有分支
git branch dev:创建一个名叫dev的新分支(创建分支的时候会把master上的commit信息同步到新创建的分支上)
git checkout dev:切换到名叫dev的分支上
git checkout -b dev:创建一个新的dev分支并切换到dev这个分支上
git branch -D dev:删除dev这个分支(一定要在其他分支上才能删除dev分支)
git merge xxx :合并当前分支与xxx分支的内容

2、正常写代码,把每天开发的任务都先提交到自己的分支上
3、提交到远程仓库上
- 把本地自己分支dev中的内容,合并到本地自己的master分支下
- 把本地自己的分支删除(防止分支重复)
4、把本地最新合并的master分支代码,提交到远程仓库的master分支下

[具体操作]
1、创建一个仓库

2、把仓库克隆到本地
3、把源代码传递到master上
4、在本地仓库中创建gh-pages分支
5、把介绍页面放在gh-pages分支下
6、把介绍页面的内容上传到gitHub的gh-pages分支下

Linux操作系统中常用的命令

ls:查看当前目录下的文件

  • -l查看详细信息
  • -a查看隐藏文件
  • -la同时具备以上两点

cd:目录切换

  • cd ../返回上级目录
  • cd /返回根目录
  • cd xxx进入到指定文件夹
  • cd E:进入到指定的磁盘

mkdir 文件夹名字 (创建一个文件夹)
touch xxx.xxx 创建一个空文件 如:touche.txt

  • 好处:可以创建无文件名的文件
  • 在电脑隐藏文件后缀名的情况下,我们也不至于创建出1.txt.txt这样后缀名重复的文件

vi 向指定文件中插入内容 如:vi 1.txt

  • 首先我们进入命令窗口
  • 我么先按i,进入到插入内容模式
  • 编辑需要写入的内容
  • 按ESC键,然后在<font color=red>英文状态下</font>再按shift+;键,再输入wq,按回车(保存并退出)
  • 或者 输入q!,按回车(强制退出,新输入的内容不保存)

echo xxx>1.txt 把xxx内容放到1.txt文件中,如果没有这个文件则创建这个文件,新存放的内容会替换原有的内容

echo xxx>>1.txt 新的内容会追加到原有内容的后面
cat 查看文件中的内容
cp xxx 拷贝文件
rm xxxx 删除文件

  • -r 递归删除(把当前文件夹中所有的后代元素也都遍历删除)
  • -rf 强制删除 一旦删除,无法返回

35、VUE

渐进式框架
声明式渲染(无需关心如何实现)、组件化开发、客户端路由(vue-router)、大规模的数据状态(vuex)、构建工具(vue-cli)
全家桶:vue.js+vue-router+vuex+vue-cli+axious

Vue核心知识点

数据驱动(主要操作的是数据)
数据变化会导致视图自动更新
组件化开发

框架的模式

MVC单项的数据绑定

  • 只能通过改变数据来改变视图
    [图片上传失败...(image-aea078-1541658485368)]

MVVM 双向的数据绑定

  • 视图发生改变,数据也会跟着变
  • 数据发生改变,视图也会跟着改变

vue的使用方式

1、采用cdn:<script src="https://unpkg.com/vue"></script>
2、在需要的项目中安装vue模块 npm install vue,安装之后导入vue.js文件

跑环境

初始化package.json文件,在项目中执行npm init -y可自动生成一个默认的package.json文件;
由于项目依赖的模块较大,每次上传下载同步都很浪费时间,所以我们只需要上传package.json文件,里面写了所有的依赖模块,我们同步下来之后只需要在需要的项目中打开cmd窗口执行npm install,就可以把项目依赖的模块下载到;

vue中数组的变异方法(能改变原数组)

如果data中属性的值是一个数组,如果想改变数组中内容,只能使用原生的会修改原数组的方法进行修改,普通的 数组[索引]=值 不行;
操作数组的方法:(以下方法都会修改原数组)

  • unshift、push、shift、pop、splice、reverse、sort

vue中常用的(以下方法都为声明式方法,for循环为编程式方法,能清晰的看到每一步)

  • forEach、filter、map、some、every、reduce、find(ES6)

forEach,for,for in,for of的区别
forEach:不支持返回值,只是普通的循环遍历
for in:key输出的值为字符串类型,包括把数组当成对象添加的属性也可以遍历出来
for of:只返回具有数字索引的属性。这一点跟for...in循环也不一样。(不能遍历对象)

    let arr = [3, 5, 7];
    arr.foo = 'hello';
    
    for (let i in arr) {
    //for in是把arr当成对象遍历,i是属性名,包括arr的私有属性
      console.log(i); // "0", "1", "2", "foo"
    }
    
    for (let i of arr) {
    //for of是把arr当成数组遍历,i是数组中的每一项
      console.log(i); //  "3", "5", "7"
    }
    for of循环不会返回数组arr的foo属性
    如果只想拿到索引,可用keys()方法
    for (let index of ['a', 'b'].keys()) {
      console.log(index);
    }
    // 0
    // 1
    如果两个都想拿到,可用entries()方法
    for (let (index, elem) of ['a', 'b'].entries()) {
      console.log(index, elem);
    }
    // 0 "a"
    // 1 "b"

把Vue当成对象添加的私有方法

全局过滤器:Vue.filter(方法名,方法);相当于给全局过滤器中增加了一个方法(一次只能增加一个)

Vue.filter('my',data=>{return data});
//页面中使用
<div id="app">
{{count|my}}
</div>

**`创建一个全局组件`**:Vue.component(自定义标签名,需要配置的参数)
```javascript

//js代码
Vue.component('my-hand',{
template:'<h3>{{msg}}</h3>',
data(){
return {msg:'我很英俊'}
}
});
let vm=new Vue({
el:'#app'
})
//页面中使用
<div id="app">
<my-hand></my-hand>
</div>

初始化vue时传入对象中的属性

el

表示vue的属性和方法对哪个DOM根元素起作用(对它的后代元素也起作用)

data

data中的内容表示需要双向绑定时用到的数据,写在data中的属性都会挂载到当前Vue的实例上;(可以直接用vm.msg来调用);

methods

methods中的方法也将挂载到Vue的实例上。可以直接通过vm实例访问这些方法,或者在指令表达式中使用。方法中的 this 自动绑定为 Vue的实例。
指令表达式中使用方法的时候,如果方法名后面不写括号,则会默认传入事件对象MouseEvent。写括号代表要传递参数,而不是直接执行,要手动传入事件对象$event。
<font color=red>注意</font>

  • 1、methods中的方法名不能和data中的变量名一样,因为都会挂载到vue的实例上,重名会报错
  • 2、不应该使用箭头函数来定义method中的方法,因为使用箭头函数会改变函数中的this,而我们要保证方法中的this都是vue的实例
  • 3、{{}}中执行method中的方法,方法后面必须要加(),才代表执行

filters

允许你在filters中定义自己的过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号中和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号“|”来指示;
<font color=red>注意</font>:
1、filters方法中的this都是window
2、后面的方法执行的时候,会默认的把之前的值当作第一个参数传递给后面的方法 ;
3、filters中的方法在{{}}中执行的时候,可以不写括号;

<!-- 在双花括号中 -->
{{ message | toFixed(2)}}//toFixed方法执行时不改变原数据,只是改变message的显示效果
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | toFixed"></div>
filters: {
   toFixed(val,pra){
       return '¥'+val.toFixed(pra);
   }
}

computed

计算属性(会有缓存),不是方法:某一个属性的值依赖于其他值的改变而改变时,可使用computed,把需要绑定的属性写在computed中,只会跟依赖的值产生关系。属性中默认会有set和get方法,如果把计算属性写成函数,则默认只调用get方法(get方法必须要有返回值);computed不支持异步;

watch:

监听属性(默认只监控所给属性的第一层):watch中的方法名应该与data中的要监听的属性名相同。只有当监听的值发生变化的时候才会触发对应的方法;watch支持异步,当需要异步的时候,watch还支持设置中间状态;如果想要深度监控,则需要写为对象的形式,并且修改deep:true来实现深度监控;

<font color=red>计算属性和方法的区别</font>

1、缓存:计算属性会根据依赖的属性(归vue管理的数据,可以响应式的变化)进行缓存,只有在它的相关依赖发生改变时才会重新求值;
2、在{{}}中使用的时候,方法名后必须要加()来执行,而计算属性如果不需要传递参数,则不需要写();
3、方法是不管数据有没有发生改变,都会重新计算,且get方法必须有返回值;

<font color=red>什么时候用computed什么时候用watch</font>

当数据依赖于多个值的改变而改变时,我们就需要用computed;

<div id="app">
    <input type="text" v-model="val"> {{fullName}}
</div>
let vm=new Vue({
        el:'#app',
        data:{
            val:'',
            firstName:'zfpx',
            lastName:'zy'
        },
        computed:{
            fullName(){
            //只要依赖的其中一个值改变,就会执行此方法;
                return this.firstName+this.val+this.lastName;
            }
        }
    });
当监听的值发生改变的时候,数据需要跟着变,就要用watch,需要异步操作的时候,就必须用watch;
```javascript

let vm=new Vue({
el:'#app',
data:{
val:'',
firstName:'zfpx',
lastName:'zy',
fullName:''
},
watch:{
//val的值改变了才会触发下面的方法,而且会默认传入两个参数,新的值和老的值
val(newV,oldV){
this.fullName=this.firstName+this.val+this.lastName;
}
//如果写成一个函数的形式(如上的形式),则只会监控第一层级属性对应的值,第一层级的值发生改变才会触发函数执行;如果要实现深度监控,则要写成如下对象的形式,将deep深度监控属性赋值为true;
val:{
//监控时发生改变就会触发此方法,方法名必须是handler
handler(newV){
localStorage.setItem('todo',JSON.stringify(newV));
},
deep:true
}
}
});

{{}}:其中可放表达式、可以放赋值运算、计算、三元运算符(尽量少写逻辑运算)

vue的实例拥有的属性

此处的this是vue的实例
this.$data vm上的响应式的数据,是个对象
this.$watch 监控
this.$el 挂载的DOM根元素
this.$set 后加的属性实现响应式的变化
this.$nextTick(()=>{}) 异步方法,渲染DOM完成后获取到需要的最新的数据
this.$refs.xxx 获取ref值为xxx的vue对象(可通过this.$refs.xxx.$el获取DOM元素)(通过v-for循环出来的可以获取多个,否则只能获取一个)

尽管有 prop 和事件,但是有时仍然需要在 JavaScript 中直接访问子组件。为此可以使用 ref 为子组件指定一个引用的值。如:
<div id="parent">
     <user-profile ref="profile"></user-profile>
</div>
<font color=red>**注意:DOM渲染是异步的,如果数据变化后想要获取最新的真实dom中的内容,需要等待页面渲染完成后再去获取,所有的DOM操作最好放在nextTick方法中异步来获取最新的DOM;**</font>

为什么data中的属性会出现响应式的变化?

vue会循环data中的属性,依次增加getter和setter方法(数据劫持),来实现响应式的变化。(只要是data中存在的属性都会被增加getter和setter方法,不存在的属性不会存在双向数据绑定。下面的例子中属性a中没有school属性,所以修改vm.a.school的属性值不会导致视图刷新。

使用实例.$set可以给对象添加响应式的数据变化
例如:vm.$set(vm.a,'school',1)

let vm=new Vue({
el:'#app-3',
data:{
msg:'zhufeng',
a:{}
}
methods:{
}
});
//页面中使用
<div id="app">
{{a.school}}
</div>

vue中如何实现数据的双向绑定

let  obj = {name:'zhufeng',age:9};//数据
let temp = {name:"lily"};//借助中间对象
let input1 = document.getElementById("box2");//视图
//对某一个对象使用了Object.defineProperty方法之后就要写对应的get和set方法了,不然无法像操作普通对象一样访问或者设置它的属性
//此方法不兼容IE8及以下
Object.defineProperty(obj,"name",{
    configurable:true,//属性是否可删除
    writable:false,//属性是否可修改
    enumerable:false,//属性是否可枚举
    get(){//获取obj的属性名对应的属性值时会调用该方法
       /*2*/ return temp['name'];
    },
    set(val){//设置obj的属性名对应的属性值时会调用此方法
    
        //实现视图变化数据跟着变:分两步,上面get中的为第二步(即再次读取的时候会调用get方法得到之前设置的值,以此来实现动态改变)
        //由于直接写obj.name = this.value;会导致循环调用set方法,所以要借助中间对象的形式把值赋给中间对象,获取obj.name的时候我们获取中间对象的最新值即可
        /*1、*/ temp.name=val;

        //实现数据变化视图改变
        input1.value=val;
    }
});
//为了初始化的时候让视图中(文本框中)有值:出现obj.name说明要访问这个属性就会用到defineProperty中的get方法
input1.value=obj.name;
//实现视图改变数据跟着改变
input1.addEventListener("input",function(){
    obj.name = this.value;//当值变化时会调用set方法
},false);

vue中的指令

dom元素的行间属性,vue提供了内置的指令,必须以v-开头,后面的值均为变量

<font color=red>v-cloak</font>:

消除页面刚加载时会看到{{}}闪一下的效果,可加给最外层的根元素;

//需要添加对应的css样式
[v-cloak]{
  display: none;
}

<font color=red>v-model(表单元素设置了之后会忽略掉value,checked,selected)</font>

让表单元素和数据实现双向绑定(映射关系)

<input type="text" v-model="msg">

<font color=red>v-text</font>:代替 {{}} 渲染成文本(不会识别html标签)可以防止网速卡慢时{{}}出现在页面上

{{}} 中的值都会解析成文本内容;

{{msg}}等价于<div v-text="msg"></div>

<font color=red>v-html</font>:把html字符渲染成html

<div v-html="msg"></div>

<font color=red>v-once</font>:只绑定一次(不能写成v-once="msg")

<div v-once>{{msg}}</div>

<font color=red>v-bind</font>:动态地绑定一个或多个特性

// 绑定一个属性
<img v-bind:src="imageSrc">
//可缩写为如下形式,此时:src后面的值就可以是变量、表达式、赋值运算、计算、三元运算符(尽量少写逻辑运算)
<img :src="imageSrc">//此时imageSrc就代表一个变量

<font color=red>v-for</font>:遍历数组、对象、字符串、数字

解决了循环问题,更高效,会在原有的基础上进行修改,会复用原有的结构,不会修改所有DOM

要循环创建哪一个标签就在那一个标签上加v-for,后面的循环最好用in,用of有时会报错
循环数组或对象使用v-for指令
<div v-for="(val,index) in msg">
        {{val,index}}//msg为数组时,val为数组中的每一项,index为索引
</div>  
<div v-for="(value,key,index) in msg">
    {{key}}={{value}}{{index}};//msg为对象时,key为对象中的每个属性名,value为属性值,index为索引
</div>  

条件渲染:<font color=red>v-if v-else-if v-else</font>与<font color=red>v-show</font>

<font color=red>v-if v-else-if v-else</font>:条件满足才渲染v-if所在标签以及标签内的内容;(操作的是DOM结构)

  • 设置条件判断的DOM元素必须是连续的
  • 操作的是DOM元素
  • key 管理复用的元素 若不想复用DOM元素,只需要给相应的DOM元素增加不同的key值
  • 频繁的显示和隐藏用v-if会很浪费性能(操作的是DOM结构),此时要用v-show(操作的是CSS样式)
<div id="app">
    <button @click="flag=!flag">请点击</button>
//template标签是vue提供给我们的没有任何实际意义,用来包裹元素用的(v-show不支持template标签)
    <template v-if="flag">
        <label>登录</label>
        <input type="text" key="1">//key 管理复用的元素 若不想复用DOM元素,只需要给相应的DOM元素增加不同的key值
    </template>
    <template v-else>
        <label>注册</label>
        <input type="text" key="2">
    </template>
</div>
let vm=new Vue({
    el:'#app',
    data:{
        flag:true
    }
});

<font color=red>v-show</font>

条件满足才让v-show所在标签以及标签内的内容显示(操作的是元素的css样式)

<input type="text" v-show="flag">//flag为true时,input框才显示

<font color=red>v-on</font>:监听 DOM 事件(v-on:click可缩写为@click)

可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码(在 methods 对象中定义的方法,而且methods中的方法名不能和data中的变量名一样)

<div v-on:click ="fn1('zhaosi,$event')">{{msg}}</div>
<div @click ="fn1('zhaosi,$event')">{{msg}}</div>//上面的简写 
方法后面可加()可不加。不加的话默认会传入事件对象e,
加()代表要传参数,如果要用事件对象,则需要传$event

<font color=red>自定义指令</font>

可通过在vue实例的<font color=red>directives:{}</font>属性中赋予自定义指令意义

<div id="app">
 <button v-color="flag" @click="flag='blue'>变色</button>
</div>
let vm=new Vue({
   el:'#app',
   data:{
       flag:'red'
   },
   directives:{//在这里赋予对应自定义指令意义
       //可直接写对应的指令不用写v-
       color(el,val){
       //el和val都是默认给的:el指的是指令所绑定的DOM元素,val是一个对象,里面存储的是有关指令的所有信息,只能用val.value获取到指令绑定的变量(或者表达式)所代表的值,这里就是flag所代表的值 'red'
       el.style.background=val.value;
       }
   }
});

vue中的修饰符

表单修饰符

  • v-model.number:将用户的输入值转为数值类型
  • v-model.lazy:在表单触发change事件时更新数据,而非触发input事件时更新数据
  • v-model.trim:自动过滤用户输入的首尾空白字符

事件修饰符

  • @click.stop:阻止点击事件的传播(往上传播和往下传播都会被阻止)
  • @submit.prevent:阻止点击提交按钮时的默认行为(阻止事件的默认行为)
  • @click.capture:点击的时候让事件在捕获阶段执行;
  • @click.once:只在第一次点击的时候让绑定的事件执行;
  • @click.self:只有点击的事件源是自己的时候触发事件;(判断事件源)

表单元素双向数据绑定(双向同步)

使用v-model属性可让input中的内容和数据实现双向同步,但是使用了v-model属性之后,input的value、checked、select属性都会失效

<div id="app">
    <input type="text" v-model="msg">
</div>
<script src="vue.js"></script>
<script>
    let vm=new Vue({
        el:'#app',//vue的属性和方法对哪个DOM根元素起作用(对它的后代元素也起作用)
        //数据
    如果data中属性的值是一个数组,如果想改变数组中内容,只能使用原生的会修改原数组的方法进行修改,普通的 数组[索引]=值 不行;
        data:{//写在data中的属性都会挂载到当前实例上
            msg:'zhufeng'
        }
    });
    console.log(vm.msg);//'zhufeng'
</script>

单选框

对于单选框和复选框来说,加了v-model属性后,初始设置的value属性不会失效;

 <div id="app">
    <input type="radio" v-model="msg" value="男">男
    <input type="radio" v-model="msg" value="女">女
    {{msg}}
 </div>
let app3=new Vue({
   el:'#app',
   data:{
     msg:'男'//默认选中的项,值与value的值对应,点击女的时候msg就会动态改为女
   }
 });

复选框

单个复选框:

<div id="app">
//复选框中加了v-model后value依然可用
    <input type="checkbox" v-model="msg">
</div>
let app3=new Vue({
    el:'#app',
    data:{
    //如果是复选框且只有一个的时候,会把msg的值转化为布尔值,如果为true,代表选中
        msg:false//为false时代表默认不选中
    }
});
多个复选框,需要绑定到同一个数组,而且要给input设置初始value值,为了在后面选中的时候获取到对应的选中框的值
```javascript
<div id="app">
  //复选框中加了v-model后value依然可用
    <input type="checkbox" v-model="msg" value="吃饭">吃饭
    <input type="checkbox" v-model="msg" value="睡觉">睡觉
    <input type="checkbox" v-model="msg" value="敲代码">敲代码
    {{msg}}
</div>
    new Vue({
      el: '#app',
      data: {
        msg: [] //此处的msg需要是一个数组
      }
    })

下拉框

<div id="app">
//加了multiple后就变为多选框,用ctrl+左键点击多选,msg也要换为一个数组
    <select v-model="msg" multiple>
    //加了disabled时候用户就不能选中此项了
    //option中的value是给写代码的人看的
        <option value="0" disabled>请选择地区</option>
        <option value="1">北京</option>
        <option value="2">上海</option>
        <option value="3">浙江</option>
    </select>
    {{msg}}//如果option的value属性不写,则取的是option中的内容
</div>
let app3=new Vue({
    el:'#app',
    data:{
        msg:'0'//默认选中的某一项,值与每一个option的value值对应
    }
});

Vue中的Class样式与style样式动态绑定(动态的优先级高于原来的)

<font color=red>:class="{}"或者:class="[]</font>:
通过:class="{}"或者:class="[]来动态的绑定class样式,与原来的class样式不冲突。
有两种方式:
1、对象的方式绑定
2、数组的方式绑定

<div id="app">


<div class="x" :class="{z:flag,y:false}">我的世界</div>

<div class="x" :class="[y,z]">我的世界</div>
</div>
let vm=new Vue({
el:'#app',
data:{
flag:true
}
});

<font color=red>**:style="{}"或者:style="[]"**</font>:绑定行内的样式
通过上述的方式来动态绑定行内的样式
```javascript

<div id="app">
//第一种是对象的方式
<div :style="{backgroundColor:'red',color:'pink'}">我是谁</div>
//第二种是数组的方式
<div :style="[str1,str2]">我的世界</div>
</div>
let vm=new Vue({
el:'#app',
data:{
str1:{backgroundColor:'blue'},
str2:{color:'yellow'}
}
});

根据hash实现单页面开发

通过hash记录跳转的路径(可以产生历史管理)
浏览器自带的历史管理方法history(history.pushState(),push到哪里就跳转到哪里),可能会导致404错误(因为用户可能会随意输入路径)
开发时使用hash的方式,上线的时候使用history的方式
[使用hash存储]

//存储:存储的时候要把存储的对象转换成字符串
localStorage.setItem('todo',JSON.stringify(obj));
//获取:获取的时候要把字符串转换成对象
JSON.parse(localStorage.getItem('todo'));

生命周期与钩子函数

生命周期:
<font color=red>beforeCreate</font>:el 和 data 并未初始化 (此方法不常用)
<font color=red>created</font>:完成了 data 数据的初始化,el的初始化未完成。用来发送ajax

<font color=red>beforeMount</font>:(执行此方法时已经完成了 el 和 data 初始化 (已经赋予了对应的值))
渲染DOM之前先确认下是否有要编译的根元素(有无el属性),有才继续确认是否具有模板属性template,如果有模版属性,则会用template的值替换掉HTML中的结构,template模版中只能有一个根元素(而且不能是文本);
<font color=red>mounted</font>:(执行此方法时代表已经挂载结束了)
把编译好的数据挂载到DOM元素上,最后渲染成真实的DOM元素;真实DOM已经渲染完成,可以操作DOM了

<font color=red>beforeUpdate</font>:当页面依赖的数据更改之后触发(此时DOM结构还没有重新加载)
<font color=red>updated</font>:DOM结构重新加载之后触发

调用vm.$destroy()之后触发下面两个事件:
<font color=red>beforeDestroy</font>:实例销毁之前调用。在这一步,实例仍然完全可用。(可在此处清除定时器,清除事件绑定)
<font color=red>destroyed</font>:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。(意义不大)

获取数据

vue中给我们提供了一个created函数,在实例创建完成后会被立即调用。方法中的this指向的也是vue的实例

let vm=new Vue({
el:'#app',
created(){
//实例创建完成后会立即执行created方法
this->vm这个实例
},
data:{
msg:''
}
});

Promise详解与axios的使用

promise:解决回调问题,存在三个状态(成功、失败、等待)
Promise是一个类,new Promise时可传递一个函数,在new 的时候就调用传递进来的函数,而且会给函数默认传递两个参数(都是函数数据类型的)

  • 第一个参数为成功后要执行的方法
  • 第二个参数为失败后要执行的方法

Promise的实例都有一个then方法:then方法中有两个参数(成功执行的函数,失败执行的函数)

let a=new Promise((resolve,reject)=>{
let a=1,b=3;
if(a<b){
//条件满足时我们让resolve执行并传入需要的参数
resolve('条件满足');
//resolve执行时then方法中的第一个参数(函数)就会执行
}else{
//条件不满足时我们让reject执行
reject('条件不满足');
//reject执行时,then方法中的第二个参数(函数)就会执行
}
})
a.then((res)=>{
//我们在promise中规定什么时候执行resolve,此方法就什么时候执行,res为执行resolve时传递的参数
console.log(res);//条件满足
},(err)=>{
//我们在promise中规定什么时候执行reject,此方法就什么时候执行,err为执行reject时传递的参数
console.log(err);
})

axios就是基于Promise进行封装的:使用方法如下
先引入axios:
```javascript

<script src="axios.js"></script>
<script>
//使用axios:axios调用get方法后会返回Promise的一个实例,可以直接用then方法
axios.get('json/1.json').then((res)=>{
//axios成功后会执行的方法中的传递的参数为一个对象,如果要获取到需要的数据,需要用res.data;
console.log(res.data);
},(err)=>{
console.log(err);
})
</script>

36、NODE

基于事件驱动的异步编程
到达某个时候做一些事情,就是事件驱动
常人所说的node是后台编程语言,其实node只是一个工具(或者环境),我们可以把node安装在服务器上,node提供的环境可以运行js 代码,这样我们就可以在服务器端使用JS编写一些处理服务器相关操作的程序,也可以理解为node让js变为了后台编程语言;
1、NODE是基于V8引擎来渲染JS的(V8是谷歌的引擎)

  • 渲染JS的速度会很快
  • 我们在使用JS开发后台程序的时候,不需要考虑浏览器兼容了,使用JS的最新标准即可(ECMAScript)

2、单线程、无阻塞I/O操作、事件驱动(event-driven)

node安装方法

npm install/uninstall xxx -g 把xxx模块安装在全局下或从全局下卸载

  • 当前电脑的每一个项目都可以通过命令来使用全局下安装的模块
  • 但是不能通过require导入使用
  • 容易引发版本冲突

npm install/uninstall xxx 把xxx模块安装在某一个项目当中或从当前项目中卸载xxx模块

  • 安装在本地项目中的模块只能在本项目中使用
  • 不能基于命令运行,但是可以通过require导入到js中进行二次开发
  • 不会导致版本冲突
    npm root -g 查看当前电脑全局安装目录
    npm root 查看当前项目的模块安装目录
    npm ls- g/npm ls 输出全局/当前项目中已经安装的模块清单

如何让安装在本地的模块也可以基于命令操作

npm init -y :在当前项目的根目录中生成package.json文件,这个文件中记录了当前项目的基本信息
如何配置命令来操作
1、先在本地安装模块
2、在package.json文件中配置可执行的命令(在scripts属性中配置好要在DOS下执行的命令)
3、npm run xxx 执行即可
本地安装的时候,我们一般都会加 --save/--save-dev

  • 开发环境:自己开发代码时候的环境
  • 生产环境:项目部署到服务器上的环境
  • -- save:把安装的模块信息存储在package.json的生产依赖清单中
  • -- save-dev:把安装的模块信息存在package.json的开发环境的依赖清单中

由于项目依赖的模块较大,每次上传下载同步都很浪费时间,所以我们只需要上传package.json文件,里面写了所有的依赖模块,我们同步下来之后只需要在需要的项目中打开cmd窗口执行npm install,就可以把项目依赖的模块下载到当前项目中;

node是如何执行js代码的

常用的方式有三种

  • 使用node的repl(Read-Evaluate-Print-Loop,输入-求值-输出-循环)命令
  • 使用命令:nodex xxx.js(在node中把js文件执行)
  • 在webStrom中直接右键->Run xxx.js也可以让JS在node中执行

[IO操作]
I(input):输入
O(Output):输出
I/O操作包括读写操作、输入输出、请求响应,还有读写外部设备都是 io,比如打印机,显示器,数据库
JS运行在服务器端node环境下,可以对服务器上的资源文件进行I/O操作;
NODE中提供了供JS代码操作I\O的方法(后面讲的fs模块就是做这件事情的)

node中的异步操作

  • 定时器
  • 异步的I/O操作
  • 回调函数
  • setImmediate:设置立即(设置在等待任务队列的顶部)
  • process.nextTick:在主任务队列的最底部执行(永远会在setImmediate之前执行)

node 和客户端浏览器的主要区别:全局对象

浏览器全局对象: window
node全局对象:global

node中的属性

global.process
NODE中提供的管理进程的属性
我们可在node的Repl命令下用set方法来设置我们的自定义属性;(此时我们设置的是全局下的自定义属性,每个模块都可以取到);
也可以在每个JS模块中直接process.env.xxx=xxx的方法设置自定义属性(此时我们设置的是当前模块中的自定义属性,只有当前模块能用);

NODE天生就是基于模块化开发的

node中的模块概念非常强,每一个JS就相当于一个模块;

node是基于common.js规范来进行设计的,提供了很多创建模块、调取模块、导出模块的方法

  • CMD模块开发思想:seajs(按需求导入:用到的时候再导入使用)
  • AMD模块开发思想:requirejs(提前导入所有需要的依赖)

node中也提供了三大模块:
1、自定义模块:自己创建的
2、第三方模块:别人写好的我们导入使用即可
3、内置模块:天生自带的

自定义模块的原理

创建一个JS就相当于创建一个模块,而模块之间是独立的(也可以共享)。

//=>NODE为了实现模块之间的独立,会自动包一层闭包,而且给每一个模块传递五个值
(function (exports, require, module, __filename, __dirname) {
/*
* module模块:NODE模块管理的对象
* exports导出:等同于module.exports,用来把模块进行导出的
* require导入:通过这个方法可以把一些模块导入到当前模块中使用
*/
//=>通过module.exports方法把一些想要供别人使用的属性和方法暴露出来
module.exports={
fn:()=>{}
};
})();
//=>下一个模块
(function (exports, require, module, __filename, __dirname) {
let obj=require('pre');//=>导入上边的模块
//=>我们的obj就是上面模块导出的对象
//{fn:()=>{}}
})();

require:导入某个模块,目的是使用其他模块中的属性和方法
```javascript
require('./xxx'):指定目录的情况下,都是为了要导入自定义的模块
require('xxx'):不指定路径的话,会先到node_modules文件夹中找到第三方模块,有的话,导入的是第三方模块,没有的话,就去内置模块中找,内置中有,导入的就是内置模块,没有的话就会报错;
module.exports:把当前模块中的某些属性和方法导出(默认导出的是一个空对象)
```javascript

//module.exports默认导出的是一个空对象
module.exports=exports={};
module.exports.fn=fn;//向默认的module.exports导出的空对象中添加fn属性,值为当前模块中的方法
exports.a=a;//向module.exports默认导出的空对象中添加a属性,值为a;
module.exports=fn;//直接把默认导出的空对象修改为了fn变量所代表的值
//当module.exports指向一个新的内存时,就只能用module.exports导出了
module.exports={};
exports.a=a;//与module.exports指向的不是同一个内存地址了,无法再通过exports导出

第三方模块的安装

除了npm我们还可以使用yarn来安装模块

1、首先在全局安装yarn
npm install yarn -g

2、想在项目中安装模块,和npm的操作步骤类似
yarn init -y 生成package.json
yarn add xxx 安装具体模块,并且保存在生产依赖项中(yarn只能把模块安装在本地项目中不能安装在全局)
yarn add xxx --dev 保存在开发依赖项中
yarn remove xxx 移除安装的模块
yarn install 按照依赖模块清单,跑环境

基本上和npm的操作类似,大家可以体验一把哈,看看急速安装是什么状态

内置模块之HTTP模块

这个内置模块是node中一个非常重要的模块,基于这个模块,我们可以完成服务的创建和管理,以及接收客户端的请求,把一些内容返回给客户端

HTTP模块创建的服务是基于HTTP传输协议完成请求和响应的,HTTPS也是一个内置模块,它可以让我们的传输基于HTTPS传输协议(比HTTP协议更安全);

<font color=red>http.createServer((request,response)=>{})</font>:

用来创建服务的,在当前服务器上创建一个服务(返回值就是创建的服务)

let http = require('http');
let server = http.createServer(()=> {
console.log('ok');
});
server.listen(9999, ()=> {
console.log('server is success,listening on 9999 port!');
});

**`注意`**:回调函数不是服务创建成功之后执行,而是当客户端向当前这个服务发送请求的时候才会被触发执行(不仅触发执行,而且还会默认传递两个参数:request,response)
**`request`**:存放的是所有客户端的请求信息,包含问号传参的数据内容
- request.method:存储的是客户端请求的方式(get或post请求)
- request.url:存放的是客户端请求的文件资源的目录名称以及传递给服务器的数据
- request.headers:存储客户端发送的请求头全部信息

**`response`**:提供相关的属性和方法,可以让服务器端把内容返回给客户端
- response.write():参数为向客户端返回的内容(通过设置响应主体的方式返回)
- response.end():结束响应,参数也是放在响应主体中的(end必须要有,只有end才代表响应结束,才能结束http事务)
- response.writeHead():设置响应头信息,第一个参数为设置的状态码,第二个参数是具体的响应头内容

<font color=red>sever.listen(监听的端口号,()=>{})</font>:

用创建的服务执行listen这个方法,相当于给服务监听端口号(一台服务器上可能存在多个服务或者项目,端口号是为了区分不同服务)
端口号:0-65535,同一台服务器上不允许出现想通过端口号的服务
回调函数:当端口号监听成功,立即执行回调函数(我们可在回调函数中给一些监听成功的提示)

当服务创建成功并且端口号也监听成功了,当前创建的服务会在服务器上一直运行着,只有这样,当客户端不管什么时候发送请求,才有服务为其处理;

客户端如何向创建的服务发请求
拿当前操作举例

1、http://localhost:9999/ 向当前自己电脑本地服务发送请求(localhost就是本地服务的意思),要求服务器端和客户端都是自己的电脑

2、http://192.168.0.38:9999/ 通过局域网IP(内网IP)访问具体的服务(只要大家在同一个局域网内,互相之间可以通过对方的IP地址,访问到对方的服务)
都要指定好对应的端口号

<font color=red>MIME类型</font>:
每一种资源文件都有自己所属的类型,我们把这个类型称为:MIME类型;下面是各种文件类型对应的MIME类型

  • html:text/html
  • css:text/css
  • js:text/javascript
  • json:application/json
  • ico:application/octet-stream
  • txt:text/plain

内置模块之url模块

这个模块最主要的作用就是用来解析URL地址中每一部分信息的
<font color=red>url.parse(str,boolean)</font>:
url模块中提供了一个方法url.parse(str,boolean)用来解析URL地址。将URL字符转换为URL对象;
第一个参数是要处理的字符串;
第二个参数为true时,会默认的把问号传参的值格式化(转换为对象键值对的方式来存储)默认为false;

let url = require('url');
let str = 'http://www.zhufengpeixun.cn:80/index.html?lx=12&age#aa';
console.log(url.parse(str, true));
//=>结果
Url {
protocol: 'http:', //=>协议
slashes: true,
auth: null,
host: 'www.zhufengpeixun.cn:80',
port: '80', //=>端口
hostname: 'www.zhufengpeixun.cn', //=>域名
hash: '#aa', //=>哈希值
search: '?lx=12&age',
query: { lx: '12', age: '' }, //=>问号传参
pathname: '/index.html', //=>请求文件的路径名称
path: '/index.html?lx=12&age',
href: 'http://www.zhufengpeixun.cn:80/index.html?lx=12&age#aa' }

内置模块之fs模块

主要作用就是进行I/O操作(对服务器端的文件进行增删改查等操作)
fs中提供的方法一般都是两套,带有Sync字段的都是同步操作,不带的都是异步操作

fs.readFile()异步读取文件中的内容(此方法没有返回值,可在回调函数中做一些事情)

let fs=require('fs');

let con=fs.readFile('./index.html','utf8',(err,result)=>{
//当文件读取成功或者失败的时候,会触发回调函数执行(并且默认传递两个实参值)
//err(error):当读取出错,信息保存在err中,如果没有出错,err为null
//result:当读取成功,信息保存在result中(第二个参数不设置utf8,获取的结果则是buffer格式的)
if(err){//err存在,代表出错了
console.log(err);
return;
}
console.log(result);
});
console.log(con);//undefined

**`fs.readFileSync()`**同步读取文件中的内容(默认返回的是buffer格式的文件内容)
- 存在两个参数
- 第一个参数是要读取的文件路径名称(如`'./index.html'`)
- 第二个参数为需要得到的文件格式(不写默认为buffer格式,一般我们写`'utf8'`)

同步和异步的区别在于:同步读取文件,文件内容没有读取完成,后面的任务无法处理,而异步不是,数据没有读取完成,下面的任务继续执行(此特点称之为:无阻塞的I\O操作);

**`fs.writeFile()`**:异步的向某个文件中写入内容(此方法没有返回值)
1、如果当前文件不存在,则会自动创建文件(不会自动创建文件夹),然后再写入内容
2、文件写入数据覆盖式写入(新写入的内容会覆盖原来的内容)
3、写入的内容需要是字符串或者buffer格式的数据
**`fs.writeFileSync()`**:同步的向某个文件中写入内容(没有返回值)
```javascript
let con=fs.writeFileSync('./temp.txt','hello',(err,result)=>{
console.log(result);

});

**`fs.readdir()`**:异步读取某一个目录下所有的内容
```javascript

fs.readdir('./',(err,result)=>{
if(err){
console.log(err);
return;
}
console.log(result);//获取的是一个数组集合,其中包含了'./'目录下所有的文件和文件夹的信息
});

**`fs.readdirSync()`**:同步读取某一个目录下的所有内容

**`fs.mkdir()`**:创建一个文件夹
1、如果已经创建的文件夹已经存在,再创建的话返回的是错误信息
2、不能一次创建多级目录如:./temp/day/css,如果没有temp文件夹则会报错;
```javascript

fs.mkdir('./temp',err=>{
if(err){
console.log(err);
return;
}
});

一次创建多级目录的方法(正则方法)
```javascript

let makeDir=function (val) {
let reg=/.?/(\w+)/gi;
let url='';
val.replace(reg,content=>{
url+=content;
/同步创建/
fs.mkdirSync(url);
/异步创建/(未完善)
});
};
makeDir('./temp/day/js/time/css');

**`fs.rmdir()`**:删除一个文件夹
如果要删除的文件夹还存在子文件夹则会提示出错:要从最深的目录开始删除
```javascript
/*一次删除多个文件夹*/
let removeDir=function (val) {
let reg=/\.?\/(\w+)/gi;
let url='.';
let ary=val.split('/').reverse();
ary.pop();
let n=-2;
val.replace(reg,(content,input,index)=>{
    n++;
    let index1=val.indexOf(ary[n]);
    index1===-1?index1=val.length:null;
    url=val.slice(0,index1);
    fs.rmdirSync(url);
});

};
removeDir('./temp/day/js/time/css');

**`fs.copyFile()`**:拷贝一个文件夹

38、ES6中的模块化与webpack的安装与使用

ES6中提供了客户端的模块化:esmodule
客户端可以基于ES6来使用一些模块(要使用谷歌60+版本以上的浏览器)
esmodule是一个规范:规定了如下规范

  • 如何定义模块( 一个JS就是一个模块)
  • 如何导出模块(使用export)
  • 如何导入模块(import)

如何在HTML中引入一个模块

依然用script标签导入,不过需要规定type类型

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--需要type为模块类型-->
<script src="main.js" type="module"></script>
</body>
</html>

如何导出一个模块

一个JS就相当于一个模块,把需要用的导出用export
导出也有两种方式:

  • 1、以默认的形式导出(必须加default)

let str='我很帅';
let str1='我很英俊';
export default {
str,str1
}

- 2、分别导出
```javascript

//此模块为a.js(下面导入时会用到)
//会将str和str1放到一个对象内导出{str:'我很帅',str1:'我很英俊'}
export let str='我很帅';
export let str1='我很英俊';

如何导入一个模块

使用import来导入一个模块,最好在需要模块的顶部导入
import具有声明作用(之后再重复声明会报错),而且声明会进行变量提升。
两种写法:

  • 1、用ES6的解构赋值:把需要的解构出来

console.log(str);//我很帅(最好不要这样用)
//导入时可用ES6中解构赋值的形式从另一个模块中解构出需要用的内容(一个个的导入)
import {str,str1} from './a.js';//自定义模块路径前必须要加 ./ ,后缀必须要加.js,不然会报错
console.log(str,str1);//我很帅 我很英俊

- 2、用`* as obj form xxx`把另一个模块中的东西批量导入到我需要的文件中
```javascript

//批量导入
import * as obj from './a.js';
console.log(obj.str, obj.str1);//我很帅 我很英俊

- 3、把默认的导入(只有以导出方式一来导出才能这样导入)
```javascript

import val from './a.js';
console.log(val);//{str: "我很帅", str1: "我很英俊"}

webpack的安装与使用

安装webpack模块:最好不要安装在全局下,否则可能导致webpack的版本差异
npm init -y
npm install webpack --save-dev
在package.json中配置一个脚本,这个脚本用的命令是webpack,会去当前的node_modules下找bin对应的webpack名字让其执行,执行的就是bin/webpack.js,webpack.js需要当前目录下有个名字叫webpack.config.js的文件,我们通过npm run build执行的目录是当前文件的目录,所以会去当前目录下查找;

babel转义es6->es5

安装babel-core(解析器)与babel-loader(翻译官)
npm install babel-core --save-dev(开发的时候用,上线的时候不用)
npm install babel-loader --save-dev

babel-preset-es2015

(让翻译官有解析ES6语法的功能)
npm install babel-preset-es2015 --save-dev

babel-preset-stage-0

解析es7语法的
npm install babel-preset-stage-0 --save-dev

解析css样式

css-loader将css解析成模块,将解析的内容插入到style标签内(style-loader)
npm install css-loader style-loader--save-dev

解析less、sass、stylus(预处理语言)

less-loader
sass-loader
stylus-loader

解析图片

file-loader
url-loader(url-loader是依赖与file-loader的)
用的时候用的是url-loader,但是两个都要安装

//- 图片的解析()如果url-loader后面不加'?'后面的内容,会把图片转换为base64码
//加了?limit=8192之后代表当图片小于8192字节(8k以下)才会转换为base64码其他情况下输出图片
{test:/.(jpg|png|gif)/,use:'url-loader?limit=8192'}, //- 图标的解析 {test:/\.(eot|svg|woff|woff2|wtf)/,use:'url-loader'}

```javascript

//在JS中引入图片需要import,或者写一个线上路径(不然不会被解析)
import page from './2.jpg';
console.log(page);//page就是打包后的图片的路径
let img=new Image();
img.src=page;
document.body.appendChild(img);

需要解析HTML插件

插件的作用是以我们自己的HTML为模版将打包后的结果自动引入到html中,产出到dist目录下
npm install html-webpack-plugin --save-dev
需要在webpack.config.js中配置如下信息

//自动生成HTML页面并把打包后的文件引入的模块(需要在下面用plugins来配置)
let HtmlWebpack=require('html-webpack-plugin');
module.exports={
//打包的入口文件,webpack会自动查找相关的依赖进行打包
//打包一个文件直接写需要打包的文件名
// entry:'./src/main.js',
//打包多个文件要写为对象的形式
entry:{
main:'./src/main.js',
main1:'./src/main1.js'
},
output:{
// filename:'bundle.js',//打包一个文件后的名字
filename:'[name].js',//打包多个文件时的名字
//path:为打包后存放的地方
path:path.resolve('./dist')//必须是一个绝对路径
},
//模块的解析规则
module:{
rules:[
//- js 匹配所有的js 用babel-loader转译 排除掉node_modules
{test:/.js/,use:'babel-loader',exclude:/node_modules/}, //- css 匹配所有的css 用style-loader和css-loader转译 ,写use时从右边往左写,先转换为css样式,再插入到style标签内 {test:/\.css/,use:['style-loader','css-loader']},
//- less 匹配所有的less 用less-loader等转义 从右往左写:先解析less样式,再转为css样式,最后插入style标签内
{test:/.less/,use:['style-loader','css-loader','less-loader']}, //- 图片的解析()如果url-loader后面不加'?'后面的内容,会把图片转换为base64码 //加了?limit=8192之后代表当图片小于8192字节(8k以下)才会转换为base64码其他情况下输出图片 {test:/\.(jpg|png|gif)/,use:'url-loader?limit=8192'},
//- 图标的解析
{test:/.(eot|svg|woff|woff2|wtf)$/,use:'url-loader'}
]
},
plugins:[
new HtmlWebpack({//自动插入到dist目录中
template:'./index.html'//使用的模版
})
]
};

webpack-dev-sever

这个模块内置了服务,可以帮我们启动一个端口号,当代码更新时,可以自动打包(在内存中打包),代码有变化就重新执行
npm install webpack-dev-server --save-dev

//在package.json的scripts属性中增加 "dev":"webpack-dev-server"
"scripts": {
"build": "webpack",
"dev":"webpack-dev-server"
}

安装vue-loader

安装 vue-loader 来解析.vue文件
安装 vue-template-compiler 用来解析vue模版的
用得时候只需要用vue-loader就可以了,他会自动调用vue-template-compiler

推荐阅读更多精彩内容