day01

1.介绍

1.课程

1.内容:

​ vue(vue-router vuex element-ui axios …) 【10+5 2个项目(app 后台管理)】-js

​ react(react-router-dom redux react-redux hooks …) 【6+3 1个项目 app】-js

2.课程内容 vue

1.官网:

https://cn.vuejs.org/

2.SPA:single page application 单页面应用

MPA:多个url–》多个HTML文件 多页面应用

[优点:有利于SEO优化,缺点:会出现白屏,用户体验度不好]

SPA:对个url—>1个html

[优点:用户体验好 缺点:首屏加载速度慢,不利于SEO优化]

2.核心

数据驱动 组件系统

3.安装

1.cdn【不推荐 项目中绝对不用】
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
2.npm 【学习理论过程会使用】
npm init
npm i vue //安装vue //安装淘宝镜像
npm install -g cnpm --registry=https://registry.npm.taobao.org
3.脚手架方式【day4 工作时候用】

4.Vue实例

5.数据绑定

js :事件 innerHTML value src className style.color …

jq:事件 html() val() attr() class css …

Vue:非表单元素(div span) 表单元素(input textarea select …) 媒体元素(img video )–给属性赋值 样式。。。。

1.非表单元素【div p span】 {{}} vHtml vText

{{}}     优点:简单方便  缺点:1.不能解析标签;2.首屏可能会出现闪屏
v-html   优点 :可以解决闪屏问题  可以解析标签  【主要用于详情】
v-text   优点:可以解决闪屏问题  缺点:不能解析标签

首屏建议使用v-text|v-html,其他屏你喜欢用什么就用什么。

2.表单元素【input】vModel

v-model

<div>账号:<input type="text" v-model="name">
</div>

3.属性绑定【媒体元素】 vBind,简写 :

<div id="app"><!-- v-bind 动态绑定属性,不仅可以绑定已知属性,自定义属性也可以绑定,简写为 :   --><img v-bind:src="img" alt=""><a v-bind:href="website.url"><img v-bind:src="website.img" alt="" v-bind:title="website.name"></a><a :href="website.url" :aaa="name"><img :src="website.img" alt=""></a>
</div>

4.条件渲染

1.v-if
<!-- v-if="boolean" 真就出现,假就消失 -->
<h3 v-if="1===2">社会很单纯</h3>
<h3 v-if="x>5">复杂的是人</h3>
2.v-show
<!-- v-show="boolean" 真就出现,假就消失 -->
<h3 v-show="1===2">社会很单纯</h3>
<h3 v-show="x>5">复杂的是人</h3>
3.v-else
<!-- v-if和v-else必须挨着 -->
<div v-if="comments.length===0">暂无评论</div>
<div v-else>{{comments}}</div>
4.v-if VS v-show
相同点:true 出现,false消失
不同点:false情况下,v-if采用的 惰性加载;v-show采用的是display:none.
使用场景:如果频繁切换,那么就使用v-show;如果不频繁切换,建议使用v-if

5.列表渲染 v-for

1.遍历数组
<!-- 遍历数组 -->
<ul><li v-for="(item,index) in comments">{{index}}---{{item}}</li>
</ul>
comments: ["物美价廉", "很好", "推荐"],
2.遍历json
<!-- 遍历json -->
<div v-for="(value,key) in json">{{key}}:{{value}}</div>
data: {comments: ["物美价廉", "很好", "推荐"],json: {name: "妲己",age: 20,sex: "女"},
}
3.key
当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key

6.动态类名

1.变量

<!-- 1.:class="变量" -->
<div :class="color">打疫苗了吗?</div>

2.【三元】

<!-- 2.:class="[三元]" 只有2种情景 -->
<div :class="[isOrange?'orange':'lime']">绿水青山就是金山银山</div>

3.json

 <!-- 3. :class="{类名1:true,类名2:false,.....}" 多种情景-->
<div :class="{pink:true,lime:true,whilte:false,blue:true}">大力改革教育</div>

7.动态行间样式

<!-- 理论 :style="{json}"-->
<div :style="{color:color,backgroundColor:'pink'}">天道酬勤,人道酬善,商道酬信。</div>

6.复习知识:

1.toFixed()

7.作业:

1.今天的案例练习3遍;

2.作业文件夹中的2个作业

day02

Vue 不支持 IE8 及以下版本

0.案例

bootstrap官网:

http://bootcss.com

1.双for

<div class="item" v-for="item in movies" :key="item.id"><h3>name:{{item.name}}</h3><p>导演:<span v-for="i in item.directors" :key="i.id">{{i.name}}&nbsp;&nbsp;</span></p><p>主演:<span v-for="i in item.actors" :key="i.id">{{i.name}}&nbsp;&nbsp;</span></p>
</div>

2.表单

表单数据,建议定义一个json,key和后端要求的字段一直,目的是为了方便和后端交互

1.指令 v-model
2.单选框
<!-- 单选框,value是选中后的值 -->
<div>性别:<input type="radio" v-model="user.sex" name="sex" :value="0">男<input type="radio" v-model="user.sex" name="sex" :value="1">女
</div>
3.多选框

对于checkbox来说,如果初始值是数组,最后就是数组;否则都是boolean

<div>爱好:<input type="checkbox" :value="1" v-model="user.hobby">唱歌<input type="checkbox" :value="2" v-model="user.hobby">跳舞<input type="checkbox" :value="3" v-model="user.hobby">写代码<input type="checkbox" :value="4" v-model="user.hobby">打游戏
</div><div><input type="checkbox" v-model="user.isAgree">是否同意
</div>
user: {"name": "11","pass": "22","tel": "322","sex": 1,"hobby": [2, 3, 4],"job": 2,"snacks": [1, 2],"des": "123123","isAgree": true
}
4.下拉菜单
<!-- option中间的给用户看的,value是程序取得数据 -->
<div>职业:<select v-model="user.job"><option value="" disabled>--请选择--</option><option :value="1">php工程师</option><option :value="2">web工程师</option><option :value="3">java工程师</option></select>
</div>
<!-- 下拉菜单复选,需要设置multiple  -->
<div>零食:<select v-model="user.snacks" multiple><option value="" disabled>--请选择--</option><option :value="1">辣条</option><option :value="2">薯片</option><option :value="3">瓜子</option><option :value="4">快乐水</option></select>
</div>
5.多行文本框
<div>备注:<textarea cols="30" rows="10" v-model="user.des"></textarea>
</div>
6.表单修饰符
<!-- .lazy 失去光标,才去修改data中的数据 -->
<input type="text" v-model.lazy="name">
<div>name:{{name}}</div><!-- .number 将输入的内容由string转为number -->
<input type="number" v-model.number="age">
<button v-on:click="logage()">打印年龄</button><!-- .trim 输入框前后去空格 -->
<input type="text" v-model.trim="msg">{{msg}}
7.事件

单选、多选、下拉菜单都是onchange,不可以使用onclick

8.MVVM模式
MVVM M-模型(model) V-视图(view) VM-视图模型(viewModel)
模型 通过 视图模型(控制器) 决定了视图的展示;
视图可以通过 视图模型(控制器) 改变模型的数据
视图模型是 视图 和模型之间的桥梁
 vue是MVVM模式框架,适合操作数据多的情况使用jq:dom操作方便、动画、链式操作
官网:jq【维护】
管理系统:vue  【内部使用 不需要推广,数据多,改版】(必然是你)
商城类:数据多,动画多 vue+jq
app:(不一定是你) 改版+数据+动画 vue+jq
活动页:【好看、一次性使用】html+css+jq(是你)

3.事件绑定

1.如何绑定事件

<button v-on:click="fn1()">点击触发</button>
<!-- 如果没有参数,()可以省略 -->
<button v-on:click="fn1">点击触发</button><!-- v-on 可以简写为@  -->
<button @click="fn1">点击触发</button>
<div>n:{{n}}</div><!-- 如果逻辑只有一句话,可以在html中实现 -->
<button @click="n=n+2">+2</button>

2.事件传参

<button @click="add(3,5)">3+5</button>

3.事件对象Event如何获取?

<!-- 显式获取:$event  -->
<button @click="getEvent($event)">获取event</button><!-- 隐式获取:调用不能写(),默认参数就是event  -->
<button @click="getEvent">获取event</button><!-- 如果出了event,还有其他参数,只能使用显式传参 -->
<button @click="getEvent2($event,10)">获取event,10</button>

4.阻止默认事件 阻止事件传播

//阻止默认事件
e.preventDefault()
//阻止传播
e.stopPropagation()

5.事件修饰符

.prevent 阻止默认
.stop 阻止传播
.self 触发的目标元素是自己才执行
.once 一次性触发
.capture 捕获
.up 上键
.down 下键
.left 左键
.right 右键.enter 回车键.13

4.$set

1.数组变了,页面不渲染,怎么办?
1.arr.splice(index,1,newObj)
2.Vue.set(arr,index,newObj)
3.this.$set(arr,index,newObj)
4.取回来数据,先操作,再赋值给数组。
2.json变了,页面不渲染,怎么办?
1.Vue.set(this.json,"y",40)
2.this.$set(this.json,"y",40)
3.this.json={...this.json,y:40
}

5.复习内容

1.阻止默认 阻止传播
if(e.preventDefault){e.preventDefault()
}else{e.returnValue=false
}

6.作业

1.练习3遍

2.作业文件夹的2个作业

day03

1.生命周期

8个生命周期函数是自动执行的函数,称为钩子函数

beforeCreate  //创建之前,什么都没有
created //创建之后,数据初始化完成,但是el还是undefined//作用:二次修改初始值
beforeMount //2.挂载期:如果有el或者$mount(),才自动触发//挂在之前:找到了要解析的模板,但是{{}} v-指令都还没有解析
mounted //挂载完成:页面完成解析,DOM节点加载完成 *****//作用:获取dom,添加动画,开启计时器,给window或者document绑定事件
beforeUpdate  //3.更新期//数据变化了,但是页面准备重新渲染之前,注意,此时取到 的数据是新值
updated  //页面更新完成
beforeDestroy //4.销毁期//作用:善后工作:1.清除计时器;2.清除window|document上的事件
destroyed //销毁完成,数据不会实时渲染,变成了纯粹的html,css

2.watch 监听器 侦听器

监听数据的改变,只能监听data中的数据和computed中的数据

new Vue({watch:{kw(newV,oldV){//逻辑},json:{handler(){console.log("json变了");},deep:true}},})

注意:不建议使用深度监听

1.深度监听会造成页面卡顿;
2.可以使用事件代替监听

jsonp

1.创建一个script标签var os=document.createElement("script")
2.给script一个src,src就是地址os.src="http://suggestion.baidu.com/su?cb=qwer&wd=123"
3.将script插入到页面document.body.appendChild(os)
4.回调函数处理数据function qwer(d){//d就是后端返回的数据}

3.filter 过滤器

1.作用:

转换数据

2.使用

| 管道符

3.注册方式

全局注册

// 全局过滤器:所有的vue实例都可用
Vue.filter("filterTel",(tel)=>{return tel.slice(0,3)+"****"+tel.slice(7)
})

局部注册

new Vue({el: "#app",//局部过滤器:只有当前vue实例可用filters: {filterPrice(a) {return a.toFixed(2)},}
})

4.computed 计算属性

new Vue({computed:{allPrice(){return 10}}
})

5.computed VS watch

watch:一个数据影响多个数据的改变没有调用,自动执行可以操作异步computed:多个数据影响一个数据手动调用,当做属性调用做同步可以有缓存

6.面试题

1.常用指令
2.SPA优缺点?
3.v-if和v-show的区别?
4.v-for的key的作用
5.数组变了,页面不渲染怎么办?
6.json变了,页面不渲染怎么办?
7.vue生命周期有哪些?
8.vue一进来页面自动执行的生命周期有哪些?
9.一进来页面要发ajax在哪个阶段?
10.表单修饰符?
11.事件修饰符?
12.MVVM
13.MVVM和jq有什么区别?什么情况下使用?
14.watch和computed区别?
15.jsonp原理?
16.vue有哪些bug?如何解决?1.{{}}闪屏 v-text2.数组变了,不渲染,4种方式解决3.json变了,不渲染,3中解决4.watch深度监听会卡顿,用事件代替5.v-for和v-if同时在一个节点上,渲染效率低,建议使用computed解决

7.复习

1.slice substr substring 区别
2.Date
3.padStart padEnd indexOf includes
4.Math.random() Math.max() Math.min()
5.arr: forEach vs map. every(some) filter reduce find findIndex

8.作业

1.练习 3遍

2.作业文件夹中的作业

1.淘宝搜索
2.购物车

day04

1.动画

1.使用场景

1.v-if
2.v-show
3.动态组件
4.路由

2. 6个状态

进来之前 enter
进来过程 enter-active
进来完成 enter-to
离开之前 leave
离开过程 leave-active
离开完成 leave-to

3.使用

1.transition 将内容包裹;2.设置name属性

<transition name="aa"><div class="box" v-if="isshow"></div>
</transition>

3.3.设置6个状态

.aa-enter{left: 0px;
}
.aa-enter-active,.aa-leave-active{transition: all 0.3s;
}
.aa-enter-to{left: 500px;
}
.aa-leave{opacity: 1;transform: scale(1,1);
}.aa-leave-to{opacity: 0.1;transform: scale(0.1,0.1);
}

4.animate.css

官网:https://animate.style/

1.安装
npm i animate.css
2.引入
 <link rel="stylesheet" href="./node_modules/animate.css/animate.css">
3.使用
 <transition enter-active-class="animate__animated animate__fadeInDown"leave-active-class="animate__animated animate__bounceOutLeft"><div class="box" v-if="isshow"></div></transition>
4.注意:

​ 1.一般情况下只写进来动画,不写离开,否则,太花里胡哨。

2.组件基础

1.什么是组件?

可复用的vue实例。(公共的html+css+js)

2.组件注册

1.全局注册

//全局组件:所有的vue实例都可以调用
Vue.component("hello",{template:"<div>我是hello</div>"
})

2.局部注册

new Vue({el:"#app",//局部组件:只有当前vue实例可用components:{websitenav:{template:"<div> <div>特色主题</div><div>行业频道</div><div>更多精选</div></div>"}}
})

3.大部分使用局部,少数使用全局。

3.组件命名

components: {// 1.不能以已经存在的标签命名。比如:div input span ... // 2.也不能以已经存在的标签的大写命名。比如:DIV INPUT ... // 3.如果组件名中间包含了大写(除首字母之外),使用的时候需要变成-小写 ,烤串写法 WebsiteNavComponenT: {template: "<div>这是第一个组件</div>"},// 4.建议名称中包含大写,目的是为了方便调用vHello: {template: "<div>hello</div>"}}

4.template

1.template 可以借助template标签来实现组件的模板

vSecond:{template:"#second"
},
<template id="second"><div><h3>this is second</h3></div>
</template>

2.template只能有1个根节点。因为一个vue实例只能作用在1个节点上,如果有很多节点,只能作用在满足条件的第一个节点上

3.脚手架

//只执行一次
npm i webpack -g //全局安装webpack
npm i @vue/cli -g //全局安装vue脚手架

创建项目:

vue create demo //demo是你的项目名称
1. manually select features
2.只选择了babel
3.package.json
4.未来是否都是这样? n

项目启动

cd demo
npm run serve

目录:

-demo    -node_modules   依赖包-public 静态资源index.html 唯一的页面favicon.ico 小图标.gitignore 上传码云不需要传的文件.babel.config.js babel 配置package.json 项目命令 依赖包readme.md 项目说明-src 你的代码main.js 入口文件App.vue 根组件

vue的插件:

vuter vetur

4.作业

1.练习3遍

2.作业文件夹中的作业

day05

组件高阶

1.组件通信***

组件关系:父子关系 非父子

父传子:子组件取了父组件的数据

场景:父组件控制数据。子组件控制的结构

语法:父组件通过自定义属性传值,子组件通过props接收,然后使用

父组件:
 <v-child :img="img" :title="name"></v-child>

子组件:

export default {props:["img","title"]
}
props验证:
export default {// props验证props:{price:{//必填required:true,//类型type:Number},tel:{//默认值default(){return '110'}}}
}

子传父:子组件调用了父组件的方法

场景:子组件要修改父组件的值。

使用:父组件绑定自定义事件,子组件通过$emit()触发自定义事件

父组件:
 <!-- 子传父:父组件绑定自定义事件,子组件通过$emit()触发自定义事件 --><v-child  @aa="changeWang" @bb="changeName($event)"></v-child>
子组件:
methods:{cwang(){//通知父组件触发changeWang  this.$emit("aa")},changeName(name){// 自定义事件传参,只能传递1个参数,接收方通过event对象来接收this.$emit("bb",name)}
},

非父子传值

EventBus【了解】–练习1遍

1.在main.js中给vue原型上添加一个vue实例

// 1.在vue的原型链上挂了一个EventBus,值是一个vue实例
Vue.prototype.EventBus=new Vue();

2.接收方绑定自定义事件

mounted(){this.EventBus.$on("sendA",(e)=>{console.log(e);this.a=e;})},

3.发送方触发自定义事件:

 //发数据this.EventBus.$emit("sendA",this.name)
vuex
本地存储
cookie

2.ref

注意:ref一定要在mounted之后使用

1.获取到原生的DOM节点

<!-- 1.通过ref获取DOM节点 -->
<div class="boxDiv" ref="div"></div>
 this.$refs.div.style.background='blue';this.$refs.div.innerHTML="123"

2.父组件获取子组件的实例

 <!-- 2.父组件获取子组件的实例 --><v-child ref="child"></v-child>
 // this.$refs.child.name="貂蝉"this.$refs.child.changeName('貂蝉')

3.is

1.解决了标签固定搭配问题

<!-- 1.解决标签固定搭配问题 -->
<ul><li is="v-one"></li>
</ul>
<table><tr is="v-one"></tr>
</table>

2.实现动态组件

<button @click="showCom='v-one'">one</button>
<button @click="showCom='v-two'">two</button><div :is="showCom"></div>

4.脚手架上使用动画

1.安装

npm i animate.css --save

2.main.js引入

import "animate.css"

3.使用

<transitionenter-active-class="animate__animated animate__bounceInLeft"><div :is="showCom"></div>
</transition>

5.scoped

样式只在当前文件夹中起作用。 建议每个组件都加scoped.

<style scoped>
h3{color:blue;
}
.boxDiv{width: 100px;height: 100px;background: red;color: #fff;
}
</style>

6.jquery

1.安装

npm i jquery --save

2.引入

 import $ from "jquery"

3.使用[注意:1.mounted之后再使用;2.注意this指向,最好使用箭头函数]

$(".show").click(()=>{$(".red").fadeIn(400)
})
$(".hide").click(()=>{$(".red").fadeOut(400)
})

7.slot 插槽

1.匿名插槽

所有嵌套的内容都会出现在匿名插槽中

<v-one><div>善上若水,水善利万物而不争</div>
</v-one>

one组件:

<div class="box"><h3>this is one</h3><!--匿名插槽: 内置组件 --><slot></slot></div>

2.具名插槽

two组件

<div class="box"><!-- 具名插槽 --><slot name="top"></slot><h3>this is two</h3><slot name="bottom"></slot></div>
<v-two><ol slot="top"><li>锦瑟无端五十弦</li><li>一弦一柱思华年</li></ol><ul slot="bottom"><li>床前明月光</li><li>疑是地上霜</li></ul>
</v-two><!-- 2.具名插槽。如果嵌套的内容没有定前往哪个插槽,那么哪个插槽都不会展示 -->
<v-two><div>手机</div>
</v-two>

3.作用域插槽

作用域插槽:父组件调用了子组件,子组件展示数据,结构又不确定,那么使用插槽;但是这段不确定的结构中有使用到数据,需要slot传递回来,父组件使用。

父组件:
<v-three :arr="arr1"><!-- v-slot 2.x 3.x都支持 --><template v-slot="props">
<span v-for="item in props.showArr" :key="item">{{item}}</span></template>
</v-three><v-three :arr="arr2"><!-- slot-scope 2.x的写法,以后就弃用 --><template slot-scope="props">
<button v-for="item in props.showArr" :key="item">{{item}}</button></template>
</v-three>

子组件(three)

<template><div class="box"><h3>展示的组件</h3><slot :showArr="showArr" a="1" b="2"></slot><h3>展示完成</h3></div>
</template><script>
// arr=["11","22","33"]
export default {props: ["arr"],computed:{showArr(){return this.arr.slice(0,3)}}
};
</script>

8.面试题

1.data为什么是个函数?

2.如何实现动态组件?

3.组件之间如何通信?

4.ref的作用是什么?

5.is的作用是什么?

9.作业

1.练习3遍

2.作业文件夹中的作业【尽量做】

day06

1.作业

查看作业笔记.md

2.混入

作用:将两个组件公共的逻辑提取。

语法:

export default {data(){return {isshow:false}},methods:{show(){this.isshow=true},hide(){this.isshow=false}}}

组件使用:

import toggle from "./toggle"
export default {mixins:[toggle]
}

3.缓存组件

1.如果想要数据缓存,可以加keep-alive

<keep-alive><v-home v-if="n==1"></v-home>
</keep-alive>

2.加上了keep-alive,mounted只会执行一次,beforeDestroy不会再重复出发了

3.加上了keep-alive会多2个钩子函数:activated(激活) deactivated(失活)

activated() {window.onclick = () => {console.log("window scroll");};
},deactivated() {window.onclick = null;},

4.路由

将url映射到组件上。

1.一级路由规则

routes=[//一级路由{ path: '/login', component: login },{path: "/index", component: index,},{path: "/detail", component: detail},{ path: "/list", component: list },
]

2.一级重定向

{ path: "*", redirect: "/login" }

3.嵌套路由

{path: "/index", component: index,//二级路由路由规则path没有"/" ,重定向是""children: [{path: "home",component: home,},{path: "cate",component: cate},{path: "shop",component: shop},{path: "mine",component: mine},{path:"",redirect: "home"}]},

4.内置组件

<router-link></router-link>
<router-view></router-view>

5.路由导航高亮效果

<footer><router-link to="/index/home" active-class="select">首页</router-link><router-link to="/index/cate" active-class="select">分类</router-link><router-link to="/index/shop" active-class="select">购物车</router-link><router-link to="/index/mine" active-class="select">我的</router-link>
</footer>

6.编程式导航

this.$router.push("/search") //是添加了新的历史记录
this.$router.replace("/search") //是使用新的记录替换当前记录
this.$router.go(-1) //返回

5.作业

1.练习2遍;

2.作业文件夹中的作业 1

3.app 至少一遍

day07

1.路由传参

<router-link to="/detail?id=1&name=2">手机</router-link>
this.$route.query.id //1
this.$route.query.name //2

2.命名路由

{ path: '/search', component: search,// 命名路由name:"搜索",},
router-link :to="{name:'搜索'}">前往搜索</router-link>

3.命名视图 -了解

<router-view class="con"></router-view>
<!-- 命名视图 了解 -->
<router-view name="view2"></router-view>
//一级路由{path: '/login',// component: login,components:{default:login,view2:test},name: "登录",// 路由元信息meta: {title: "登录"}},

4.动态路由

1.传递参数

<router-link to="/detail/1/手机">手机</router-link>

2.修该路由规则

{path:"/detail/:id/:name"
}

3.取值

this.$route.params.id //1
this.$route.params.name //手机

5.路由模式

const router = new VueRouter({// history 不带#,hash是带#mode:"history",//hash history  ,默认是hash})

hash VS history

hash  http://baidu.com/#/login1.前进 后退 刷新  都ok2.#/login 是hash值,hash值是不会影响请求3.采用的是window.onhashchange=()=>{} 原理实现,是可以兼容IE678的
history http://baidu.com/login1.前进 后退 ok刷新:如果后端有这个路由,就会直接展示后端数据到页面;如果后端没有这个路由,404.2. /login 是会影响请求3.采用的是HTML5新增的API interface (pushState replaceState)4.如果想使用history模式,需要后端配合。

6.导航守卫*

守卫|路由钩子函数:

如果没有设置守卫,可以自由出入;如果设置了守卫,需要守卫允许,才可以进入或者离开

全局守卫router.beforeEach()rotuer.afterEach()
路由独享守卫beforeEnter()
组件内部守卫:beforeRouteEnter()beforeRouteUpdate()beforeRouteLeave()

登录拦截如何实现??

如果用户没有登录,只能访问登录或者注册路由;如果登录了,才可以访问所有的路由。

1.在登录成功的时候,设计一个标识,用来延段是否登录。 【login.vue】

 methods:{login(){//name="admin" pass="123"if(this.user.name=="admin"&&this.user.pass=="123"){//设计一个标记localStorage.setItem("islogin",true)this.$router.push("/index/home")}else{alert("账号密码错误")}}}

2.在全局前置守卫做拦截,【router/index.js】

//全局前置守卫:进入每一个路由都会执行
//to:前往的路由数据 from是从哪来的路由数据  next允许不允许进入
router.beforeEach((to, from,next)=>{// 1.如果去的登录页,直接进if(to.path==="/login"||to.path=="/register"){next()return;}// 2.如果去的不是登录,判断islogin有没有。如果有,进let islogin=localStorage.getItem("islogin");// "true" nullif(islogin){next()return;}// 3.如果没有,去登录next("/login")
})

7.懒加载

let index=()=>import("../pages/index/index.vue")
let list=()=>Promise.resolve(import("../pages/list/list.vue"))

8.滚动处理

 //滚动处理scrollBehavior (to, from, savedPosition){//如果之前savedPosition没有,滚动到{x:0,y:0}//如果之前savedPosition有,滚动到savedPositionif(savedPosition){return savedPosition}else{return {x:0,y:0}}}

9.路由元信息

{path: '/login', component: login, name: "登录",// 路由元信息meta: {title: "登录"}},
<div class="header">{{$route.meta.title}}</div>

10.作业

1.app 练习2遍

day07

1.路由传参

<router-link to="/detail?id=1&name=2">手机</router-link>
this.$route.query.id //1
this.$route.query.name //2

2.命名路由

{ path: '/search', component: search,// 命名路由name:"搜索",},
router-link :to="{name:'搜索'}">前往搜索</router-link>

3.命名视图 -了解

<router-view class="con"></router-view>
<!-- 命名视图 了解 -->
<router-view name="view2"></router-view>
//一级路由{path: '/login',// component: login,components:{default:login,view2:test},name: "登录",// 路由元信息meta: {title: "登录"}},

4.动态路由

1.传递参数

<router-link to="/detail/1/手机">手机</router-link>

2.修该路由规则

{path:"/detail/:id/:name"
}

3.取值

this.$route.params.id //1
this.$route.params.name //手机

5.路由模式

const router = new VueRouter({// history 不带#,hash是带#mode:"history",//hash history  ,默认是hash})

hash VS history

hash  http://baidu.com/#/login1.前进 后退 刷新  都ok2.#/login 是hash值,hash值是不会影响请求3.采用的是window.onhashchange=()=>{} 原理实现,是可以兼容IE678的
history http://baidu.com/login1.前进 后退 ok刷新:如果后端有这个路由,就会直接展示后端数据到页面;如果后端没有这个路由,404.2. /login 是会影响请求3.采用的是HTML5新增的API interface (pushState replaceState)4.如果想使用history模式,需要后端配合。

6.导航守卫*

守卫|路由钩子函数:

如果没有设置守卫,可以自由出入;如果设置了守卫,需要守卫允许,才可以进入或者离开

全局守卫router.beforeEach()rotuer.afterEach()
路由独享守卫beforeEnter()
组件内部守卫:beforeRouteEnter()beforeRouteUpdate()beforeRouteLeave()

登录拦截如何实现??

如果用户没有登录,只能访问登录或者注册路由;如果登录了,才可以访问所有的路由。

1.在登录成功的时候,设计一个标识,用来延段是否登录。 【login.vue】

 methods:{login(){//name="admin" pass="123"if(this.user.name=="admin"&&this.user.pass=="123"){//设计一个标记localStorage.setItem("islogin",true)this.$router.push("/index/home")}else{alert("账号密码错误")}}}

2.在全局前置守卫做拦截,【router/index.js】

//全局前置守卫:进入每一个路由都会执行
//to:前往的路由数据 from是从哪来的路由数据  next允许不允许进入
router.beforeEach((to, from,next)=>{// 1.如果去的登录页,直接进if(to.path==="/login"||to.path=="/register"){next()return;}// 2.如果去的不是登录,判断islogin有没有。如果有,进let islogin=localStorage.getItem("islogin");// "true" nullif(islogin){next()return;}// 3.如果没有,去登录next("/login")
})

7.懒加载

let index=()=>import("../pages/index/index.vue")
let list=()=>Promise.resolve(import("../pages/list/list.vue"))

8.滚动处理

 //滚动处理scrollBehavior (to, from, savedPosition){//如果之前savedPosition没有,滚动到{x:0,y:0}//如果之前savedPosition有,滚动到savedPositionif(savedPosition){return savedPosition}else{return {x:0,y:0}}}

9.路由元信息

{path: '/login', component: login, name: "登录",// 路由元信息meta: {title: "登录"}},
<div class="header">{{$route.meta.title}}</div>

10.作业

1.app 练习2遍

day08

一、课程内容-axios

1.介绍

官网:http://www.axios-js.com/zh-cn/docs/

axios 是一个基于 Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生 XHR 的封装,只不过它是 Promise 的实现版本,符合最新的 ES 规范,它本身具有以下特征:

从浏览器中创建 XMLHttpRequest
⚫ 支持 Promise API
⚫ 客户端支持防止CSRF
⚫ 提供了一些并发请求的接口(重要,方便了很多的操作)

⚫ 从node.js创建http请求

⚫ 拦截请求和响应
⚫ 转换请求和响应数据

⚫ 取消请求
⚫ 自动转换JSON数据

2.配置代理

在你的项目目录下创建一个文件,叫 vue.config.js:

module.exports = {// 部署应用时的基本 URLpublicPath:"",// build 时构建文件的目录outputDir: 'dist',// build 时放置生成的静态资源 (js、css、img、fonts) 的目录 assetsDir: 'static',// 指定生成的 index.htmlindexPath: 'index.html',// 设置代理请求devServer: {proxy: {"/api":{target:"url",ws:true,changeOrigin:true}} }
}

注意:前端项目重启

3.安装

npm i axios --save

4.使用

import axios from "axios"//get
axios({url:"/后端提供的url",method:"get",//可以省略,params:{id:1}
}).then(res=>{//res就是后端返回的数据
})axios.get(url,{//配置项headers:{},//参数params:{}
}).then(res=>{})//post
axios({url:"/后端提供的url",method:"post",//不可以省略,data:{id:1}
}).then(res=>{//res就是后端返回的数据
})axios.post("url",data,{//配置项headers:{token:1}
}).then(res=>{})

5.post传参问题

1.没有文件
import qs from "querystring"export let reqLogin=(user)=>{  console.log(JSON.stringify(user));//'{"phone":"110","password":"123"}'console.log(qs.stringify(user));//'phone=110&password=123'return axios({url: "/api/login",method: "post",//没有文件data: qs.stringify(user),})
}
2.有文件 FormData
//注册
export let reqRegister=(user)=>{// 假设:user={name:1,age:2,ava:File}let data=new FormData()/*data.append("name",user.name)data.append("age",user.age)data.append("ava",user.ava)*/for(let i in user){data.append(i,user[i])}return  axios({//url请求路径 method请求方式 data参数url:"/api/register",method:"post",data:data})}

6.拦截器

//请求拦截:返回的是后端收到的请求
//每次请求都要携带token
axios.interceptors.request.use(config=>{console.log("此处是请求拦截:");config.headers.token="123"console.log(config);return config
})//响应拦截:返回的是前端收到的数据
axios.interceptors.response.use(res=>{//每次请求都要打印console.log("===此处是响应拦截,本次请求的地址是:"+res.config.url);console.log(res);//每次失败都要弹一下失败if(res.data.code!==200){alert(res.data.msg)}//返回的是给前端的return res;
})

7.import

// 1个文件,只能有1个export default
// import a from "./a"
export default 10;// 1个文件可以有很多个export
// import {login,register,home} from "./a"
export let login="123";
export let register=[1,2,3]
export let home=()=>{return 10;
}

8.封装

1.src/http/http.js 环境配置 请求拦截 响应拦截 get post

//环境配置 请求拦截 响应拦截 get post
// 1.引入依赖包
import axios from "axios"
import Vue from "vue"
import qs from "querystring"// 2.环境配置
if (process.env.NODE_ENV === "development") {Vue.prototype.$pre = "http://localhost:3000"
}if (process.env.NODE_ENV === "production") {Vue.prototype.$pre = ""
}// 3.请求拦截
axios.interceptors.request.use(config => {config.headers.token = "123"return config;
})// 4.响应拦截
axios.interceptors.response.use(res => {//打印console.log("本次请求地址:" + res.config.url);console.log(res);//失败处理if (res.data.code !== 200) {alert(res.data.msg)}return res;
})
/*** eg:get("/api/getCate",{}).then(res)** @param {*} url 请求地址* @param {*} [params={}] 请求参数集合*/
export function get(url,params={}) {return axios({url, method: "get",params})
}/*** eg:post("/login",{phone:"123"}).then(res=>{})** @param {*} url 请求地址* @param {*} [data={}] 请求参数集合,默认是{}* @param {boolean} [isFile=false] 用来判断是否有文件,有就传true;没有不需要传参* @returns*/
export function post(url,data={},isFile=false){let params=null;//有文件if(isFile){params=new FormData();for(let i in data){params.append(i,data[i])}}else{//无文件params=qs.stringify(data)}return axios({url,method:"post",data:params})
}

2.src/http/api.js

import {get,post} from "./http"
//登录
export const reqLogin=(user)=>post("/api/login",user)//注册
export const reqRegister=user=>post("/api/register",user)//分类
export const reqHomeCate=()=>get("/api/getCate")//列表
export const reqList=(params)=>get("/api/getgoodlist",params)//详情
export const reqDetail=params=>get("/api/getgoodsinfo",params)

day09

UI框架

1.布局 ;2. 表单; 3.展示数据;4.js反馈; 5.常用的界面组件

1.element-ui 饿了么 PC

1.官网

https://element.eleme.cn/#/zh-CN

2.安装
npm i element-ui -S
3.引入 main.js
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
4.使用
<el-button type="danger">123</el-button>

2.iview PC端

http://v1.iviewui.com/

3.vant 有赞 移动端

https://vant-contrib.gitee.io/vant/#/zh-CN/

day11

vuex

1.Vuex 是什么?

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

2.安装

npm i vuex --save

3.创建仓库

1.src/store/index.js

// 1.安装 npm i vuex --save
// 2.引入
import Vue from 'vue'
import Vuex from "vuex"
Vue.use(Vuex)export default new Vuex.Store({//公共状态state: {name: "妲己",age: 20},//修改状态的方法mutations: {changeWang(state) {state.name = "王昭君"},changeAge100(state) {state.age = 100}}
})

2.main.js引入仓库

import store from "./store"
new Vue({render: h => h(App),//3.创建仓库store
}).$mount('#app')

3.组件就可以使用

<div class="box"><h3>this is a</h3><div>name:{{$store.state.name}}</div><div>age:{{$store.state.age}}</div><button @click="$store.commit('changeWang')">王昭君</button><button @click="$store.commit('changeAge100')">age=100</button></div>

4.使用

0.仓库

export default new Vuex.Store({//状态集合:数据state: {name: "妲己",age: "20",arr: []},//将state的数据导出给组件getters: {name(state) {return state.name},age(state){return state.age},arr(state){return state.arr}},//修改状态:只有mutations里面的方法才能修改state//只能做同步mutations: {/*** @param {*} state 当前仓库的集合* @param {*} name 你传递的参数*/changeName(state, name) {state.name = name;},changeAge(state, age) {state.age = age;},changeArr(state, arr) {state.arr = arr}},//逻辑 :处理异步,不能直接修改stateactions: {/** @param {*} context 当前仓库本身*/changeName2s(context) {setTimeout(() => {context.commit("changeName", '西施')}, 2000)},changeName(context, name) {context.commit("changeName", name)},//请求listreqArr(context) {setTimeout(() => {context.commit("changeArr", [1, 2, 3, 4])}, 300)}},modules: {}
})

1.取数据

$store.state.name

2.触发mutations

$store.commit('changeName','貂蝉')

3.触发actions

$store.dispatch("changeName",'貂蝉')

4.mutations VS actions

mutations 同步                     可以修改state 通过commit()   第一个参数是状态集合(state)
actions   逻辑(同步和异步都可以做) 不能修改state 通过dispatch() 第一个参数是仓库对象(store)

5.从getters中取数据

$store.getters.name

6.流程 单向数据流

state--(getters)-->compoonents--(dispatch)-->actions--(commit)-->mutations--修改-->state--更新-(getters)--->components -...

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8US5FQDY-1659630008219)(/Users/haoliuting/Desktop/0308/day11-vuex/笔记/vuex.png)]

7.辅助函数 mapGetters mapActions

1.数组方式

<script>
import { mapGetters, mapActions } from "vuex";
export default {// 通过mapGetters可以将getters上的数据成批导入给computedcomputed: {...mapGetters(["name", "age", "arr"]),a(){return 10;}},//   通过mapActions可以将actions上方法成批导入给methodsmethods: {...mapActions(["changeName2s","changeName"]),fn(){}},
};
</script>

2.json方式

import { mapGetters, mapActions } from "vuex";
export default {// 通过mapGetters可以将getters上的数据成批导入给computedcomputed: {...mapGetters({username:"name",userage:"age",arr:"arr"}),},//   通过mapActions可以将actions上方法成批导入给methodsmethods: {...mapActions({cname:"changeName"}),fn(){}},
};

8.modules 模块

new Vuex.Store({modules:{home:{namespaced:true,//命名空间  有了它,就可以通过“home/list”state:{},mutations:{},actions:{},getters:{}}}
})

9.目录结构

-storeindex.js //创建仓库并导出actions.js //根级别下的actionsmutations.js //根级别下的mutations state getters-modules //模块home.js //home模块shop.js

10.vuex VS 本地存储

vuex 刷新就没有了  操作数据方便  实时渲染
本地存储 刷新还在   操作不方便    不具备实时渲染

本地存储和vuex同步

11.注意

vuex是单项数据流

v-model双向数据绑定.

如果遇到了表单,就使用v-model,此处不能使用vuex.

5.案例

1.创建项目

vuex vue-router css-pre (less)

2.配置代理

3.重置项目

1.App.vue

<template><div><router-view></router-view></div>
</template><script>
export default {}
</script>

2.views 文件都删除

3.router/index.js 重置

import Vue from 'vue'
import VueRouter from 'vue-router'Vue.use(VueRouter)const routes = []const router = new VueRouter({routes
})export default router

4.components 里的文件都删除

4.http

5.store

-storeindex.js //创建仓库并导出actions.js //根级别下的actionsmutations.js //根级别下的mutations state getters-modules //模块home.js //home模块shop.js

index.js

import Vue from 'vue'
import Vuex from 'vuex'//引入
import {actions} from "./actions"
import {state,getters,mutations} from "./mutations"
import home from "./modules/home"
Vue.use(Vuex)export default new Vuex.Store({state,mutations,actions,çgetters,modules: {home}
})

actions.js

export const actions={}

Mutations.js

export const state={}
export const getters={}
export const mutations={}

Home.js

const state = {}const getters = {}const mutations = {}const actions = {}export default {state,getters,mutations,actions,namespaced: true
}

6.home下的banner

1.设计状态层 store/modules/home.js

import {reqBanner,reqHomeCate} from "../../http/api"
const state = {//1.轮播图初始值banner: [],}const getters = {// 2.导出bannerbanner(state) {return state.banner},}const mutations = {//3.修改bannerchangeBanner(state, banner) {state.banner = banner;},}const actions = {//4.请求bannerreqBanner(context){reqBanner().then(res=>{//5.触发修改bannercontext.commit("changeBanner",res.data.list)})},}

2.home.vue使用

<template><div><h3>首页</h3><img v-for="item in banner" :key="item.id" :src="$pre+item.img" alt=""></div>
</template><script>
import {mapGetters,mapActions} from "vuex"
export default {computed:{...mapGetters({banner:"home/banner",})},methods:{...mapActions({reqBanner:"home/reqBanner",})},mounted(){this.reqBanner()}
}
</script>

7.home下的cates

1.store/modules/home.js 设计cates

import {reqBanner,reqHomeCate} from "../../http/api"
const state = {// 6.分类初始值cates:[]
}const getters = {//7.导出catescates(state){return state.cates}
}const mutations = {//8.修改changeCates(state,cates){state.cates=cates}
}const actions = {//9.请求分类reqCates(context){reqHomeCate().then(res=>{context.commit("changeCates",res.data.list)})}
}

2.组件使用

<template><div><h3>首页</h3><img v-for="item in banner" :key="item.id" :src="$pre+item.img" alt=""><div v-for="item in cates" @click="$router.push('/list?id='+item.id)" :key="item.catename">{{item.catename}}</div></div>
</template><script>
import {mapGetters,mapActions} from "vuex"
export default {computed:{...mapGetters({cates:"home/cates"})},methods:{...mapActions({reqCates:"home/reqCates"})},mounted(){this.reqCates()}
}
</script><style>
img{width: 100px;height: 100px;
}
</style>

8.登录 登出

1.分析:用户信息很多地方都要用,存vuex方便使用,但是vuex刷新就没有了,所以本地存储同步一份。刷新就将本地存储赋值给vuex。

2、store/mutations.js 初始化数据

export const state={// 本地存储有值,就取出来给user;没有,user={}user:sessionStorage.getItem("user")?JSON.parse(sessionStorage.getItem("user")):{}
}
export const getters={user(state){return state.user}
}
export const mutations={changeUser(state,user){state.user=user;}
}

3.store/actions.js 处理逻辑 进行同步

export const actions={changeUser(context,obj){// 1.vuex存起来context.commit("changeUser",obj)// 2.本地存储 :vuex和本地存储同步if(obj.token){sessionStorage.setItem("user",JSON.stringify(obj))}else{sessionStorage.removeItem("user")}}
}

4.登录成功 login.vue 存值

 methods: {...mapActions({changeUser: "changeUser",}),login() {reqLogin(this.user).then((res) => {if (res.data.code == 200) {//存vuex 存本地存储this.changeUser(res.data.list);//跳转this.$router.push('/home')}});},},

5.登出 mine,vue

computed: {...mapGetters({user:"user"}),},methods: {...mapActions({changeUser:"changeUser"}),logout(){this.changeUser({})}},

9.登录拦截【router/index.js】

import store from "../store"//登录拦截
router.beforeEach((to,from,next)=>{if(to.path=="/"){next()return;}//判断仓库user是否有tokenif(store.getters.user.token){next()return;}next("/")
})

10.掉线处理[src/http/http.js]

import store from "../store"
import router from "../router"
// 3.请求拦截
axios.interceptors.request.use(config => {if (config.url !== "/api/login" && config.url !== "/api/register") {config.headers.authorization = store.getters.user.token}return config;
})// 4.响应拦截
axios.interceptors.response.use(res => {//打印console.log("本次请求地址:" + res.config.url);console.log(res);//失败处理if (res.data.code !== 200) {Toast(res.data.msg)}//掉线处理if(res.data.msg==="登录已过期或访问权限受限"){router.replace("/login")}return res;
})

6.css预处理

1.创建项目 选择了预处理器(less)

2.创建less文件夹,处理预处理

-lessindex.less //整合所有的lesscolor.less //颜色size.less //大小table.less //表格form.less //表单text.less //文本

3.组件使用

<style lang="less">
@import "../less/index.less";
.title{font-size: @h3;color: @primary;margin: @margin;
}
img{width: 100px;height: 100px;
}
</style>

day15

1.vue初探

官网:https://cn.vuejs.org/
介绍:

vue是渐进式 JavaScript 框架

渐进式 :主张最少。

优点:
1.轻量级的数据框架
2.双向数据绑定
3.提供了指令
4.组件化开发
5.客户端路由
6.状态管理
缺点:
1.Vue 底层基于 Object.defineProperty 实现响应式,而这个 api 本身不支持 IE8 及以下浏 览器,所以Vue不支持IE8及其以下浏览器;
2.Vue 打造的是SPA,所以不利于搜索引擎优化(SEO);
3.由于 CSR(客户端渲染)的先天不足,导致首屏加载时间长,有可能会出现闪屏。
核心:
数据驱动 组件系统
MVVM:
M-model模型
V-view视图
VM-viewModel 视图模型
模型(model)通过了视图模型  决定了视图(view)
视图(view)  通过视图模型 修改模型 (model)
视图模型是模型和视图之间的桥梁。
SPA:

single page application 单页面应用

优点:加载快,用户体验好缺点:不利于SEO,首屏加载时间长a页面—>index.html/#/ab页面—>index.html/#/b
MPA:

多页面应用

优点:有利于SEO缺点:会有白屏,用户体验不好a页面—>a.htmlb页面—>b.html

day16

1.react介绍

1.1简介

React 是Facebook内部的一个JavaScript类库。
React 可用于创建Web用户交互界面。
React不是一个完整的MVC框架,最多可以认为是MVC中的V(View),甚至React并不非常认可MVC开发模式。
React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。
React 引入了虚拟DOM(Virtual DOM)的机制。
React 引入了组件化的思想。
React 使用Facebook专门为其开发的一套语法糖--JSX。

1.2优缺点

优点:

● React速度很快
react并不直接对DOM进行操作,引入了一个叫做虚拟DOM的概念,安插在javascript逻辑和实际的DOM之间,性能好。
● 跨浏览器兼容
虚拟DOM帮助我们解决了跨浏览器问题,它为我们提供了标准化的API,甚至在IE8中都是没问题的。
● 一切皆是组件
代码更加模块化,重用代码更容易,可维护性高。
● 单向数据流
Flux是一个用于在JavaScript应用中创建单向数据层的架构,它随着React视图库的开发而被Facebook概念化。
● 同构、纯粹的javascript
因为搜索引擎的爬虫程序依赖的是服务端响应而不是JavaScript的执行,预渲染你的应用有助于搜索引擎优化。

缺点:

React不适合做一个完成的框架。
React本身只是一个V而已,并不是一个完整的框架,所以如果是大型项目想要一套完整的框架的话,基本都需要加上ReactRouter和Flux才能写大型应用。

1.3 react 解决了什么问题?

1.在组件化方面,react天生组件化,这是React的核心,除了能够在团队内部积累业务组件以外,也能找到众多开源组件的实现。
2.在模块化方便,基于webpack可以使用ES6或者CommonJs的写法实现模块化代码;
3.在开发效率方面,react的代码基本就是组件的组合,分而治之的方式让代码的可读性很高,容易理解。
而且相比于MVC几乎是祛除了Controller的角色,只用关心render函数,不用关心视图局部的修改;
4.在运行效率方面,React实现了Virtual DOM,相比较MVVM框架具有更优的效率;
5.在可维护性方面,React基于flux或者redux的架构设计,确定性的store很容易定位问题,无论是新增业务代码还是查找业务代码都不再是难题;
6.在用户体验方面,基于React很容易实现SPA,提高用户体验。

2.脚手架

//安装脚手架
npm i create-react-app -g//创建项目
create-react-app demo //demo是项目名//进入项目
cd demo //启动
npm start

目录

-demo-node_modules 依赖包-public 静态资源 index.html -src   源代码index.js // 入口文件app.js //根组件

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';ReactDOM.render(<App />,document.getElementById('root')
);

App.js

function App() {return (<div className="App">123</div>);
}export default App;

3.JSX语法

1.非表单元素 div

{/* {} 可以绑定数据、方法、表达式 */}
<div>姓名:{name}</div>
<div>价格:{price.toFixed(2)}</div>
<div>{1 > 2 ? name : name2}</div>

2.属性绑定:img 属性绑定 <标签 属性名={变量}>

<img src={img} alt="" /><a href={website.url} aaa={website.name}><img src={website.logo} alt="" title={website.name} /></a>

3.条件渲染

let arr = [1, 2, 3, 4];
let isshow = false;
{/* 条件渲染   {三元判断} ,如果没有内容展示,就定为null*/}
{arr.length > 0 ? <div>有数据</div> : <div>暂无数据</div>}
{isshow ? <div>弹框</div> : null}

4.列表渲染

let news = [{id: 1,name: "7.1建党",con: "热泪庆祝建党100周年",},{id: 2,name: "马嘉祺学霸",con: "分数307",},{id: 3,name: "上天",con: "好多人上天",},
];
{news.map((item) => {return <div key={item.id}>{item.name}</div>;
})}

5.动态类名

{/* 动态类名 1.使用className代替class; 2.语法 className={三元} */}
<div className={10 > 11 ? "red" : "blue"}>小车车</div>
{news.map((item, index) => {return (<div key={item.id} className={index % 2 == 0 ? "red" : "blue"}>{item.name}</div>);
})}

6.动态行间样式

let bg = "pink";
{/* 行间样式 语法:style={json} */}
<h3>行间样式</h3>
<div style={{ background: "#000", color: "#fff" }}>天道酬勤</div>
<div style={{ background: bg }}>商道酬信</div>

7.注释

{/* 注释 */}
  1. jsx 中遇到< html解析,遇到了{ js解析
  2. 如果你的js不能直接出一对标签,后缀名改为jsx;

4.组件

1.如何注册?

1.函数注册

function First(props) {return (<div className="box"></div>);
}export default First;

2.类定义注册

import React,{Component} from "react"class Second extends Component{  constructor(){      super();//构造函数必须加super()}//渲染钩子函数render(){return (<div className="box"><h3>this is second -{this.name}--{age}--{this.name2}--{name3}--{this.name4}</h3></div>)}
}export default Second;

2.注意点

// 1.一个组件的模板,只能有一个根节点;
// 2.组件名首字母要大写
// 3.可以以已经存在的标签的大写命名。eg:Form
// 4.组件名中间有大写,原样调用即可。eg:WebsiteNav
// 5.注册组件:(1)函数定义组件 (2)类定义

3.类定义 VS 函数定义

(1)类定义组件 有生命周期,函数定义的没有;
(2)类定义有state,函数定义没有;
(3) 对于父组件传递的数据,类定义组件通过this.props接收,函数定义通过props接收。
(4)对于类定义,每调用一次,就会实例化一个对象,而对于函数组件,只是单纯的计算,所以函数的性能高于类定义。
home 类 业务组件banner 函数 木偶组件list 函数

5.事件处理

1.如何绑定事件?

{/* 1.如何绑定事件? (1)箭头函数:不用管this(2)bind: 第一个参数是调用该函数的对象,一般使用this.*/}
<button onClick={() => this.fn1()}>箭头函数绑定fn1</button>
<button onClick={this.fn1.bind(this)}>fn1</button>

2.如何传参?

{/* 2.如何传参?(1)箭头函数:正常传参(2)bind: 第2个实参对应第1个形参*/}
<button onClick={() => this.fn2(3, 5)}>箭头函数传参:3+5</button>
<button onClick={this.fn2.bind(this, 10, 20)}>bind传参:10+20</button>

3.event 事件对象如何获取?

{/* 3.event 事件对象如何获取? (1)显示传参: 箭头函数,event想在哪一位就在哪一位(2)隐式传参:bind 没有参数的第一位是event. event永远都在最后一位*/}
<button onClick={(e) => this.getEvent(e)}>箭头函数获取event</button>
<button onClick={this.getEvent.bind(this)}>bind获取event</button>
<button onClick={(e) => this.getEvent2(10, e)}>箭头函数获取event,10
</button>
<button onClick={this.getEvent2.bind(this, 10)}>bind获取event</button>

4.阻止默认 阻止传播?

{/* 4.阻止默认 阻止传播?(1)阻止默认:e.preventDefault() 注意:return false 不可以;(2)阻止传播:e.stopPropagation()(3)捕获事件:Capture.eg:onClickCapture*/}
<div className="redBox" onContextMenu={(e) => this.yj(e)}></div><div className="outer" onClick={() => this.outerClick()}><div className="redBox" onClick={this.innerClick.bind(this)}>冒泡</div>
</div><div className="outer" onClickCapture={() => this.outerClick2()}><div className="redBox" onClickCapture={() => this.innerClick2()}>捕获</div>
</div>

6.state

// 1.初始化在constructor
// 2.取值:var { name, age, sex } = this.state;
// 3.如果state要全部传递给子组件,可以使用 <Child {...this.state}></Child>
// 4.修改state数据需要调用setState(),
// 5.setState()的调用会引起render的重新执行,所以render中一定不可以调用setState(),否则会引起死循环
// 6.修改数组:不要直接操作数组。 1.取;2.做;3.放
// 7.修改json:建议使用 ...
// 8.setState()是异步的,如果想要获取修改后的值,需要在回调函数中获取

调用 setState 之后发生了什么?

在代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面。在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

7.面试题

1.react的优缺点

2.react中组件如何创建?

3.函数定义组件和类定义组件的区别?

4.setState()中第二个参数为什么是个回调函数?

5.setState()调用后发生了什么?

8.作业:

练习:3遍

day17

1.props

1.取值:let { name, age, sex,json:{x,y} ,changeWang} = this.props;
2.props不仅可以传递属性,也可以传递方法
3.组件嵌套的内容,在this.props.children  { this.props.children}
4.super(props)的作用:(1) super() 用了继承,所以需要super();(2)super(props)为了在构造函数中使用this.props。
5.如果想把props全部向下传递,使用{...this.props}

state VS props

state:自己的状态,可以修改,而且需要通过setState()。state变了,页面会重新渲染
props:父组件传递过来的状态,不可以直接修改。props变了,页面会重新渲染

2.组件通信(父子)

父传子

父传子:父组件通过自定义属性传递数据,子组件通过props接收

父组件
 <Child name={this.state.name}></Child>
子组件
  let { name} = props;

子传父

子传父:父组件通过自定义属性传递了方法,子组件通过props调用

父组件
<ChildchangeWang={() => this.changeWang()}cname={(name) => this.changeName(name)}></Child>
子组件
export default function Child(props) {let {  changeWang,cname } = props;return (<div className="box"><h3>this is child</h3><button onClick={()=>changeWang()}>王昭君</button><button onClick={()=>cname('貂蝉')}>貂蝉</button></div>);
}

3.生命周期

1.初始期(1)constructor:初始化数据(2)render:渲染DOM初始期:渲染DOM节点; 更新期:调和过程,进行diff算法,计算出最优的更新方式,局部更新(3)componentDidMount:渲染完成:计时器、请求打开,window|document添加事件、获取DOM
2.更新期(state、props)shouldComponentUpdate() : 判断是否更新(1)没有return内容,报错(2)return true. 更新流程 shouldComponentUpdate->render->componentDidUpdate(3) return false.更新流程:shouldComponentUpdaterender() 调和过程,进行diff算法,计算出最优的更新方式,局部更新componentDidUpdate() 更新完成
3.销毁期componentWillUnmount() 销毁之前:清除计时器 取消window|document事件

4.表单【受控组件 非受控组件】

1.受控组件

特点:
就地反馈,如:验证
禁用按钮 如:提交
执行特定的输入格式 如:身份证号、银行卡号
取值赋值
特征 取值 赋值
Input type=“text” e.target.value value
Input type=“radio” e.target.value checked
Input type=“checkbox” e.target.value |e.target.checked checked
Select e.target.value Value
Textarea e.target.value Value
 //3.修改userchangeUser(e, key) {let value = e.target.value;//如果是isAgree,需要用checked取值if (key === "isAgree") {value = e.target.checked;}//如果是爱好,处理一段逻辑if (key === "hobby") {value = this.state.user.hobby;// 如果点的框选中,user.hobby添加一条数据;如果从选中到取消,删除这条数据if (e.target.checked) {value.push(parseInt(e.target.value));} else {//将value中数据和parseInt(e.target.value)一样的那条数据删除value.splice(value.findIndex((item) => item === parseInt(e.target.value)),1);}}//电话号处理if (key === "tel") {let {user: { tel },} = this.state;// 原来的是小于3位,+空格;如果原来的是大于3位,不+空格if (value.length === 3 && tel.length < 3) {value += " ";}// 原来的是小于8位,+空格;如果原来的是大于8位,不+空格if (value.length === 8 && tel.length < 8) {value += " ";}//   如果大于13位,就是13位if (value.length > 13) {value = value.slice(0, 13);}}this.setState({user: {...this.state.user,[key]: value,},});}

2.各个表单使用

<div>{/* 对于单选框来说,需要自己手动设置value;赋值使用的是checked */}性别:<inputtype="radio"name="sex"onChange={(e) => this.changeUser(e, "sex")}value="0"checked={user.sex === "0"}/>男<inputtype="radio"name="sex"onChange={(e) => this.changeUser(e, "sex")}value="1"checked={user.sex === "1"}/>女</div><div>{/* 多选框,取值checked+value;赋值:checked */}爱好:{hobbyList.map((item) => (<label key={item.id}><inputtype="checkbox"value={item.id}onChange={(e) => this.changeUser(e, "hobby")}checked={user.hobby.includes(item.id)}/>{item.name}</label>))}</div><div>{/* select 取值 value;赋值 value  */}职业:<select onChange={(e) => this.changeUser(e, "job")} value={user.job}><option value="" disabled>--请选择--</option>{jobList.map((item) => (<option key={item.id} value={item.id}>{item.name}</option>))}</select></div><div>{/* textarea 取值value;赋值 value */}描述:<textareaols="30"rows="10"onChange={(e) => this.changeUser(e, "des")}value={user.des}></textarea></div>

3.对比受控和非受控组件

特征 受控组件 非受控组件
一次性检索(例如表单提交)
及时验证
有条件的禁用提交按钮
执行输入格式
一个数据的几个输入
动态输入

5.安装cnpm

npm install -g cnpm --registry=https://registry.npm.taobao.org

day18

1.ref

React.createRef()

(1)创建一个ref对象;(2)将ref对象绑定到节点(3)操作 this.div.current

1.获取原生DOM节点

 constructor() {super();// 创建一个ref对象this.div = React.createRef();}
 <div className="red" ref={this.div}></div>
changeColor(color) {let div = this.div.current;div.style.background = color;div.innerHTML = color;
}

2.获取子组件实例

constructor() {super();// 创建一个ref对象this.child=React.createRef()}
<Child ref={this.child}></Child>
 changeChildName(name){this.child.current.changeName(name)}

2.组件优化

1.Fragment

目的:所有的组件都有一个根节点,但是有时候希望这个节点不存在,就可以使用Fragment

1.Fragment

引入 使用

import React, { Component,Fragment } from 'react';class First extends Component {render() {return (<Fragment><h3>fragment</h3><p>哈哈</p><p>嘿嘿嘿</p></Fragment>);}
}export default First;
2.<></>
import React, { Component } from 'react';class First extends Component {render() {return (<><h3>fragment</h3><p>哈哈</p><p>嘿嘿嘿</p></>);}
}export default First;

2.需求:父组件给子组件传了数据,父组件没有传递给子组件的数据变化了,也会引起子组件的重新渲染,我们希望子组件不要渲染,如果是子组件接收的数据 变了,子组件才重新渲染。

1.shouldCompnentUpdate-类定义组件
shouldComponentUpdate(nextProps,nextState){// 判断旧的props上的name是否和新的props上的name一样。如果一样,就不渲染了if(this.props.name===nextProps.name){return false}return true;}
2.pureComponent -类定义组件
1.PureComponent 浅比较,如果传递的数据是引用类型,引用类型的改变,建议需要使用 拷贝
2.PureComponent 如果props发生了改变,会计算,如果是state发生了改变,也会计算。
如果一个组件有state,建议使用Component +shouldComponentUpdate
如果一个组件只有props,建议使用PureComponent 【木偶组件 】
import React, { PureComponent } from 'react';
class Child2 extends PureComponent {render() {console.log("child2 render");let {name,arr}=this.propsreturn (<div className="box"><h3>PureComponent</h3><div>name:{name}</div><div>arr:{JSON.stringify(arr)}</div></div>);}
}export default Child2;
3.React.meno()-函数定义组件
React.memo()  浅比较,如果传递的数据是引用类型,引用类型的改变,建议需要使用 拷贝
React.memo() 本身是一个函数, 参数是个组件,返回一个新的组件,这样的函数叫高阶组件(HOC)
function Child3(props) {let { name ,arr} = props;console.log("child3 开始计算");return (<div className="box"><h3>child3</h3><div>name:{name}</div><div>arr:{JSON.stringify(arr)}</div></div>);
}
export default React.memo(Child3)

3.componentDidCatch 错误边界处理

1.封装了一个组件ErrorBoundary.jsx

import React, { Component } from 'react';class ErrorBoundary extends Component {constructor(){super()//初始认为没有报错this.state={hasError:false}}componentDidCatch(){//此时,有报错了this.setState({hasError:true})}render() {let {hasError}=this.statereturn (<div>{hasError?<div>此处有报错!!</div>:this.props.children}</div>);}
}export default ErrorBoundary;

2.使用组件ErrorBoundary 包裹可能出错的组件

<ErrorBoundary><List></List>
</ErrorBoundary>

4.HOC 高阶组件

HOC 高阶组件:增强原来的组件1.本身是个函数2.参数 是个组件3.返回值也是个组件

封装的withRequest.js

import React, { Component } from "react"
import axios from "axios"
export default url => C => {return class MyCom extends Component {constructor() {super()this.state = {arr: []}}componentDidMount() {axios({url: url}).then(res => {this.setState({arr: res.data.d})})}render() {let { arr } = this.statereturn (<><C arr={arr}></C></>)}}
}

调用

let RequestList=withRequest("/mock/like.json")(List)
let RequestBanner=withRequest("/mock/banner.json")(Banner)

day19

1.路由

1.路由模式 【hash history】

import {HashRouter,BrowserRouter} from "react-router-dom"ReactDOM.render(<HashRouter><App /></HashRouter>,document.getElementById('root')
);

2.路由出口【Switch】

import {Switch} from "react-router-dom"
<Switch></Switch>

3.路由规则【Route】

import {Route} from "react-router-dom"
 <Route exact strict path="/register" component={Register}></Route><Route path="/index" component={Index}></Route>
Route 的属性 :exact[是否精确匹配] 默认:false。 如果要精确匹配,需要设置exact
strict:严格模式。 需要搭配exact使用。 默认是路径后可以加'/',也可以访问,加上严格模式,有'/'就不行

4.重定向【Redirect】

import {Redirect } from "react-router-dom"
{/* 4.重定向 */}<Redirect to="/"></Redirect>

5.路由导航【Link NavLink(activeClassName activeStyle)】

<Link to="/search">搜索</Link>
<NavLink to="/search">搜索</NavLink>
高亮效果:
<footer className="index-footer"><NavLink to="/index/home" activeClassName="select">首页</NavLink><NavLink to="/index/cate" activeClassName="select">分类</NavLink><NavLink to="/index/shop" activeClassName="select">购物车</NavLink>
</footer>
<footer className="index-footer"><NavLink to="/index/home" activeStyle={{color:"orange"}}>首页</NavLink><NavLink to="/index/cate" activeStyle={{color:"orange"}}>分类</NavLink><NavLink to="/index/shop" activeStyle={{color:"orange"}}>购物车</NavLink>
</footer>

6.编程式导航【push replace go 】

this.props.history.push("/search"); //添加新的历史记录
this.props.history.replace("/search"); // 用新的历史记录替换当前历史记录
this.props.history.goBack(); //返回
this.props.history.go(-1);// 返回
注意:
1.如果是路由组件,可以直接使用编程式导航;
2.如果不是路由组件,想要使用编程式导航,有2种方式:① 路由组件传递props给非路由组件;<GoBack {...this.props}></GoBack>②使用withRouter

withRouter

import React, { Component } from 'react';
import {withRouter} from "react-router-dom"
class GoBack extends Component {goBack(){console.log(this.props);// this.props.history.goBack()this.props.history.go(-1)}render() {return (<button onClick={()=>this.goBack()}>封装的返回</button>);}
}export default withRouter(GoBack);

7.路由传参【?】

 <Link to={`/cateList?id=1&name=222`}>{item.name}</Link>
取参数:

1.原生js

componentDidMount(){let str=this.props.location.search;//"?id=2&name=qqq&age=122" --{id:"2",name:"qqq",age:"122"}// 1.利用原生jslet substr=str.slice(1);//"id=2&name=qqq&age=122"let arr=substr.split("&");// ['id=2','name=qqq','age=122']let result={}arr.forEach(item=>{let subArr=item.split("=");//["id","2"]result[subArr[0]]=subArr[1]  })console.log(result);}

2.node questring

import querystring from "querystring"
componentDidMount(){let str=this.props.location.search;//"?id=2&name=qqq&age=122" --{id:"2",name:"qqq",age:"122"}// 2.node querystring.parse()let result=querystring.parse(str.slice(1))console.log(result);}

3.URLSearchParams

componentDidMount(){let str=this.props.location.search;//"?id=2&name=qqq&age=122" --{id:"2",name:"qqq",age:"122"}// 3.原生jslet params=new URLSearchParams(str);console.log(params.get("id"));console.log(params.get("name"));}

8.动态路由【:】

 <Link to={`/detail/1`}>{item.name}</Link>
<Route path="/detail/:id" exact component={Detail}></Route>
let id=this.props.match.params.id

9.全局守卫【登录拦截】

1.登录成功的时候设置一个标识【login.jsx】

 login = () => {let {user: { phone, password },} = this.state;if (phone === "admin" && password === "123") {//存一个标识,用来判断是否登录sessionStorage.setItem('islogin',1)this.props.history.push("/index/home");} else {alert("error");}};

2.封装了一个PrivateRoute ,判断是否登录,觉得出规则还是重定向

import React, { Component } from 'react';
import {Route,Redirect} from "react-router-dom"
class PrivateRoute extends Component {render() {let islogin=sessionStorage.getItem("islogin");//'1' nullreturn (<>{islogin?<Route {...this.props}></Route>:<Redirect to="/login"></Redirect>}</>);}
}export default PrivateRoute;

3.需要拦截的用PrivateRoute写规则【App.jsx】

<Switch>{/* 路由规则 */}<Route path="/login" component={Login}></Route>{/* exact 精确匹配,默认false,如果没设,那么‘/register/a’也会进入'/register'strict 严格模式,默认false,如果没有设置,那么“/register/”是可以访问的;如果设置了严格模式,只能访问“/register”strict 需要和exact 一起使用*/}<Route path="/register" exact strict component={Register}></Route><PrivateRoute path="/index" component={Index}></PrivateRoute><PrivateRoute path="/search" component={Search}></PrivateRoute><PrivateRoute path="/list" component={List}></PrivateRoute>{/* exact精确匹配 */}<PrivateRoute path="/detail/:id" exact component={Detail}></PrivateRoute>{/* 重定向 */}{/* <Redirect to="/login"></Redirect> */}{/* 404 404千万不要设置exact,这句写在最后*/}<Route path="/" component={NotFound}></Route>
</Switch>

10.路由独享守卫

 <Route path="/search" render={(props)=>{let type=sessionStorage.getItem("type")if(type==="2"){return <Search {...props}></Search>}else{return <div>你没有权限 !!!!</div>}}}></Route>

11.懒加载

1.通过React.lazy()引入组件

let Login=React.lazy(()=>import("./pages/Login/Login"))
let Index=React.lazy(()=>import("./pages/Index/Index"))

2.需要将规则包裹在React.Suspense 组件中,fallback必填

// 2.React.Suspense  fallback必须的<React.Suspense fallback={<div>正在加载。。。</div>}>{/* 2.路由出口 */}<Switch><Route exact path="/" component={Login}></Route><Route path="/index" component={Index}></Route></Switch></React.Suspense>

2.数据交互

1.下载

npm i axios --save

2.配置代理

package.json 注意:配置完代理需要重启项目

{"proxy":"http://localhost:3000","name": "luyou","version": "0.1.0",
}

3.使用

3.UI库

1.ant design (PC)

2.ant design mobile (移动端)

1.安装

npm install antd-mobile --save

2.修改index.html

<script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js"></script><script>if ('addEventListener' in document) {document.addEventListener('DOMContentLoaded', function() {FastClick.attach(document.body);}, false);}if(!window.Promise) {document.writeln('<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js"'+'>'+'<'+'/'+'script>');}</script>

3.入口文件引入样式

import 'antd-mobile/dist/antd-mobile.css';

4.使用

4.作业

1.到数据库创建一个数据库,运行orange_data.sql文件

2.修改后端的配置 config/global.js

// 数据库连接参数
exports.dbConfig = {host: 'localhost', //数据库地址user: 'root',//数据库用户名password: '1234',//数据库用户密码port: 3306,database: '0308_orange' // 数据库名字
}

3.启动

npm i
npm start //localhost:3000

day20

Redux

1.目的

1.非父子组件通信;
2.组件层和状态层解耦。

2.三大原则

1.单一数据源
2.state是只读的
3.只能通过纯函数修改state

3.目标

React(组件) ----》react-redux《---- redux(状态) ------》redux-thunk 《------ 后端(数据)

4.redux

0.安装

npm i redux --save

1.创建仓库

//引入方法
import { createStore } from "redux"//初始状态
const initState = {name: "妲己",age: 20
}//reducer用来修改state
/***** @param {*} state  上一次修改完成后的值,对于第一次来说,没有上一次,默认是初始值* @param {*} action 规则-动作*             {type:"changeName",name:"王昭君"}*             {type:"changeAge",age:100}*/function reducer(state = initState, action) {switch (action.type) {case "changeName":state.name = action.name;return state;case "changeAge":state.age = action.age;return state;default:return state;}
}// 创建仓库
let store = createStore(reducer)//导出仓库
export default store;

2.组件使用

1.store.getState() 取状态的

2.store.dispatch(action) 派发动作 派发任务

this.un= store.subscribe(callback) 添加订阅者

4.this.un() 取消订阅者

3.action creattors

//action creator [vuex actions] 方便组件派发任务
export let actions = {changeName: (name) => ({ type: types.CHANGE_NAME, name: name }),changeAge: (age) => ({ type: types.CHANGE_AGE, age })
}
<button onClick={()=>store.dispatch(actions.changeAge(200))}>age=200</button>

4.action types

// action types
const types = {// 修改nameCHANGE_NAME: "CHANGE_NAME",// 修改ageCHANGE_AGE: "changeAge"
}
//action creator [vuex actions] 方便组件派发任务
export let actions = {changeName: (name) => ({ type: types.CHANGE_NAME, name: name }),changeAge: (age) => ({ type: types.CHANGE_AGE, age })
}
function reducer(state = initState, action) {switch (action.type) {case types.CHANGE_NAME:state.name = action.name;return state;case types.CHANGE_AGE:return {...state,age: action.age};default:return state;}
}

5.react-redux 关联react和redux

1.安装

npm i react-redux --save

2.通过Provider将store和App关联【入口文件index.js】

import store from "./store"
import {Provider} from 'react-redux'
ReactDOM.render(<Provider store={store}><App /></Provider>,document.getElementById('root')
);

3.容器型组件 connect

import React, { Component } from "react";
//容器型组件:通过connect函数将redux中的数据和方法导入到该组件中
import { connect } from "react-redux";
import { actions } from "../store";
class D extends Component {render() {console.log(this.props);let { name, age, changeName, changeAge } = this.props;return (<div className="box"><h1>this is D --react-redux</h1><div>name:{name}</div><div>age:{age}</div><button onClick={() => changeName("宫本")}>宫本</button><button onClick={() => changeAge(300)}>age=300</button></div>);}
}
let mapStateToProps = (state) => {return {name: state.name,age: state.age,};
};
let mapDispatchToProps = (dispatch) => {return {changeName: (name) => dispatch(actions.changeName(name)),changeAge: (age) => dispatch(actions.changeAge(age)),};
};
export default connect(mapStateToProps, mapDispatchToProps)(D);
mapStateToProps
参数:store.getState()
返回:一个集合,这个集合会被放到props上
目的:从仓库取数据
mapDispatchToProps
参数:store.dispatch()
返回:一个集合,这个集合会被放到props上
目的:从仓库调用action

4.selectors [vuex getters]

export const getName = state => state.name;
export const getAge = state => state.age

组件使用

let mapStateToProps = (state) => ({name: getName(state),age: getAge(state),
});

5.bindActionCreators

目的:集中导入所有的actions到组件

import { actions } from "../store";
import { bindActionCreators } from "redux";
let mapDispatchToProps = (dispatch) => ({//   changeName: (name) => dispatch(changeName(name)),//   changeAge: (age) => dispatch(changeAge(age)),methods: bindActionCreators(actions, dispatch),
});

组件使用:

let {methods: { changeName, changeAge },
} = this.props;

6.容器型组件 vs 展示型组件

容器型组件: (1)对redux是有感知的;(2)数据和方法来自store;(3)类定义组件;(4)路由组件
展示型组件:(1)对redux是无感知的; (2) 数据和方法来自父组件;(3)函数定义组件;(4)木偶组件

7.reselect

npm i reselect --save

使用

import { createSelector } from "reselect"
//导出订单
export const getOrders = state => state.orders;
//导出刷选条件
export const getFilter = state => state.filter;//reselect 可以减少不必要的计算,只有依赖的数据变了,才计算
export const getShowOrder = createSelector([getOrders, getFilter],(orders, filter) => {console.log("重新计算展示的订单");return filter === 0 ? orders : orders.filter(item => item.status === filter)}
)

day22

Hooks 16.8之后

函数定义组件:state 生命周期. hooks只能在函数定义组件中使用,函数组件名首字母要大写。

useState()
useEffect()
useReducer()
useContext()

1.useState() 状态

const [name, setName] = useState("妲己");

2.useEffect() 生命周期

​ 1.useEffect(callback) callback就是componentDidMount +componentDidUpdate.任何数据变了,都会触发componentDidUpdate

useEffect(() => {document.title = "你点了" + num + "次";});

2.useEffect(callback,[]) callback是componentDidMount,和后面数组中数据发生改变的时候的更新

​ 如果设置[],那么任何数据的改变,都不会再引起执行,就相当于是componentDidMount()

​ 任何数据变了,都不会再触发componentDidUpdate

useEffect(() => {setInterval(()=>{setDate(new Date())})document.title = "你点了" + num + "次";}, []);

3.num变了,才会触发componentDidUpdate

useEffect(() => {console.log("要重新执行了");document.title = "你点了" + num + "次";},[num])

4.useEffect(()=>{ return fn },[]) return的函数就是componentWillUnmount

 useEffect(() => {let time = setInterval(() => {setDate(new Date());});return ()=>{clearInterval(time)}}, []);

3.useReducer()

状态很多,可以使用useReducer()代替useState()

import React,{useReducer} from 'react';const initState={name:"妲己",age:20
}const reducer=(state,action)=>{switch(action.type){case "changeName":// {type:"changeName",name:'xx'}return {...state,name:action.name}case "changeAge":// {type:"changeAge",age:100}return {...state,age:action.age}default:return state;}
}const Reducer = () => {const [state, dispatch] = useReducer(reducer, initState)return (<div><div>name:{state.name}</div><div>age:{state.age}</div><button onClick={()=>dispatch({type:"changeName",name:'王昭君'})}>王昭君</button><button onClick={()=>dispatch({type:"changeAge",age:100})}>age=100</button></div>);
}export default Reducer;

4.useContext()

父组件给子组件传值,子组件没用,子组件传递给了自己的子组件,这样传递,容易出错,可以使用useContext() 让父组件直接将数据传递给子组件的子组件。

1.父组件
import React,{useState} from 'react';
import Child from './Child';//1.创建一个Context对象
export let MyContext=React.createContext();
const Context = () => {const [name, setName] = useState('妲己');const [age, setAge] = useState(20);return (<div className="box"><h3>useContext</h3><div>name:{name}</div>{/* 2.传值 */}<MyContext.Provider value={ {name,age} }><Child ></Child></MyContext.Provider></div>);
}export default Context;
2.子组件 (什么都没做)
import React from 'react';
import ChildChild from './ChildChild';
const Child = () => {return (<div className="box"><h3>子组件</h3><ChildChild></ChildChild></div>);
}export default Child;
3.子组件的子组件
import React, { useContext } from "react";// 3.引入Context对象
import { MyContext } from "./Context";
const ChildChild = () => {// 4.取出数据const { name, age } = useContext(MyContext);return (<div className="box"><h3>child child</h3><div>name:{name}</div><div>age:{age}</div></div>);
};export default ChildChild;

days to study vue2+react相关推荐

  1. React 16 加载性能优化指南

    关于 React 应用加载的优化,其实网上类似的文章已经有太多太多了,随便一搜就是一堆,已经成为了一个老生常谈的问题. 但随着 React 16 和 Webpack 4.0 的发布,很多过去的优化手段 ...

  2. 前端前端开发工程师_我们庞大的工程师团队会使用此前端开发指南

    前端前端开发工程师 by Yangshun Tay 阳顺泰 我们庞大的工程师团队会使用此前端开发指南 (Our large team of engineers use this front end d ...

  3. 哔哩哔哩 Web 首页重构——回首2021

    本期作者 刘磊 高能链开放平台资深前端开发工程师 01 前言 在 2021 年时我们通过数据分析发现:在电脑端有越来越多用户的电脑屏幕切换成了大屏,现有 B 站的网页设计风格已经难以在宽屏设备上高效率 ...

  4. 关于Java 软件工程师应该知道或掌握的技术栈

    鄙人星云,今天突然想写这么一篇需要持续更新的文章,主要目的用于总结当前最流行的技术和工具,方便自己也方便他人. 更新时间:2018-10-23 09:26:19 码农职业路径图 码农入门职业路径图 J ...

  5. 重走Android路 之 今日正式启程

    LZ-Says:重拾路,奠基路,加油~! 前言 14年9月,到现在,三个多年头了,从帝都到廊坊,再从廊坊回到帝都,经历了很多,也看淡了很多. 相比技术而言,承担的越来越多,责任也随着年纪逐渐上升,压力 ...

  6. zx-calendar JS日历插件(带Vue2/Vue3/React版本)

    zx-calendar, zx-vue-calendar (Vue2.x.x and Vue3.x.x), zx-react-calendar 源码文档地址:https://github.com/ca ...

  7. 尚硅谷Vue2学习笔记分享

    前言 这里是尚硅谷Vue2的学习笔记分享. 原视频是尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通 Vue3的笔记链接 文章目录 前言 初识Vue 模板语法 数据绑定 el和data ...

  8. Vue2 总结(Basic)

    title: Vue2 总结(Basic) date: 2022-03-28 10:38:54 tags: Vue categories: Vue cover: https://cover.png f ...

  9. 尚硅谷Vue2.0+Vue3.0全套教程视频笔记 + 代码 [P001-050]

    视频链接:尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通_哔哩哔哩_bilibili P1-50:当前页面.  P51-100:尚硅谷Vue2.0+Vue3.0全套教程视频笔记 + ...

最新文章

  1. matlab编程实现基于密度的聚类(DBSCAN)
  2. js、css分别实现元素水平垂直居中
  3. 过拟合曲线与早期停止法
  4. 数据派研究组招募 | 寻找最志同道合的你!
  5. 想进大厂?Dubbo 普普通通 9 问你知道吗
  6. c# webservice生成客户端及使用时碰到decimal类型时的特殊处理
  7. c++反汇编与逆向分析
  8. 基于Springboot2.0的Dubbo入门项目(dubbo-spring-boot-starter)
  9. XDocReport 的简单使用 操作word 替换变量,动态图片,指定操作指令(程序)扩展(转自:http://www.cnblogs.com/fish-in-sky/p/4973237.html)
  10. 如何才能优雅地书写JS代码
  11. ASP.NET Core端点路由 作用原理
  12. Devexpress - office - 效果
  13. 使用Json封装scroll,已处理其兼容性问题
  14. 来认识下less css
  15. 两个一样的图像相除会怎么样_【壮凌自动化分析】一种动力电池生产中基于图像运动模糊的速度检测方法...
  16. UnityShader18.1:立方体贴图(下)
  17. 引入react文件报错_React Native常见问题(一)
  18. ati开源驱动_ATI Radeon 9800 Vista驱动程序-Flash和Windows视频停止或卡顿
  19. 三菱FX3UFX2NFX1N PLC 模拟器模拟通信功能,模拟PLC实体,FX3U仿真器,仿真PLC服务器
  20. 深圳神州行今日起单向收费 零月租成套餐亮点

热门文章

  1. 桌面图标有了蓝色问号解决方案
  2. 《疯狂Java讲义》读书笔记5
  3. eclipse看不到android设备,为什么Eclipse的Android设备选择器没有显示我的Android设备?...
  4. 推荐开发工具系列之--PyF5(自动刷新)
  5. 中国公有云厂商2019年收入排名TOP10分析
  6. three.js旋转,材质,灯光使用 —— 太阳地球月亮运动
  7. 宣布发布 .NET 7 Release Candidate 1
  8. 电脑文件管理,教你批量给全部文件夹名称随机命名
  9. 8.3.7-8.3.8
  10. 滚动截屏苹果_30个小技巧,带你玩转苹果三大系统