days to study vue2+react

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/[email protected]">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">
  
  <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

社会很单纯

复杂的是人

2.v-show

社会很单纯

复杂的是人

3.v-else

暂无评论
{{comments}}
4.v-if VS v-show
相同点:true 出现,false消失
不同点:false情况下,v-if采用的 惰性加载;v-show采用的是display:none.
使用场景:如果频繁切换,那么就使用v-show;如果不频繁切换,建议使用v-if

5.列表渲染 v-for

1.遍历数组

  • {{index}}---{{item}}
comments: ["物美价廉", "很好", "推荐"],
2.遍历json

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

6.动态类名

1.变量


打疫苗了吗?

2.【三元】


绿水青山就是金山银山

3.json

 
大力改革教育

7.动态行间样式


天道酬勤,人道酬善,商道酬信。

6.复习知识:

1.toFixed()

7.作业:

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

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

day02

Vue 不支持 IE8 及以下版本

0.案例

bootstrap官网:

http://bootcss.com

1.双for

name:{{item.name}}

导演: {{i.name}}  

主演: {{i.name}}  

2.表单

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

1.指令 v-model
2.单选框

性别:
3.多选框

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

爱好: 唱歌 跳舞 写代码 打游戏
是否同意
user: {
  "name": "11",
  "pass": "22",
  "tel": "322",
   "sex": 1,
  "hobby": [2, 3, 4],
   "job": 2,
  "snacks": [1, 2],
    "des": "123123",
   "isAgree": true
}
4.下拉菜单

职业:
零食:
5.多行文本框
备注:
6.表单修饰符


name:{{name}}
{{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.如何绑定事件







n:{{n}}

2.事件传参


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









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-text
	2.数组变了,不渲染,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属性


	

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:"
我是hello
"
})

2.局部注册

new Vue({
  el:"#app",

  //局部组件:只有当前vue实例可用
  components:{
    websitenav:{
      template:"
特色主题
行业频道
更多精选
"
} } })

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

3.组件命名

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

4.template

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

vSecond:{
  template:"#second"
},
<template id="second">
  <div>
    <h3>this is secondh3>
  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接收,然后使用

父组件:
 

子组件:

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

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

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

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

父组件:
 
    
子组件:
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节点


 this.$refs.div.style.background='blue';
 this.$refs.div.innerHTML="123"

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

 
   
 // this.$refs.child.name="貂蝉"
 this.$refs.child.changeName('貂蝉')

3.is

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


2.实现动态组件





4.脚手架上使用动画

1.安装

npm i animate.css --save

2.main.js引入

import "animate.css"

3.使用


  

5.scoped

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


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.匿名插槽

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


  
善上若水,水善利万物而不争

one组件:

this is one

2.具名插槽

two组件

this is two


  
  1. 锦瑟无端五十弦
  2. 一弦一柱思华年
  • 床前明月光
  • 疑是地上霜
手机

3.作用域插槽

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

父组件:

  
  



  
  

子组件(three)




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


  

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.内置组件



5.路由导航高亮效果

首页 分类 购物车 我的

6.编程式导航

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

5.作业

1.练习2遍;

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

3.app 至少一遍

day07

1.路由传参

手机
this.$route.query.id //1
this.$route.query.name //2

2.命名路由

{ 
    path: '/search', 
    component: search,
    // 命名路由
    name:"搜索",

  },
router-link :to="{name:'搜索'}">前往搜索

3.命名视图 -了解




//一级路由
  {
    path: '/login',
    // component: login,
    components:{
      default:login,
      view2:test
    },
    name: "登录",
    // 路由元信息
    meta: {
      title: "登录"
    }
  },

4.动态路由

1.传递参数

手机

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/#/login
	1.前进 后退 刷新  都ok
	2.#/login 是hash值,hash值是不会影响请求
	3.采用的是window.onhashchange=()=>{} 原理实现,是可以兼容IE678的
history http://baidu.com/login
	1.前进 后退 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" null
  if(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有,滚动到savedPosition
    if(savedPosition){
      return savedPosition
    }else{
      return {x:0,y:0}
    }
  }

9.路由元信息

{
    path: '/login', component: login, name: "登录",
    // 路由元信息
    meta: {
      title: "登录"
    }
  },
{{$route.meta.title}}

10.作业

1.app 练习2遍

day07

1.路由传参

手机
this.$route.query.id //1
this.$route.query.name //2

2.命名路由

{ 
    path: '/search', 
    component: search,
    // 命名路由
    name:"搜索",

  },
router-link :to="{name:'搜索'}">前往搜索

3.命名视图 -了解




//一级路由
  {
    path: '/login',
    // component: login,
    components:{
      default:login,
      view2:test
    },
    name: "登录",
    // 路由元信息
    meta: {
      title: "登录"
    }
  },

4.动态路由

1.传递参数

手机

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/#/login
	1.前进 后退 刷新  都ok
	2.#/login 是hash值,hash值是不会影响请求
	3.采用的是window.onhashchange=()=>{} 原理实现,是可以兼容IE678的
history http://baidu.com/login
	1.前进 后退 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" null
  if(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有,滚动到savedPosition
    if(savedPosition){
      return savedPosition
    }else{
      return {x:0,y:0}
    }
  }

9.路由元信息

{
    path: '/login', component: login, name: "登录",
    // 路由元信息
    meta: {
      title: "登录"
    }
  },
{{$route.meta.title}}

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 = {
  // 部署应用时的基本 URL
  publicPath:"",
  // build 时构建文件的目录
  outputDir: 'dist',
  // build 时放置生成的静态资源 (js、css、img、fonts) 的目录 assetsDir: 'static',
  // 指定生成的 index.html
  indexPath: '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.使用
123

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.组件就可以使用

this is a

name:{{$store.state.name}}
age:{{$store.state.age}}

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
    }
  },
  //逻辑 :处理异步,不能直接修改state
  actions: {
    /*
     * @param {*} context 当前仓库本身
     */
    changeName2s(context) {

      setTimeout(() => {
        context.commit("changeName", '西施')
      }, 2000)
    },
    changeName(context, name) {
      context.commit("changeName", name)
    },
    //请求list
    reqArr(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.数组方式



2.json方式

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

8.modules 模块

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

9.目录结构

-store
	index.js //创建仓库并导出
	actions.js //根级别下的actions
	mutations.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





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

-store
	index.js //创建仓库并导出
	actions.js //根级别下的actions
	mutations.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.导出banner
    banner(state) {
        return state.banner
    },
    
}

const mutations = {
    //3.修改banner
    changeBanner(state, banner) {
        state.banner = banner;
    },
    
}

const actions = {
    //4.请求banner
    reqBanner(context){
        reqBanner().then(res=>{
            //5.触发修改banner
            context.commit("changeBanner",res.data.list)
        })
    },
   
}

2.home.vue使用




7.home下的cates

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

import {reqBanner,reqHomeCate} from "../../http/api"
const state = {
   
    // 6.分类初始值
    cates:[]
}

const getters = {
   
    //7.导出cates
    cates(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.组件使用






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是否有token
  if(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文件夹,处理预处理

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

3.组件使用


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/#/a

b页面—>index.html/#/b
MPA:

多页面应用

优点:有利于SEO

缺点:会有白屏,用户体验不好

a页面—>a.html

b页面—>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(
  ,
  document.getElementById('root')
);

App.js

function App() {
  return (
    
123
); } export default App;

3.JSX语法

1.非表单元素 div

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

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


      
        
      

3.条件渲染

let arr = [1, 2, 3, 4];
let isshow = false;
{/* 条件渲染   {三元判断} ,如果没有内容展示,就定为null*/}
{arr.length > 0 ? 
有数据
:
暂无数据
} {isshow ?
弹框
: 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={三元} */}
11 ? "red" : "blue"}>小车车
{news.map((item, index) => { return (
{item.name}
); })}

6.动态行间样式

let bg = "pink";
{/* 行间样式 语法:style={json} */}

行间样式

天道酬勤
商道酬信

7.注释

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

4.组件

1.如何注册?

1.函数注册

function First(props) {
  return (
    
); } export default First;

2.类定义注册

import React,{Component} from "react"

class Second extends Component{  
    constructor(){      
        super();//构造函数必须加super()
    }
   
    //渲染钩子函数
    render(){
       
        return (
            

this is second -{this.name}--{age}--{this.name2}--{name3}--{this.name4}

) } } 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.
        */}


2.如何传参?

{/* 2.如何传参?
        (1)箭头函数:正常传参
        (2)bind: 第2个实参对应第1个形参
        */}


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

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




4.阻止默认 阻止传播?

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

6.state

// 1.初始化在constructor
// 2.取值:var { name, age, sex } = this.state;
// 3.如果state要全部传递给子组件,可以使用 
// 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接收

父组件
 
子组件
  let { name} = props;

子传父

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

父组件
 this.changeWang()}
          cname={(name) => this.changeName(name)}
        >
子组件
export default function Child(props) {
  let {  changeWang,cname } = props;
  return (
    

this is child

); }

3.生命周期

1.初始期
    (1)constructor:初始化数据
    (2)render:渲染DOM
    初始期:渲染DOM节点; 更新期:调和过程,进行diff算法,计算出最优的更新方式,局部更新
    (3)componentDidMount:渲染完成:计时器、请求打开,window|document添加事件、获取DOM
2.更新期(state、props)
    shouldComponentUpdate() : 判断是否更新
        (1)没有return内容,报错
        (2return true. 更新流程 shouldComponentUpdate->render->componentDidUpdate
        (3) return false.更新流程:shouldComponentUpdate
    render() 调和过程,进行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.修改user
  changeUser(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.各个表单使用

{/* 对于单选框来说,需要自己手动设置value;赋值使用的是checked */} 性别: this.changeUser(e, "sex")} value="0" checked={user.sex === "0"} /> 男 this.changeUser(e, "sex")} value="1" checked={user.sex === "1"} /> 女
{/* 多选框,取值checked+value;赋值:checked */} 爱好: {hobbyList.map((item) => ( ))}
{/* select 取值 value;赋值 value */} 职业:
{/* textarea 取值value;赋值 value */} 描述:

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();
  }
 
changeColor(color) {
  let div = this.div.current;
  div.style.background = color;
  div.innerHTML = color;
}

2.获取子组件实例

constructor() {
    super();
    // 创建一个ref对象
    this.child=React.createRef()
  }

 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

哈哈

嘿嘿嘿

); } } export default First;
2.<>
import React, { Component } from 'react';

class First extends Component {
    render() {
        return (
            <>
                

fragment

哈哈

嘿嘿嘿

); } } 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.props
        return (
            

PureComponent

name:{name}
arr:{JSON.stringify(arr)}
); } } export default Child2;
3.React.meno()-函数定义组件
React.memo()  浅比较,如果传递的数据是引用类型,引用类型的改变,建议需要使用 拷贝 
React.memo() 本身是一个函数, 参数是个组件,返回一个新的组件,这样的函数叫高阶组件(HOC
function Child3(props) {
  let { name ,arr} = props;
  console.log("child3 开始计算");
  return (
    

child3

name:{name}
arr:{JSON.stringify(arr)}
); } 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.state
        return (
            
{ hasError?
此处有报错!!
:this.props.children }
); } } export default ErrorBoundary;

2.使用组件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.state
            return (
                <>
                    
                
            )
        }
    }
}

调用

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(
  
    
  
  ,
  document.getElementById('root')
);

2.路由出口【Switch】

import {Switch} from "react-router-dom"

3.路由规则【Route】

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

4.重定向【Redirect】

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

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

搜索
搜索
高亮效果:
首页 分类 购物车
首页 分类 购物车

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给非路由组件;
		
	②使用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 (
            
        );
    }
}

export default withRouter(GoBack);

7.路由传参【?】

 {item.name}
取参数:

1.原生js

componentDidMount(){
        let str=this.props.location.search;//"?id=2&name=qqq&age=122" --{id:"2",name:"qqq",age:"122"}
        // 1.利用原生js
        
        let 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.原生js
        let params=new URLSearchParams(str);
        console.log(params.get("id"));
        console.log(params.get("name"));

    }

8.动态路由【:】

 {item.name}

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' null
        return (
            <>
                {
                    islogin?:
                }
            
        );
    }
}

export default PrivateRoute;

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


  {/* 路由规则 */}
  
  {/* exact 精确匹配,默认false,如果没设,那么‘/register/a’也会进入'/register'
        strict 严格模式,默认false,如果没有设置,那么“/register/”是可以访问的;如果设置了严格模式,只能访问“/register”
        strict 需要和exact 一起使用
        */}
  
  


  
  

  {/* exact精确匹配 */}
  
  {/* 重定向 */}
  {/*  */}

  {/* 404 404千万不要设置exact,这句写在最后*/}
  

10.路由独享守卫

 {
          let type=sessionStorage.getItem("type")
          if(type==="2"){
            return 
          }else{
            return 
你没有权限 !!!!
} }}>

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必须的
    正在加载。。。
}> {/* 2.路由出口 */}

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('
                    
                    

你可能感兴趣的:(react.js,前端,vue)