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
https://cn.vuejs.org/
MPA:多个url–》多个HTML文件 多页面应用
[优点:有利于SEO优化,缺点:会出现白屏,用户体验度不好]
SPA:对个url—>1个html
[优点:用户体验好 缺点:首屏加载速度慢,不利于SEO优化]
数据驱动 组件系统
<script src="https://cdn.jsdelivr.net/npm/[email protected]">script>
npm init
npm i vue //安装vue
//安装淘宝镜像
npm install -g cnpm --registry=https://registry.npm.taobao.org
js :事件 innerHTML value src className style.color …
jq:事件 html() val() attr() class css …
Vue:非表单元素(div span) 表单元素(input textarea select …) 媒体元素(img video )–给属性赋值 样式。。。。
{{}} 优点:简单方便 缺点:1.不能解析标签;2.首屏可能会出现闪屏
v-html 优点 :可以解决闪屏问题 可以解析标签 【主要用于详情】
v-text 优点:可以解决闪屏问题 缺点:不能解析标签
首屏建议使用v-text|v-html,其他屏你喜欢用什么就用什么。
v-model
<div>
账号:<input type="text" v-model="name">
div>
<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>
社会很单纯
复杂的是人
社会很单纯
复杂的是人
暂无评论
{{comments}}
相同点:true 出现,false消失
不同点:false情况下,v-if采用的 惰性加载;v-show采用的是display:none.
使用场景:如果频繁切换,那么就使用v-show;如果不频繁切换,建议使用v-if
- {{index}}---{{item}}
comments: ["物美价廉", "很好", "推荐"],
{{key}}:{{value}}
data: {
comments: ["物美价廉", "很好", "推荐"],
json: {
name: "妲己",
age: 20,
sex: "女"
},
}
当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key
1.变量
打疫苗了吗?
2.【三元】
绿水青山就是金山银山
3.json
大力改革教育
天道酬勤,人道酬善,商道酬信。
1.toFixed()
1.今天的案例练习3遍;
2.作业文件夹中的2个作业
bootstrap官网:
http://bootcss.com
name:{{item.name}}
导演:
{{i.name}}
主演:
{{i.name}}
表单数据,建议定义一个json,key和后端要求的字段一直,目的是为了方便和后端交互
性别:
男
女
对于checkbox来说,如果初始值是数组,最后就是数组;否则都是boolean
爱好:
唱歌
跳舞
写代码
打游戏
是否同意
user: {
"name": "11",
"pass": "22",
"tel": "322",
"sex": 1,
"hobby": [2, 3, 4],
"job": 2,
"snacks": [1, 2],
"des": "123123",
"isAgree": true
}
职业:
零食:
备注:
name:{{name}}
{{msg}}
单选、多选、下拉菜单都是onchange,不可以使用onclick
MVVM M-模型(model) V-视图(view) VM-视图模型(viewModel)
模型 通过 视图模型(控制器) 决定了视图的展示;
视图可以通过 视图模型(控制器) 改变模型的数据
视图模型是 视图 和模型之间的桥梁
vue是MVVM模式框架,适合操作数据多的情况使用
jq:dom操作方便、动画、链式操作
官网:jq【维护】
管理系统:vue 【内部使用 不需要推广,数据多,改版】(必然是你)
商城类:数据多,动画多 vue+jq
app:(不一定是你) 改版+数据+动画 vue+jq
活动页:【好看、一次性使用】html+css+jq(是你)
n:{{n}}
//阻止默认事件
e.preventDefault()
//阻止传播
e.stopPropagation()
.prevent 阻止默认
.stop 阻止传播
.self 触发的目标元素是自己才执行
.once 一次性触发
.capture 捕获
.up 上键
.down 下键
.left 左键
.right 右键
.enter 回车键
.13
1.arr.splice(index,1,newObj)
2.Vue.set(arr,index,newObj)
3.this.$set(arr,index,newObj)
4.取回来数据,先操作,再赋值给数组。
1.Vue.set(this.json,"y",40)
2.this.$set(this.json,"y",40)
3.this.json={
...this.json,
y:40
}
1.阻止默认 阻止传播
if(e.preventDefault){
e.preventDefault()
}else{
e.returnValue=false
}
1.练习3遍
2.作业文件夹的2个作业
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
监听数据的改变,只能监听data中的数据和computed中的数据
new Vue({
watch:{
kw(newV,oldV){
//逻辑
},
json:{
handler(){
console.log("json变了");
},
deep:true
}
},
})
注意:不建议使用深度监听
1.深度监听会造成页面卡顿;
2.可以使用事件代替监听
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就是后端返回的数据
}
转换数据
| 管道符
全局注册
// 全局过滤器:所有的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)
},
}
})
new Vue({
computed:{
allPrice(){
return 10
}
}
})
watch:
一个数据影响多个数据的改变
没有调用,自动执行
可以操作异步
computed:
多个数据影响一个数据
手动调用,当做属性调用
做同步
可以有缓存
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解决
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
1.练习 3遍
2.作业文件夹中的作业
1.淘宝搜索
2.购物车
1.v-if
2.v-show
3.动态组件
4.路由
进来之前 enter
进来过程 enter-active
进来完成 enter-to
离开之前 leave
离开过程 leave-active
离开完成 leave-to
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);
}
官网:https://animate.style/
npm i animate.css
<link rel="stylesheet" href="./node_modules/animate.css/animate.css">
<transition enter-active-class="animate__animated animate__fadeInDown"
leave-active-class="animate__animated animate__bounceOutLeft">
<div class="box" v-if="isshow">div>
transition>
1.一般情况下只写进来动画,不写离开,否则,太花里胡哨。
可复用的vue实例。(公共的html+css+js)
1.全局注册
//全局组件:所有的vue实例都可以调用
Vue.component("hello",{
template:"我是hello"
})
2.局部注册
new Vue({
el:"#app",
//局部组件:只有当前vue实例可用
components:{
websitenav:{
template:" 特色主题行业频道更多精选"
}
}
})
3.大部分使用局部,少数使用全局。
components: {
// 1.不能以已经存在的标签命名。比如:div input span ...
// 2.也不能以已经存在的标签的大写命名。比如:DIV INPUT ...
// 3.如果组件名中间包含了大写(除首字母之外),使用的时候需要变成-小写 ,烤串写法
WebsiteNavComponenT: {
template: "这是第一个组件"
},
// 4.建议名称中包含大写,目的是为了方便调用
vHello: {
template: "hello"
}
}
1.template 可以借助template标签来实现组件的模板
vSecond:{
template:"#second"
},
<template id="second">
<div>
<h3>this is secondh3>
div>
template>
2.template只能有1个根节点。因为一个vue实例只能作用在1个节点上,如果有很多节点,只能作用在满足条件的第一个节点上
//只执行一次
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
1.练习3遍
2.作业文件夹中的作业
组件关系:父子关系 非父子
场景:父组件控制数据。子组件控制的结构
语法:父组件通过自定义属性传值,子组件通过props接收,然后使用
子组件:
export default {
props:["img","title"]
}
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)
}
},
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)
注意:ref一定要在mounted之后使用
this.$refs.div.style.background='blue';
this.$refs.div.innerHTML="123"
// this.$refs.child.name="貂蝉"
this.$refs.child.changeName('貂蝉')
1.解决了标签固定搭配问题
2.实现动态组件
1.安装
npm i animate.css --save
2.main.js引入
import "animate.css"
3.使用
样式只在当前文件夹中起作用。 建议每个组件都加scoped.
1.安装
npm i jquery --save
2.引入
import $ from "jquery"
3.使用[注意:1.mounted之后再使用;2.注意this指向,最好使用箭头函数]
$(".show").click(()=>{
$(".red").fadeIn(400)
})
$(".hide").click(()=>{
$(".red").fadeOut(400)
})
所有嵌套的内容都会出现在匿名插槽中
善上若水,水善利万物而不争
one组件:
this is one
two组件
this is two
- 锦瑟无端五十弦
- 一弦一柱思华年
- 床前明月光
- 疑是地上霜
手机
作用域插槽:父组件调用了子组件,子组件展示数据,结构又不确定,那么使用插槽;但是这段不确定的结构中有使用到数据,需要slot传递回来,父组件使用。
{{item}}
子组件(three)
展示的组件
展示完成
1.data为什么是个函数?
2.如何实现动态组件?
3.组件之间如何通信?
4.ref的作用是什么?
5.is的作用是什么?
1.练习3遍
2.作业文件夹中的作业【尽量做】
查看作业笔记.md
作用:将两个组件公共的逻辑提取。
语法:
export default {
data(){
return {
isshow:false
}
},
methods:{
show(){
this.isshow=true
},
hide(){
this.isshow=false
}
}
}
组件使用:
import toggle from "./toggle"
export default {
mixins:[toggle]
}
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;
},
将url映射到组件上。
routes=[
//一级路由
{ path: '/login', component: login },
{
path: "/index", component: index,
},
{
path: "/detail", component: detail
},
{ path: "/list", component: list },
]
{ path: "*", redirect: "/login" }
{
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"
}
]
},
this.$router.push("/search") //是添加了新的历史记录
this.$router.replace("/search") //是使用新的记录替换当前记录
this.$router.go(-1) //返回
1.练习2遍;
2.作业文件夹中的作业 1
3.app 至少一遍
day07
手机
this.$route.query.id //1
this.$route.query.name //2
{
path: '/search',
component: search,
// 命名路由
name:"搜索",
},
router-link :to="{name:'搜索'}">前往搜索
//一级路由
{
path: '/login',
// component: login,
components:{
default:login,
view2:test
},
name: "登录",
// 路由元信息
meta: {
title: "登录"
}
},
1.传递参数
手机
2.修该路由规则
{
path:"/detail/:id/:name"
}
3.取值
this.$route.params.id //1
this.$route.params.name //手机
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模式,需要后端配合。
如果没有设置守卫,可以自由出入;如果设置了守卫,需要守卫允许,才可以进入或者离开
全局守卫
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")
})
let index=()=>import("../pages/index/index.vue")
let list=()=>Promise.resolve(import("../pages/list/list.vue"))
//滚动处理
scrollBehavior (to, from, savedPosition){
//如果之前savedPosition没有,滚动到{x:0,y:0}
//如果之前savedPosition有,滚动到savedPosition
if(savedPosition){
return savedPosition
}else{
return {x:0,y:0}
}
}
{
path: '/login', component: login, name: "登录",
// 路由元信息
meta: {
title: "登录"
}
},
{{$route.meta.title}}
1.app 练习2遍
手机
this.$route.query.id //1
this.$route.query.name //2
{
path: '/search',
component: search,
// 命名路由
name:"搜索",
},
router-link :to="{name:'搜索'}">前往搜索
//一级路由
{
path: '/login',
// component: login,
components:{
default:login,
view2:test
},
name: "登录",
// 路由元信息
meta: {
title: "登录"
}
},
1.传递参数
手机
2.修该路由规则
{
path:"/detail/:id/:name"
}
3.取值
this.$route.params.id //1
this.$route.params.name //手机
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模式,需要后端配合。
如果没有设置守卫,可以自由出入;如果设置了守卫,需要守卫允许,才可以进入或者离开
全局守卫
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")
})
let index=()=>import("../pages/index/index.vue")
let list=()=>Promise.resolve(import("../pages/list/list.vue"))
//滚动处理
scrollBehavior (to, from, savedPosition){
//如果之前savedPosition没有,滚动到{x:0,y:0}
//如果之前savedPosition有,滚动到savedPosition
if(savedPosition){
return savedPosition
}else{
return {x:0,y:0}
}
}
{
path: '/login', component: login, name: "登录",
// 路由元信息
meta: {
title: "登录"
}
},
{{$route.meta.title}}
1.app 练习2遍
官网:http://www.axios-js.com/zh-cn/docs/
axios 是一个基于 Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生 XHR 的封装,只不过它是 Promise 的实现版本,符合最新的 ES 规范,它本身具有以下特征:
从浏览器中创建 XMLHttpRequest
⚫ 支持 Promise API
⚫ 客户端支持防止CSRF
⚫ 提供了一些并发请求的接口(重要,方便了很多的操作)
⚫ 从node.js创建http请求
⚫ 拦截请求和响应
⚫ 转换请求和响应数据
⚫ 取消请求
⚫ 自动转换JSON数据
在你的项目目录下创建一个文件,叫 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
}
}
}
}
注意:前端项目重启
npm i axios --save
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=>{})
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),
})
}
//注册
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
})
}
//请求拦截:返回的是后端收到的请求
//每次请求都要携带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;
})
// 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;
}
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)
1.布局 ;2. 表单; 3.展示数据;4.js反馈; 5.常用的界面组件
https://element.eleme.cn/#/zh-CN
npm i element-ui -S
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
123
http://v1.iviewui.com/
https://vant-contrib.gitee.io/vant/#/zh-CN/
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
npm i vuex --save
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}}
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: {
}
})
$store.state.name
$store.commit('changeName','貂蝉')
$store.dispatch("changeName",'貂蝉')
mutations 同步 可以修改state 通过commit() 第一个参数是状态集合(state)
actions 逻辑(同步和异步都可以做) 不能修改state 通过dispatch() 第一个参数是仓库对象(store)
$store.getters.name
state--(getters)-->compoonents--(dispatch)-->actions--(commit)-->mutations--修改-->state--更新-(getters)--->components -...
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8US5FQDY-1659630008219)(/Users/haoliuting/Desktop/0308/day11-vuex/笔记/vuex.png)]
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(){}
},
};
new Vuex.Store({
modules:{
home:{
namespaced:true,//命名空间 有了它,就可以通过“home/list”
state:{},
mutations:{},
actions:{},
getters:{}
}
}
})
-store
index.js //创建仓库并导出
actions.js //根级别下的actions
mutations.js //根级别下的mutations state getters
-modules //模块
home.js //home模块
shop.js
vuex 刷新就没有了 操作数据方便 实时渲染
本地存储 刷新还在 操作不方便 不具备实时渲染
本地存储和vuex同步
vuex是单项数据流
v-model双向数据绑定.
如果遇到了表单,就使用v-model,此处不能使用vuex.
vuex vue-router css-pre (less)
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 里的文件都删除
-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
}
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使用
首页
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.组件使用
首页
{{item.catename}}
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({})
}
},
import store from "../store"
//登录拦截
router.beforeEach((to,from,next)=>{
if(to.path=="/"){
next()
return;
}
//判断仓库user是否有token
if(store.getters.user.token){
next()
return;
}
next("/")
})
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;
})
1.创建项目 选择了预处理器(less)
2.创建less文件夹,处理预处理
-less
index.less //整合所有的less
color.less //颜色
size.less //大小
table.less //表格
form.less //表单
text.less //文本
3.组件使用
vue是渐进式 JavaScript 框架
渐进式 :主张最少。
1.轻量级的数据框架
2.双向数据绑定
3.提供了指令
4.组件化开发
5.客户端路由
6.状态管理
1.Vue 底层基于 Object.defineProperty 实现响应式,而这个 api 本身不支持 IE8 及以下浏 览器,所以Vue不支持IE8及其以下浏览器;
2.Vue 打造的是SPA,所以不利于搜索引擎优化(SEO);
3.由于 CSR(客户端渲染)的先天不足,导致首屏加载时间长,有可能会出现闪屏。
数据驱动 组件系统
M-model模型
V-view视图
VM-viewModel 视图模型
模型(model)通过了视图模型 决定了视图(view)
视图(view) 通过视图模型 修改模型 (model)
视图模型是模型和视图之间的桥梁。
single page application 单页面应用
优点:加载快,用户体验好
缺点:不利于SEO,首屏加载时间长
a页面—>index.html/#/a
b页面—>index.html/#/b
多页面应用
优点:有利于SEO
缺点:会有白屏,用户体验不好
a页面—>a.html
b页面—>b.html
React 是Facebook内部的一个JavaScript类库。
React 可用于创建Web用户交互界面。
React不是一个完整的MVC框架,最多可以认为是MVC中的V(View),甚至React并不非常认可MVC开发模式。
React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。
React 引入了虚拟DOM(Virtual DOM)的机制。
React 引入了组件化的思想。
React 使用Facebook专门为其开发的一套语法糖--JSX。
● React速度很快
react并不直接对DOM进行操作,引入了一个叫做虚拟DOM的概念,安插在javascript逻辑和实际的DOM之间,性能好。
● 跨浏览器兼容
虚拟DOM帮助我们解决了跨浏览器问题,它为我们提供了标准化的API,甚至在IE8中都是没问题的。
● 一切皆是组件
代码更加模块化,重用代码更容易,可维护性高。
● 单向数据流
Flux是一个用于在JavaScript应用中创建单向数据层的架构,它随着React视图库的开发而被Facebook概念化。
● 同构、纯粹的javascript
因为搜索引擎的爬虫程序依赖的是服务端响应而不是JavaScript的执行,预渲染你的应用有助于搜索引擎优化。
React不适合做一个完成的框架。
React本身只是一个V而已,并不是一个完整的框架,所以如果是大型项目想要一套完整的框架的话,基本都需要加上ReactRouter和Flux才能写大型应用。
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,提高用户体验。
//安装脚手架
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;
{/* {} 可以绑定数据、方法、表达式 */}
姓名:{name}
价格:{price.toFixed(2)}
{1 > 2 ? name : name2}
let arr = [1, 2, 3, 4];
let isshow = false;
{/* 条件渲染 {三元判断} ,如果没有内容展示,就定为null*/}
{arr.length > 0 ? 有数据 : 暂无数据}
{isshow ? 弹框 : null}
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>;
})}
{/* 动态类名 1.使用className代替class; 2.语法 className={三元} */}
11 ? "red" : "blue"}>小车车
{news.map((item, index) => {
return (
{item.name}
);
})}
let bg = "pink";
{/* 行间样式 语法:style={json} */}
行间样式
天道酬勤
商道酬信
{/* 注释 */}
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;
// 1.一个组件的模板,只能有一个根节点;
// 2.组件名首字母要大写
// 3.可以以已经存在的标签的大写命名。eg:Form
// 4.组件名中间有大写,原样调用即可。eg:WebsiteNav
// 5.注册组件:(1)函数定义组件 (2)类定义
(1)类定义组件 有生命周期,函数定义的没有;
(2)类定义有state,函数定义没有;
(3) 对于父组件传递的数据,类定义组件通过this.props接收,函数定义通过props接收。
(4)对于类定义,每调用一次,就会实例化一个对象,而对于函数组件,只是单纯的计算,所以函数的性能高于类定义。
home 类 业务组件
banner 函数 木偶组件
list 函数
{/* 1.如何绑定事件?
(1)箭头函数:不用管this
(2)bind: 第一个参数是调用该函数的对象,一般使用this.
*/}
{/* 2.如何传参?
(1)箭头函数:正常传参
(2)bind: 第2个实参对应第1个形参
*/}
{/* 3.event 事件对象如何获取?
(1)显示传参: 箭头函数,event想在哪一位就在哪一位
(2)隐式传参:bind 没有参数的第一位是event. event永远都在最后一位
*/}
{/* 4.阻止默认 阻止传播?
(1)阻止默认:e.preventDefault() 注意:return false 不可以;
(2)阻止传播:e.stopPropagation()
(3)捕获事件:Capture.eg:onClickCapture
*/}
this.yj(e)}>
this.outerClick()}>
冒泡
this.outerClick2()}>
this.innerClick2()}>
捕获
// 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 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面。在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。
1.react的优缺点
2.react中组件如何创建?
3.函数定义组件和类定义组件的区别?
4.setState()中第二个参数为什么是个回调函数?
5.setState()调用后发生了什么?
练习:3遍
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:自己的状态,可以修改,而且需要通过setState()。state变了,页面会重新渲染
props:父组件传递过来的状态,不可以直接修改。props变了,页面会重新渲染
父传子:父组件通过自定义属性传递数据,子组件通过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
);
}
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.更新流程:shouldComponentUpdate
render() 调和过程,进行diff算法,计算出最优的更新方式,局部更新
componentDidUpdate() 更新完成
3.销毁期
componentWillUnmount() 销毁之前:清除计时器 取消window|document事件
就地反馈,如:验证
禁用按钮 如:提交
执行特定的输入格式 如:身份证号、银行卡号
特征 | 取值 | 赋值 |
---|---|---|
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,
},
});
}
{/* 对于单选框来说,需要自己手动设置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 */}
描述:
特征 | 受控组件 | 非受控组件 |
---|---|---|
一次性检索(例如表单提交) | 是 | 是 |
及时验证 | 是 | 否 |
有条件的禁用提交按钮 | 是 | 否 |
执行输入格式 | 是 | 否 |
一个数据的几个输入 | 是 | 否 |
动态输入 | 是 | 否 |
npm install -g cnpm --registry=https://registry.npm.taobao.org
React.createRef()
(1)创建一个ref对象;(2)将ref对象绑定到节点(3)操作 this.div.current
constructor() {
super();
// 创建一个ref对象
this.div = React.createRef();
}
changeColor(color) {
let div = this.div.current;
div.style.background = color;
div.innerHTML = color;
}
constructor() {
super();
// 创建一个ref对象
this.child=React.createRef()
}
changeChildName(name){
this.child.current.changeName(name)
}
目的:所有的组件都有一个根节点,但是有时候希望这个节点不存在,就可以使用Fragment
引入 使用
import React, { Component,Fragment } from 'react';
class First extends Component {
render() {
return (
fragment
哈哈
嘿嘿嘿
);
}
}
export default First;
import React, { Component } from 'react';
class First extends Component {
render() {
return (
<>
fragment
哈哈
嘿嘿嘿
>
);
}
}
export default First;
shouldComponentUpdate(nextProps,nextState){
// 判断旧的props上的name是否和新的props上的name一样。如果一样,就不渲染了
if(this.props.name===nextProps.name){
return false
}
return true;
}
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;
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)
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 包裹可能出错的组件
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)
import {HashRouter,BrowserRouter} from "react-router-dom"
ReactDOM.render(
,
document.getElementById('root')
);
import {Switch} from "react-router-dom"
import {Route} from "react-router-dom"
Route 的属性 :exact[是否精确匹配] 默认:false。 如果要精确匹配,需要设置exact
strict:严格模式。 需要搭配exact使用。 默认是路径后可以加'/',也可以访问,加上严格模式,有'/'就不行
import {Redirect } from "react-router-dom"
{/* 4.重定向 */}
搜索
搜索
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);
{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"));
}
{item.name}
let id=this.props.match.params.id
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,这句写在最后*/}
{
let type=sessionStorage.getItem("type")
if(type==="2"){
return
}else{
return 你没有权限 !!!!
}
}}>
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必须的
正在加载。。。
npm i axios --save
package.json 注意:配置完代理需要重启项目
{
"proxy":"http://localhost:3000",
"name": "luyou",
"version": "0.1.0",
}
略
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('