属性就是给html添加特殊的功能
语法:
卸载开标签中 属性=“属性值”
获取: npm install --save bootstrap@3
就是写页面的 让写页面的效率更高
js在设计之初是单线程的 但是要处理一些等待时间较长的操作的时候就会比较麻烦 所以js需要有异步操作来解决这个等待事件较长的问题
但是要实现异步操作那么就要有一个机制来处理异步问题 所以 事件循环就是来处理异步操作的机制
事件循环就是异步操作的机制 那么异步操作也有优先级
宏任务与微任务(优先级高)
宏任务:定时器
微任务:promise
墨客 墨刀 蓝狐 …
async 中文异步的意思 他是promise的语法糖(糖衣语法 用简单的语法来描述一个内容)
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<script>
// 使用async包装的函数会返回一个promise对象
async function fun(){
return "你好"
}
console.log(fun())
script>
body>
html>
await async wait的简写(等待异步)await必须在async包装的函数中才能使用 不能单独使用
await等待异步 他可以直接获得promise成功的返回值
作者: 尤雨溪
渐进式 的 自底向上增量开发的 mvvm框架
渐进式 可以和多种框架进行合并 vue是一个渐进式的框架(vue只会按照我们程序员的需要来进行功能的实现 不会影响到项目中没有用到vue框架的区域)只会做职责以内的事情
自底向上增量开发:先完成最基本的页面 然后再使用vue进行数据的绑定 一步步完成整个项目
mvvm
1、获取vue库文件(使用npm(包管理工具)来进行获取)
(1)在你要写项目的文件夹 上打开cmd
(2)初始化 npm init -y
(3) 下载 npm install --save xxx (默认最新版 指定版本 npm install --save xxx@你的版本)
如果太慢 可以切换成淘宝镜像 安装:npm i -g cnpm --registry=https://registry.npm.taobao.org
(4)开始编写vue的helloword
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1>{{text}}h1>
<h1>{{obj.name}}h1>
div>
<script>
// 3。vm层创建(就是vue实例)
new Vue({
// 4.创建m层数据
data:{
text:"你好",
num:18,
bool:true,
arr:[111,223,444,555,6,6,7,7],
obj:{
name:"xixi",
age:18
}
},
// 5.关联视图层
el:"#demoDiv"
})
script>
body>
html>
就是把模型数据插入到视图中
语法:
{{表达式}}
表达式: 通过计算返回结果的公式
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.js"> script>
head>
<body>
<div id="demoDiv">
<h1>{{}}中不建议复杂的内容h1>
{{num+demo}}
<h1>{{bool?"你好":"你坏"}}h1>
<h1>{{text}}h1>
<h1>{{text.toUpperCase()}}h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
num:2,
demo:3,
bool:false,
text:"abcdefghijk"
}
})
script>
body>
html>
我们只需要告诉程序你要干什么 他就会自动完成
在js中我们使用的所有变量的插入页面的过程 就是命令式 我们需要指挥程序一步步干什么
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<h1 id="demoh">h1>
<script>
let text="你好"
document.getElementById("demoh").innerHTML=text
script>
body>
html>
vue就是一个js框架 作用就是把数据用更加简单的方式插入到页面中 vue可以根据数据的改变让页面也随之发生改变
在vue中带有v-前缀的html特殊属性
指令的作用:是给html添加特殊的功能
语法:写在html的开标签中 v-指令=“指令值”
作用: 给表单元素进行数据的
语法:v-model=“变量”
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.js"> script>
head>
<body>
<div id="demoDiv">
<h1>v-modelh1>
<input type="text" v-model="text"/>
<em>{{text}}em>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
text:"你好"
}
})
script>
body>
html>
原理:数据劫持与发布者订阅者模式
数据劫持:数据拦截 vue中使用Object.defineProerty() 就是可以监听着我们data中的模型数据 当数据改变的时候 Object.defineProerty() 就会触发 模型改变 他会通知视图改变 视图改变 就会通知模型进行改变 会监听这改变 与修改
发布者订阅者模式:就是一个一对多的关系 发布者变了 所有的订阅者都会随之发生改变
作用: 就是控制元素的显示和隐藏
语法:v-show=“布尔值” true显示 false隐藏
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.js"> script>
head>
<body>
<div id="demoDiv">
<h1>v-showh1>
<h1 v-show="bool">控制我的显示和隐藏h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
bool:false
}
})
script>
body>
html>
作用:就是给dom元素绑定事件
语法: v-on:事件(不加on)=“函数” v-on:click="???" v-on:change="???"
简写语法: @事件=“函数”
函数写在那?
函数写在与el data 同级的位置 使用methods进行包裹
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.js"> script>
head>
<body>
<div id="demoDiv">
<h1>v-onh1>
<button v-on:click="fun()">点我打印内容button>
<button @click="funb()">简写button>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
},
methods:{
fun(){
console.log("你好")
},
funb(){
console.error("你坏")
}
}
})
script>
body>
html>
作用: 便利data中的数据
语法: v-for="(便利的值,便利的下表) in 你要便利的数据"
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-forh1>
<ul>
<li v-for="(v,i) in arr">
{{v}}------{{i}}
li>
ul>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
arr:["EZ","MF","NOC","VN"]
},
methods:{
}
})
script>
body>
html>
便利复杂数据
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-forh1>
<ul>
<li v-for="(v,i) in arr">
{{v}}------{{i}}
li>
ul>
<hr/>
<table border="1">
<tr v-for="(v,i) in obj">
<td>{{v.name}}td>
<td>{{v.age}}td>
tr>
table>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
arr:["EZ","MF","NOC","VN"],
obj:[
{name:"huanghuang",age:27},
{name:"bilin",age:29},
{name:"xixi",age:26}
]
},
methods:{
}
})
script>
body>
html>
作用: 给html的标签属性插入变量
语法: v-bind:html的属性=“变量” 简写 :html的属性=“变量”
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-bindh1>
<a v-bind:href="ahref">{{text}}a>
<a :href="ahref">{{text}}a>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
text:"点我去百度",
ahref:"http://www.baidu.com"
},
methods:{
}
})
script>
body>
html>
作用:判断dom是否加载
语法: v-if=“布尔值” true加载 false不加载
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-ifh1>
<input type="checkbox" v-model="bool">
<h1 v-if="bool">我是测试v-if的h1>
<h1 v-show="bool">我是测试v-show的h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
bool:true
},
methods:{
}
})
script>
body>
html>
v-if 是对dom元素进行添加和移除 v-if 在加载的时候对性能损耗低 v-if在元素频繁切换的时候性能损耗高
v-show 是对dom元素使用css进行显示和隐藏 v-show 在加载的时候对性能损耗高 v-if在元素频繁切换的时候性能损耗低
作用: v-if不符合的时候执行else
语法:必须配合v-if来进行时候用 不能单独使用
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-elseh1>
<input type="checkbox" v-model="bool">
<h1 v-if="bool">你好h1>
<h1 v-else>你坏h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
bool:true
},
methods:{
}
})
script>
body>
html>
作用 可以对多个内容进行dom添加的判断
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1 v-if="num==1">吃h1>
<h1 v-else-if="num==2">睡h1>
<h1 v-else-if="num==3">上厕所h1>
<h1 v-else-if="num==4">在睡h1>
<h1 v-else>什么也没有干h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
num:8
},
methods:{
}
})
script>
body>
html>
作用:在网页中展示纯文本内容 同{{}}类似的功能
语法: v-text=“变量”
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-texth1>
<h1>{{demo}}h1>
<h1 v-text="demo">h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
demo:"我是文本"
},
methods:{
}
})
script>
body>
html>
相同点: 都可以向页面中插入内容
不同点:{{}}模板插值得语法 而v-text是指令
v-text可以解决屏幕闪烁问题
当用户网络很慢的时候 由于js没有加载 可能会导致页面出现{{}} 问题 然后js加载成功之后 {{}}消失变成正常的数据展示 可能会在成用户体验不好
解决:
1.使用v-text
2.使用v-cloak指令来解决 当前这个指领的作用是保持元素上直到关联vue实例之后 在进行编译
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
<style>
[v-cloak]{
display: none;
}
style>
head>
<body>
<div id="demoDiv" v-cloak>
<h1>v-texth1>
<h1>{{demo}}h1>
<h1 v-text="demob">h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
demo:"我是文本1",
demob:"我是text"
},
methods:{
}
})
script>
body>
html>
作用:就是把字符串标签插入页面进行展示
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<div>
{{text}}
div>
<div v-text="text">
div>
<div v-html="text">div>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
text:"我是斜体"
},
methods:{
}
})
script>
body>
html>
作用:一次性差值
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<input type="text" v-model="text">
<h1>{{text}}h1>
<h1 v-once>{{text}}h1>
<h1>{{text}}h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
text:"你好么么哒"
},
methods:{
}
})
script>
body>
html>
监听data中的数据 如果数据改变了 那么watch就会收到通知调用一个函数(我们就可以在这个函数中完成指定的逻辑)
语法:写在与el data methods同级
watch:{
你要监听的数据 ( 新数据, 旧数据 ){
}
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<input type="text" v-model="inputval">
div>
<script>
new Vue({
el:"#demoDiv",
data:{
inputval:""
},
methods:{
},
// 监听
watch:{
inputval(newval,oldval){
console.log(newval+"----"+oldval)
}
}
})
script>
body>
html>
首次加载不会触发
课下自行百度
1.必须有node
2.如果网速慢的话 那么建议大家切换淘宝镜像
3.全局下载脚手架 npm install -g @vue/cli (只需要在 第一次使用的时候才下载 除非你重新装系统或者node 才需要再次下载)
4.查看版本 vue --version
5.创建项目
(5-1)把cmd的路径切换到你要创建项目的文件夹下
(5-2)vue create 项目名(弹出的选择选择第三个 剩下的眼睛一闭 一路回撤直到回车不了)
6.启动项目
(6-1)cd到你创建的项目之下
(6-2)输入npm run serve
1.看看有没有以来文件夹 node_modules 如果没有 那么你cd到你向前项目路径下 使用npm install 重新下载依赖
2.公司的项目或者别人的项目 怎么启动?你只需要来到 项目下的package.json文件中去查看 scripts节点即可
所有的命令都需要使用npm run 你的配置项(所有中只有一个是特例 就是start)
1.删除src下components文件夹的helloword.vue文件
2.删除src下app.vue的内容
3.在src下的components中创建我们自己的.vue文件(需要下载插件vetur)
4.在app.vue中引用我们自己的文件
<template>
<div id="app">
<Home />
div>
template>
<script>
// 1.引用 但是建议首字母大写
import Home from './components/home.vue'
export default {
name: 'App',
components: {
// 2.调用
Home
}
}
script>
<style>
style>
一个.vue文件有三个部分
template部分 就是今后写html的地方
你好
//style部分 CSS
{{text}}
课下自行整理
和本地模式一模一样
{{text}}
和本地模式一模一样
{{text}}
谁触发这个事件事件对象就是谁
事件对象
vue中对于事件上面添加了一个新的内容修饰符 通过修饰符可以对当前这个事件来设置更多辅佐性的功能
语法:
v-on:或者@事件.修饰符="函数"
对键盘上面的按键进行指定
.up .down .left .right .ctrl .enter .space
使用修饰符来完成对于指定按键的设置
1.阻止冒泡 : .stop
2.阻止默认行为 : .prevent
3.与事件冒泡相反 设置捕获 :.capture
4.只触发一次 : .once
5.只出法自己范围内的事件 不包含子元素的 .self
阻止冒泡
修饰符同时可以串联
<div class="zi" @click.stop.once="zi()">div>
他是一个vue的属性 这个属性是由计算功能的 (对data数据进行计算展示)
语法: 写在与data methods等同级位置
一条数据 在多个位置 展示不同形态的时候 使用计算属性
又或者 一个变量 需要展示之前 进行处理数据 也可以用计算属性
computed:{
计算出的结果变量(){
return 计算内容
}
}
正常展示:{{text}}
大写展示:{{textUpper}}
大写加截取展示:{{textSub}}
你好
{{newarr}}
{{fun()}}
计算属性走缓存 只要计算属性处理过数据之后 数据在没有改变的时候 无论你在页面调用
多少次 他都只执行一次 然后剩下的调用都是从缓存中进行读取的 节省资源
函数 只要被调用那么就会执行 调用多少次执行多少次 比较消耗资源
首先计算属性和监听都是 对data的数据进行相关的操作
但是计算属性是依赖data的数据 并且对data的数据进行处理返回处理后的结果
而监听 仅仅是监听 当data的数据改变了他会触发一个函数 来完成一些逻辑
axios是一个基于promise的第三方数据请求库
下载: npm install --save axios
axios的基本使用
就是浏览器的安全机制 不同源 (不同端口 不同协议 不同域名) 就会造成跨域
1.jsonp
2.代理跨域
devServer代理跨域
方式:
(1) 需要在vue项目的根路径下创建一个vue.config.js的文件
(2)写入如下内容
module.exports={
devServer:{
proxy:{
"/api":{
target:"http://www.weather.com.cn/",
changeOrigin:true,
pathRewrite:{
"^/api":""
}
}
}
}
}
(3)千万不要忘了
(3)千万不要忘了
(3)千万不要忘了
(3)千万不要忘了
(3)千万不要忘了
(3)千万不要忘了
(3)千万不要忘了
修改我们的请求路径为/api
(4)因为我们修改了配置文件 那么项目必须重启
nginx反向代理
3.cors
在发送请求的时候 但是每次如果在进行项目中 我们每请求都要携带一些参数据的时候 那么这个时候就可以使用拦截器 把每次需要在发送请求的时候携带的数据 使用拦截器 给请求进行添加 减少重复代码的编写
请求拦截
相应拦截
使用:
(1)在src文件夹下新建 api(封装数据请求的文件夹) util(工具文件夹)
(2) 创建拦截器 在util下新建一个文件 写入如下内容
import axios from "axios"
// 创建axios实例
let service=axios.create()
// 设置拦截器
// 添加请求拦截器
service.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
service.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
export default service
import axios from "axios"
// 创建axios实例
let service=axios.create()
// 设置拦截器
// 添加请求拦截器
service.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
service.interceptors.response.use(function (response) {
// 对响应数据做点什么 当相应成功正确的时候你所写的地方
return response;
}, function (error) {
console.log("http状态吗",error.response.status)
switch (error.response.status) {
case 404:
alert("哎呀网络连接超时!!!!")
break;
case 500:
alert("当前服务器正在维护请您稍后再试")
break;
default:
alert("您的错误反馈后台技术已经接收 请您稍后在次访问此页面!")
break;
}
// 对响应错误做点什么
return Promise.reject(error);
});
export default service
就是在发送请求的时候 会先经过他 可以在请求拦截里面添加每次发送请求都要携带的参数
(1)在api文件夹下创建一个文件荣来容纳数据请求的封装
import service from "@/util/service.js"
// 开始封装数据请求
function getlink(url){
return new Promise((resolve,reject)=>{
// 开始写你的数据请求
service.request({
url,
method:"GET"
}).then((ok)=>{
resolve(ok)
}).catch((err)=>{
reject(err)
})
})
}
export default getlink
(2)就要调用数据请求
1.下载 npm install --save mockjs
2.在src文件夹下创建一个mock文件夹(用来放我们的模拟数据的文件夹)
3.编写模拟数据json 与 mock配置
(3-1)创建json文件用来编写模拟数据
(3-2)配置模拟数据
// 1.引用mockjs
let Mock=require("mockjs")
// 2.配置
// Mock.mock("模拟数据地址","方式get/post",require("你的json数据"))
Mock.mock("/data/list/xiaoming","get",require("./data.json"))
4.千万不要忘了建立关联 在main.js
import Vue from 'vue'
import App from './App.vue'
// 1.引用组件
import Ceshi from "./components/ceshi.vue"
// 2.配置成为全局组件
// Vue.component(给你引用的组件起个调用名,你引用的组件)
Vue.component("Ceshi",Ceshi)
// 建立mock与项目的关系
// 因为如果我们只写了文件夹的地址 那么他会自动找到这个文件夹的index
// .js
require("./mock")
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
get请求发送数据使用params来进行发送
post发送数据 使用data
post发送数据需要进行转换 URLSearchParams()之后后台才能正常接收到数据
fun(){
// 发送post需要使用
let usp= new URLSearchParams()
// 每条数据都需要使用append进行绑定
// usp.append(你要发送数据的key,val)
usp.append("uname",this.inputaval)
usp.append("upwd",this.inputbval)
link("/api/niubi_userlist/user/denglu","post",{},usp).then((ok)=>{
console.log(ok)
})
}
}
1.在项目的根路径下创建一个vue.config.js
2.写入如下内容
module.exports={
devServer:{
// 自动开启
open:true,
// 修改端口
port:8888
}
}
组件自定义控件(通过组件就可以把一个页面拆分成一个个的小ui模块 然后把它们拼装到一块形成一个完成的页面)
可以通过组件 创建出方便复用的ui代码块
组件的本质 : 自定义标签
只能在部分地方进行使用
1.在src下的components文件夹中创建对应的组件.vue文件并且编写内容
2.显示组件(默认情况下 只创建组件 是不会在页面显示的)
(1)引用
(2)调用
在data methods的同级位置 创建components:{ 调用你的组件 }
(3)使用
可以在项目的任何地方进行使用(如果这个组件想在很多个地方都要使用 那么我们可以吧这个组件变成全局组件)除非你前期设计好组件的使用 否则建议大家少用全局组件(全局组件名会造成项目的污染)
1.在main,js中进行引用与配置
import Vue from 'vue'
import App from './App.vue'
// 1.引用组件
import Ceshi from "./components/ceshi.vue"
// 2.配置成为全局组件
// Vue.component(给你引用的组件起个调用名,你引用的组件)
Vue.component("Ceshi",Ceshi)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
2.在你想使用全局组件的地方直接用
不想让组件之间的样式相互污染
scoped -------- 当前样式仅对当前组件生效
组件与组件之间是可以相互嵌套的 那么这种嵌套关系就是父子组件
组件与组件之间的数据能相互使用吗?
父组件的数据子组件不能直接用
子组件的数据父组件不能直接用
组件与组件之间是一个完整的独立的个体 数据与数据之间默认是不能相互直接使用的。
props 是一个属性
在data methods同级使用props:[ 接受父组件传值的变量1,接受父组件传值的变量2,。。。。n ]
zizizizziizz
在组件中进行使用
zizizizziizz----{{zitext}}
父组件传值
props验证 在传统的props验证的写法中 我们可以给子组件传递任何数据类型的数据
但是在一些特殊情况下这样可能会出问题(就是如果子组件拿到数据需要对数据进行操作的时候 可能不同的数据类型所展示的结果就会出现偏差)
props验证 如果验证不成功 不会影响我们页面展示 他会在控制台给我们一个警告提示我们开发者有问题
语法:
1.在data methods等同级位置 使用
props:{
你要接受的变量:数据类型
}
zizizziziziziziziz---{{title+6}}
2.使用
3.传递
同基本写法
逆向传值默认是不被允许的 所以我们如果想进行逆向传值的话 那么我们必须要通过事件来触发传递
1.在子组件中创建一个事件触发一个函数 进行逆向传值的准备
zizizizizzi
2.抛出子组件要传递的数据------把数据绑定到自定义事件之上
自定义事件: this.$emit( “你自定义事件的名字”,“数据” )
zizizizizzi
3.父组件接受子组件抛出的数据—接受自定义事件使用数据
fyufufufff
只需要在组件之上使用ref即可直接取出子组件的数据
就是同一父组件下的子组件进行相互的数据传递
中央事件总线(eventBus):就是凌驾在两个兄弟组件之上的一个空的vue实例
1.在src下创建一个eventBus文件夹(就是容纳中央事件总线的文件夹)
// 容纳中央事件总线
import Vue from "vue"
export default new Vue
2.在要传递的组件之上抛出
ziaaaaaaaaaaaaaaaaaaaaaa
3.在接收的组件中接收
$on 监听实例上的自定义事件
zizizizizizbbbbbbbbbbbbbb
vuex状态(数据)管理工具
vuex 就可以把整个项目的数据集中的管理起来 方便组件与组件的使用 (组件想使用数据 那么不需要使用 复杂的传递方式了 直接就可以去vuex中进行数据 的获取)
传统的vue 是单向数据流 如果是兄弟或者是跨层级的组件在进行传递的时候vue就非常的麻烦
vuex就可以来进行上述传值 简化了数据传递的复杂度
store文件夹(用来容纳vuex的容器文件夹)
1.下载 npm install --save vuex
2.在src文件夹下新建store文件夹并且新建index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
})
3.在main.js 中引用vuex文件 并且在vue实例上注册
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'//引用
Vue.config.productionTip = false
new Vue({
router,
store,//注册
render: h => h(App)
}).$mount('#app')
vuex的所有数据都在state中进行创建
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {//创建数据的类似于组件中的data
text:"你好",
age:18,
arr:[111,2222,33333],
obj:{
love:"女"
}
},
mutations: {
},
actions: {
},
modules: {
}
})
1.取值方式1
任意组件直接使用 this.$store.state.xxx使用
hhhhh{{this.$store.state.text}}
2.取值方式2
使用计算属性来进行vuex的数据获取
uuuuu{{newage}}
vuex中state的数据不能直接修改
mutations 里面封装的是一个个的函数 每个函数就是一个修改的动作
如果要触发mutations的修改动作 那么我们要使用commit这个方法来进行调用
commit触发mutations修改
1.通过事件触发commit来调用修改操作
hhhhh{{this.$store.state.text}}
2.去store中编写对应的mutations修改动作
mutations: {
uptext(){
}
},
3.开始修改
mutations: {
// 第一个形参state就是指向上面的state数据源
// 第二个形参接收的就是commit方法中的第二个参数
uptext(state,payload){
state.text=payload.newtext
}
},
在vuex中如果我们修改数据之后 页面在刷新一次 那么页面的数据你会回复成默认值
created() {
//在页面加载时读取sessionStorage里的状态信息
if (sessionStorage.getItem("store")) {
this.$store.replaceState(
Object.assign(
{},
this.$store.state,
JSON.parse(sessionStorage.getItem("store"))
)
);
}
//在页面刷新时将vuex里的信息保存到sessionStorage里
window.addEventListener("beforeunload", () => {
sessionStorage.setItem("store", JSON.stringify(this.$store.state));
});
},
actions是一个触发器 他可以帮助我们触发一个异步操作(异步请求)
actions中是一个个的方法 每一个方法就是一个异步的动作
actions调用的话 使用dispatch()来进行调用
1.页面通过dispatch来触发actions
ppppp{{this.$store.state.text}}
actions创建对应的方法
actions: {
// context形参 就是store对象
demoLink(){
console.log("我是actions")
}
},
//
created(){
// 2.通过dispatch触发一个actions
this.$store.dispatch("getaxios",{url:"/data/one"})
}
3.编写对应的actions
actions: {
// 3编写对应的actions
getaxios(){
}
},
4.引用数据请求 并且发送
import Vue from 'vue'
import Vuex from 'vuex'
// 4.引用数据请求
import getlink from "@/apis/getapi.js"
Vue.use(Vuex)
export default new Vuex.Store({
state: {//创建数据的类似于组件中的data
},
mutations: {
},
actions: {
// 3编写对应的actions
getaxios(context,payload){
console.log(context)
// 5.发送一部操作
getlink(payload.url).then((ok)=>{
console.log(ok)
})
}
},
modules: {
}
})
actions: {
// 3编写对应的actions
getaxios(context,payload){
console.log(context)
// 5.发送一部操作
getlink(payload.url).then((ok)=>{
console.log(ok.data.data)
// 6.把请求来的数据交给mutations来修改state
context.commit("uparr",{arrdata:ok.data.data})
})
}
},
7创建对应的mutations
// 7创建对应的mutations
uparr(state,payload){
// 8把请求来的数据修改state
state.arr=payload.arrdata
}
在页面展示
-----
{{newarr}}
getters 可以对一个数据在不同位置展示出不同的形态时候用
getters 处理的数据 任何组件都能用
vue的计算属性处理的数据 只能当前组件使用
定义getters
getters:{
// 里面就一个形参 state代表的就是数据源
newdemo(state){
return state.demo.toUpperCase()
}
}
使用
在想使用的地方直接使用 this.$store.getters.xxx即可获取到处理好的数据
可以把原来写在一起的数据 修改 异步操作 计算属性 按照页面等进行分类管理
1.新建文件用来单独放置上述的属性
let userm={
state: {
text:"我是user的数据"
},
mutations: {
},
actions: {
},
getters:{
},
}
export default userm
2.把模块注入到vuex中
import Vue from 'vue'
import Vuex from 'vuex'
// 引用模块
import Homem from "./modules/homem.js"
import Phonem from "./modules/phonem.js"
import Userm from "./modules/userm.js"
Vue.use(Vuex)
export default new Vuex.Store({
// 注入
modules: {
Homem,
Phonem,
Userm
}
})
3.使用数据 this.$store.state.模块名.xxx
用来混合父组件与子组件自己的模板(就是可以在组件被调用的时候向其内部插入新的dom节点)
组件如果调用的时候使用双标签 那么我们在他的开关标签中能否插入新的内容?
默认情况下是不行的
fufufuffufu
这个h1是不会显示的
你好么么哒!!!!^_!
就是在你想插入新内容的组件中 放置一个 外部的内容就会显示在slot插入的位置
ziziziziz
大家会发现 上面的槽口 只有一个 但是外部插入的所有内容都在这一个上面进行显示 后期不好管理
1.定义槽口的时候 使用name创建槽口的名字
2.插入的时候需要指定往那个槽口中插入 使用slot属性
fufufuffufu
你好么么哒!!!!^_!1
你好么么哒!!!!^_!2
你好么么哒!!!!^_!3
你好么么哒!!!!^_!4
你好么么哒!!!!^_!5
你好么么哒!!!!^_!6
你好么么哒!!!!^_!7
你好么么哒!!!!^_!8
你好么么哒!!!!^_!9
你好么么哒!!!!^_!0
路由就是可以为我们完成页面之间的跳转 让我们完成单页面多视图的应用(SPA)
vue-router库来实现路由
1.下载了vue-route库
2.创建views文件夹 并且写入路由页面组件
3.配置路由规则
(3-1)新建router文件夹并且新建index.js
(3-2)设置配置文件
import Vue from 'vue'//引用vue
import VueRouter from 'vue-router'引用vuerouter
Vue.use(VueRouter)在vue中使用路由功能
创建了路由规则配置
const routes = [
{
path: '/home',
name: 'Home',
component: Home
},
]
实例化路由对象 并且设置路由模式与路由规则的传入
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
暴露
export default router
4.注入路由 mian。js中注入
import Vue from 'vue'
import App from './App.vue'
import router from './router' 引用路由
Vue.config.productionTip = false
new Vue({
router,注入路由
render: h => h(App)
}).$mount('#app')
在创建vue脚手架项目的时候 我们一定要选中router项
在项目创建好之后 会发现项目src文件夹下多了两个文件夹
views ------》页面文件夹
router -----》就是用来配置路由的
1.删除components与views文件夹下的.vue文件
2.在app.vue中删除
1.在views下创建对应页面
2.配置路由页面规则–router下的index.js中进行配置
import Vue from 'vue'
import VueRouter from 'vue-router'
// 1.引用路由页面到路由规则配置文件中
import Home from '../views/home.vue'
import Gouwu from '../views/gouwu.vue'
import Jingxi from '../views/jingxi.vue'
import Fenlei from '../views/fenlei.vue'
import Wode from '../views/wode.vue'
// 在vue中使用路由功能
Vue.use(VueRouter)
// 2、配置路由规则
const routes = [
{
path: '/',//url路径
name: 'Home',//给当前的规则起个名字
component: Home //你匹配的路由页面
},
{
path: '/gouwu',//url路径
name: 'gouwu',//给当前的规则起个名字
component: Gouwu //你匹配的路由页面
},
{
path: '/fenlei',//url路径
name: 'fenlei',//给当前的规则起个名字
component: Fenlei //你匹配的路由页面
},
{
path: '/jingxi',//url路径
name: 'jingxi',//给当前的规则起个名字
component: Jingxi //你匹配的路由页面
},
{
path: '/wode',//url路径
name: 'wode',//给当前的规则起个名字
component: Wode //你匹配的路由页面
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
3.设置路由出口 在app.vue中 使用router-view来进行标识
router-link 来进行页面的切换 其中to属性来设置跳转地址
在vue路由导航中 会默认给我们选中的当前导航添加样式类 router-link-active
如果在配置路由的时候 路由规则的path中 只有一个单独的/ 那么无论选没有选中当前的这个路由 都会添加上述的类名 为了解决 所以我们在配置路由的时候 path中不能设置单独的/
但是如果我们吧路由规则的path在设置的时候 没有设置单独的/ 那么第一次进入页面的时候就没有默认路由规则 也就没有默认的首页 解决方式使用重定向
this.$router.push("/去哪里")
404页面
this.$router.replace("/去哪里")
this.$router.go() 正数 前进 负数回退
重新定位方向 可以在第一次进入页面的时候帮助用户自动把页面进行指定位置的切换
const routes = [
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/shop',
name: 'shop',
component: Shop
},
{
path: '/phone',
name: 'phone',
component: Phone
},
{
path: '/user',
name: 'user',
component: User
},
// 重定向
{
path:"/",
// 重新定位方向
redirect:"/home"
}
]
当url中出现了我们没有配置过的路由页面 就会出现白屏
为了解决 我们需要给用户在url中没有我们配置过路由的情况下 做出一个页面没有找到的提示
配置的方式和船舰路由一样 唯一的区别就是在path配置的时候使用通配符
const routes = [
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/shop',
name: 'shop',
component: Shop
},
{
path: '/phone',
name: 'phone',
component: Phone
},
{
path: '/user',
name: 'user',
component: User
},
// 重定向
{
path:"/",
// 重新定位方向
redirect:"/home"
},
// 404页面必须在路由规则的最最最下面 就算有重定向也要在他下面
// 404页面必须在路由规则的最最最下面 就算有重定向也要在他下面
// 404页面必须在路由规则的最最最下面 就算有重定向也要在他下面
// 404页面必须在路由规则的最最最下面 就算有重定向也要在他下面
// 404页面必须在路由规则的最最最下面 就算有重定向也要在他下面
{
path: '*',
name: 'no',
component: No
}
]
在一个路由中嵌套另外一个路由 那么就是多级路由
多级路由创建方式和一级路由过程一样 只是在配置路由规则的时候有所不同
使用children关键字来进行配置
1.在views下新建 二级路由页面
2.配置路由规则
(2-1)在router下的index.js中先引用二级路由页面
(2-2)确定是哪个一级路由的子路由 然后就在对应的一级路由中添加children配置二级路由
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/home.vue'
import Sj from '../views/shiji.vue'
import Syy from '../views/shuyingyin.vue'
import Wode from '../views/wode.vue'
import Xz from '../views/xiaozu.vue'
// 1.引用二级路由页面
import Era from "@/views/er/era.vue"
import Erc from "@/views/er/erc.vue"
import Erd from "@/views/er/erd.vue"
import Ere from "@/views/er/ere.vue"
Vue.use(VueRouter)
const routes = [
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/sj',
name: 'Sj',
component: Sj
},
{
path: '/syy',
name: 'Syy',
component: Syy,
// 2.二级路由配置
children:[
{
path: '/era',
name: 'Era',
component: Era
},
{
path: '/erc',
name: 'Erc',
component: Erc
},
{
path: '/erd',
name: 'Erd',
component: Erd
},
{
path: '/ere',
name: 'Ere',
component: Ere
},
]
},
{
path: '/wode',
name: 'Wode',
component: Wode
},
{
path: '/xz',
name: 'Xz',
component: Xz
},
{
path:"/",
redirect:"/home"
}
// {
// path: '/about',
// name: 'About',
// // route level code-splitting
// // this generates a separate chunk (about.[hash].js) for this route
// // which is lazy-loaded when the route is visited.
// component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
// }
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
3.各位大哥大姐千万不要忘了 配置二级路由的出口
3.各位大哥大姐千万不要忘了 配置二级路由的出口
3.各位大哥大姐千万不要忘了 配置二级路由的出口
3.各位大哥大姐千万不要忘了 配置二级路由的出口
3.各位大哥大姐千万不要忘了 配置二级路由的出口
3.各位大哥大姐千万不要忘了 配置二级路由的出口
3.各位大哥大姐千万不要忘了 配置二级路由的出口
router-view
路由出口写在 对应一级路由的页面中
书影音
4.设置路由导航
(4-1)如果多级路由在配置规则的时候 path带/ path:"/xxx" 那么 路由导航就to属性就是 /xxx
{
path: '/era',//path带/斜杠
name: 'Era',
component: Era
},
路由导航
era
(4-2)如果多级路由在配置规则的时候 path不不不不不不带/ path:“xxx” 那么 路由导航就to属性就是 /一级路由/二级路由
{
path: 'era', //path不带/
name: 'Era',
component: Era
},
路由导航
era
在vue设置路由的时候有两种模式 hash history
使用mode来进行设置
mode: 'history',
区别 | hash(默认值) | history |
---|---|---|
url展示上 | url带# | url不带# |
兼容性 | 支持低版本浏览器 | 是HTML5新增的所以不兼容低版本浏览器 |
刷新页面(上线之后) | 刷新正常 | 刷新页面会丢失 |
在开发app分享页面的时候 有可能这个页面就是vue写的 在嵌入到第三方原生app的时候 有的app对url是有要求的 不能带#
把数据从一个路由页面传递到另外一个页面的技术
1.在路由规则中设置接收参数(谁接收数据 就在谁的路由规则中设置)
{
path: '/xz/:xiaoming',//接收数据的规则上设置接收参数
name: 'Xz',
component: Xz
},
2.发送数据
this.$router.push({name:“你要跳转的路由规则的name”,params:{你配置的接收参数:“数据”}})
fun(id){
console.log(id)
// 传递数据
// this.$router.push({name:"你要跳转的路由规则的name",params:{你配置的接收参数:"数据"}})
this.$router.push({name:"Xz",params:{xiaoming:id}})
}
3.接收数据 this.$route.params.xxx
<h1>{{this.$route.params.xiaoming}}h1>
1.发送数据
this.$router.push({name:“你要跳转的路由规则的name”,query:{接收参数:“数据”}})
this.$router.push({path:“你要跳转的路由的路径”,query:{接收参数:“数据”}})
// 使用query方式进行传参
this.$router.push({name:"Sj",query:{xiaohong:"我是query传参"}})
2.接收数据
this.$route.query.xxx
1.用法上:
query方式可以使用path也可以使用name作为跳转路径 params只能用name
接收上query使用this. r o u t e . q u e r y . x x x x 而 p a r a m s 使 用 t h i s . route.query.xxxx 而params使用this. route.query.xxxx而params使用this.route.params.xxxx
2.url 展示上是不同的
query 是 key=val query显示key相对来说不安全
params url只有val 不显示key 相对来说安全一些
$router : 他是vueRouter的全局对象 它里面包含了对路由全局操作的属性和方法
$route: 就是一个路由对象 每一个路由都有一个route对象 也就是说他是类似于局部页面路由的一个对象他只能处理当前路由页面的操作
懒加载简单来说 就是按需加载 在想使用的时候进行加载
就是给使用者 更好的用户体验 路由的项目可能会出现首页白屏问题
路由是完成spa单页面应用的一个技术 就是项目中之后一个页面 然后如果用户需要切换页面显示的话 是在当前页面对整体内容进行一个替换
项目在第一次加载的时候 会把全部页面都先加载 然后在把指定要显示的显示出来 可能页面过多 导致加载事件过长 那么用户所看到的就是白屏
路由懒加载 分为两种 : vue异步组件的方式 第二种 就是es中import的方式
异步组件方式:
component: (resolve) => require(['你要引用的路由页面路径'], resolve)
import 的方式:
component: () => import('你要引用的路由页面路径')
路由切换的时候被自动调用的函数
使用场景: vue项目中进行所在路由页面切换的时候 进行一些项目的验证 比如 用户的登录状态验证 就需要在每次页面切换的时候进行状态的验证(自动执行的)
无论是哪个路由 在切换的时候都会触发这个钩子函数
设置在router文件夹下的index.js中 写在实例化路由对象之后
在准备切换路由的时候触发
// 全局前置守卫
// router.beforeEach((to去哪里,from从哪里来,next下一步)=>{})
router.beforeEach((to,from,next)=>{
console.log("to",to)
console.log("from",from)
if(to.path=="/about"){
next()
}else{
alert("您没有登录请您登录后在试!!!")
next("/about")
}
})
进入到路由的时候生效
// 全局后置守卫
// router.afterEach((to从哪来,from去哪里)=>{})
router.afterEach((to,from)=>{
console.log("to",to)
console.log("from",from)
})
相对于全局守卫来说 独有独享 仅仅只对一个路由页面生效
router下的index.js中 钩子函数写在指定你要设置守卫的路由配置中 与path name component同级
{
path: '/phone',
name: 'phone',
component: () => import( '../views/phone.vue'),
// 路由独享守卫
beforeEnter(to,from,next){
console.log(to)
console.log(from)
// 进行一些是否登录的判断判断成功让她进入 不成功不能进
alert("当前页面是vip页面")
next("/about")//不让下一步
}
},
写在指定的.vue文件中
组件内守卫
我们开发者可以在路由中自己添加一些数据 方便页面使用
{
path: 'erf',
name: 'erf',
component: () => import( '../views/er/erf.vue'),
meta:{
title:"账号权限"
}
},
this.$router.options.routes
mixin是vue组件复用功能的技术之一 他可以把多个组件中重复出现的属性和方法进行封装方便多次调用
1.混入就是把组件多次使用的属性和方法等内容进行封装
新建一个mixin的文件夹用来容纳混入的封装
export let demo={
methods:{
fun(){
console.log("你好!!!!!!")
}
},
data(){
return {
}
},
computed:{
}
}
慎用可能会造成代码的污染、
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 1.引用mixin
import {demo} from "./mixins"
// 2.配置全局混入
Vue.mixin(demo)
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
This is an about page
生命周期 vue实例从创建到销毁的过程
钩子函数 就是在特定阶段内被自动调用的函数
就是给我们开发者在程序的不同阶段提供一个自动执行程序(逻辑)的场所
8个钩子函数 4组 (实例创建 模板渲染 数据更新 实例销毁)
beforeCreate 实例准备创建
created 实例创建完毕 在vue实例new穿件完毕之后立即调用 但是这个时候 只是把vue实例出来了 实例中的data methods等属性还没有开始处理
beforeMount 模板准备渲染
mounted 页面加载完毕之后立即调用 页面已经显示了 vue实例中的内容也已经处理完了
beforeUpdate 开始准备更新
updated 更新完毕
beforeDestroy 开始准备销毁
Destroyed 销毁完毕
1.生命周期在页面初次加载的时候执行什么?
前两组 分别为 实例创建前后 (英文带上) 模板创建前后(英文带上)
2.生命周期的作用是什么?
vue实例从创建到销毁的过程中在特定阶段内被自动调用的函数同时给我们开发者在程序的不同阶段提供一个自动执行程序(逻辑)的场所
3.vue生命周期一共几个阶段?
4大阶段 8个钩子
4.请您简述vue生命周期的各个钩子函数
beforeCreate 实例准备创建 (数据观测与初始化事件还没有执行)
created 实例创建完毕 (完成了数据的观测 属性 方法也都进行了初始化 但是页面没有显示渲染)
beforeMount 模板准备渲染 (在准备把template模板往页面中进行挂在 准备编译页面内容)
mounted 页面加载完毕之后立即调用 (页面被成功的进行了挂载 页面的dom内容也都生成完毕)
beforeUpdate 开始准备更新(在数据准备更新的时候调用 此时还处于数据构建更新的准备阶段)
updated 更新完毕 (数据已经成功的在页面dom中更新完毕了)
beforeDestroy 开始准备销毁(vue实例还能用)
Destroyed 销毁完毕
5.vue数据请求应该在那个钩子函数中进行调用 为什么?
在created和mounted中都可以
但是 如果要涉及请求完毕操纵dom的时候 那么必须在mounted中进行数据请求
在不改变原始数据的情况下 格式化展示数据
1.写在与data methods的同级位置
filters:{
过滤器的名字( 你操纵的数据 ){
return 你的逻辑
}
}
export default {
props:["datalist"],
// 过滤器
filters:{
xiaoming(val){
if(val.length>6){
return val.substr(0,5)+".."
}else{
return val
}
}
}
}
使用过滤器 只需要在你想使用的数据后面使用 |过滤器的名字
在项目的根路径下创建一个vue.config.js的文件
module.exports={
devServer:{
open:true
},
// 配置引用别名
configureWebpack:{
resolve:{
alias:{
// 别名:真实路径
"niubi":"@/utils"
}
}
}
}
给多个组件使用同一个挂载点并且动态切换(多个组件每次只显示一个并且动态的进行切换)
语法:
在页面想显示我们多个组件的时候会用下面的语法 来声明挂载点
phone
在动态组件中如果有多个输入框 那么我们在切换动态组件的时候会发现这些驶入框的内容会丢失
在多个路由页面中如果有多个输入框 那么我们在切换路由页面的时候会发现这些驶入框的内容也会丢失
我们在路由或者是动态组件切换的时候因为 每次切换vue都会出现一个新的vue组件实例 所以会丢失
keep-alive 可以在keep-alive包裹的内容 在切换的时候把数据状态保存在内存中 防止重复的DOM渲染 减少了性能与时间上的损耗
用在动态组件之上
用在路由之上 只需包裹路由的出口
include 你想缓存谁
可以写多个 中间用逗号隔开
exclude 你不想缓存谁
有两个钩子函数 但是在写的时候一定要在被keep-alive所管理的组件中进行使用
activated 进入到被keep-alive管理的组件时候触发
deactivated 离开被keep-alive管理的组件时候触发
activated(){
console.log("进入到keep-alive管理的组件了")
},
deactivated(){
console.log("离开了keep-alive管理的组件了")
}
你有没有遇见过 vue数据改变页面没有改变(没有更新)的情况
问题所在: 当vue的data中的数据(对象和数组)在初始化完毕之后 再向其中插入新的属性的时候 那么这时数据发生改变 但是页面视图不会更新
vue数据变视图不会改变-----$set
{{ obj.name }}--{{obj.age}}
在vue2.0中双向绑定使用的是数据劫持Object.defineProerty() 但是Object.defineProerty() 只会监听初始化的数据 如果初始化完毕了 数据在新增新的内容 Object.defineProerty() 就监听不到 监听不到就没有数据劫持 没有数据劫持就没有双向绑定 所以 数据变了视图也不会改变
我就是想中途添加一个新属性并且数据变视图也要改变怎么办?
语法: this.$set(“你要修改谁”,“你要新增的key”,“你要新增的val”)
就是在vue中进行dom操作
user
在现有的指令不够用的时候 有我们自己来创建指令
语法:
写在与data methods同级
directives:{
自定义指令的名字:{
自定义指令的钩子函数( el 你绑定的自定义指令所在的dom元素 ){
你的操纵逻辑
}
}
}
bind : 绑定指令到元素上 只执行一次;
inserted : 绑定了指令的元素在插入页面展示的时候调用
update: 所有节点更新的时候调用
componentUpdate: 指令所在组件的节点以及他自己所有的子节点全部更新了 在调用
unbind: 接触指令和元素的绑定时候调用 只执行一次
directives:{//自定义指令
xiaoming:{//自定义指令的名字随便起
inserted(el){
el.style.color="red";
}
}
},
v-自定义指令的名字
This is an about page
vue项目在日常开发运行ing的时候 我们使用的是内置的微型开发服务器devServer 但是我们的项目今后是要到公网服务器上面进行运行的 所以那个微型开发服务器就不足以支撑我们今后的项目运行了 那么我们就需要把项目放到更厉害的服务器上面 在这个时候 我们所写的vue项目文件是.vue结尾的 浏览器不认识 所以我们需要把当前项目进行打包 打包成浏览器可以直接认识的文件 然后再用这个更厉害的服务器运行
流程:
1.基础命令:npm run build
build之后运行打包的dist文件夹下的index.html的时候 会发现页面什么都没有 并且console中有很多的404错误 我们打包之后静态资源文件路径有问题 所以我们需要修改
2.修改静态资源路径 publicPath:"./" 去vue.config.js中进行修改
3.在吧路由模式进行hash的切换
打包安卓ios
hbuilderx 选择文件 —》新建----》项目 ----》h5+app
1.在项目下下载所需要的依赖
sass-loader node-sass
npm install --save sass-loader@10 node-sass@6
2.在写样式的时候需要指定文件类型
详见git文档
node 是一个基于chrome浏览器js解析器(v8)的一个javascript运行环境
可以让js在脱离浏览器的情况下进行单独的运行
单线程
非阻塞式io (io输入输出)
事件驱动
node的一个企业级应用框架简化了我们在创建http服务的时候复杂度
使用:
1.npm install --save express
2.创建后台服务
// 1.引用express
let express=require("express");
// 2.初始化express对象
let app=express()
// 3.创建服务
// req 请求
// res 相应
app.get("/xiaoming/xiaohong",(req,res)=>{
res.send({msg:"我是一个后台服务"})
})
// 4.监听端口
app.listen(8888)
如果后台有很多个接口我应该怎么创建
let express=require("express");
let app=express()
app.get("/xiaoming/xiaohong",(req,res)=>{
res.send({msg:"我是一个后台服务"})
})
// 如果有多个接口
app.get("/xiaoming/xiaohua",(req,res)=>{
res.send({msg:"我是第二个"})
})
app.get("/xiaoming/xiaohei",(req,res)=>{
res.send({msg:"我是第三个"})
})
app.listen(8888)
非关系型数据库(NoSql数据库 not only sql不仅仅是sql) Mongodb Redis
关系型数据库: MySql Oracle SQL Server BD2
关系型和非关系型数据库区别
非关系型数据库非常的快 稳定性不够(没有一个正式的官方支持)由于比较新 所以支持的特性还不够扩展性不够
1.npm`安装Mongoose: npm install --save mongoose@5
2.在项目下新建db.js文件用来封装数据库连接内容
// 封装数据库连接的模块
// 1.引用mongoose
let mongoose=require("mongoose")
// 2.设置连接
mongoose.connect("mongodb://localhost:27017/xiaoming")//xiaoming是你设置的数据库
// 3.开始连接
var db = mongoose.connection;
// 4.设置错误的时候信息和连接成功的信息
db.on('error', console.error.bind(console, '连接错误'));
db.once('open', function() {
console.log("连接ok")
});
// 5.暴漏
module.exports=db
3.在你创建的随笔一个后台路由中引用db文件 并且调用
let express=require("express");
let app=express()
// 引用数据库连接模块
let db=require("./db")
app.get("/xiaoming/xiaohong",(req,res)=>{
// 调用数据库连接模块
db
res.send({msg:"我是一个后台服务"})
})
// 如果有多个接口
app.get("/xiaoming/xiaohua",(req,res)=>{
res.send({msg:"我是第二个"})
})
app.get("/xiaoming/xiaohei",(req,res)=>{
res.send({msg:"我是第三个"})
})
app.listen(8888)
但是运行的时候有设置连接模式的警告
(node:11436) DeprecationWarning: current URL string parser is deprecated, and will be removed in a future version. To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect.
(Use `node --trace-deprecation ...` to show where the warning was created)
(node:11436) [MONGODB DRIVER] Warning: Current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
所以我们可以根据提示配置连接模式
// 封装数据库连接的模块
// 1.引用mongoose
let mongoose=require("mongoose")
// 2.设置连接 设置连接模式
mongoose.connect("mongodb://localhost:27017/xiaoming",{ useNewUrlParser: true,useUnifiedTopology: true })//xiaoming是你设置的数据库
// 3.开始连接
var db = mongoose.connection;
// 4.设置错误的时候信息和连接成功的信息
db.on('error', console.error.bind(console, '连接错误'));
db.once('open', function() {
console.log("连接ok")
});
// 5.暴漏
module.exports=db
Element,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库
下载 npm i element-ui@2 -S
2 在 main.js 中写入以下内容:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
在调用接口的时候使用postman先来进行下接口是否正确的测试
接收前台的get请求数据 使用 req.query.xxxx
是一个规范 定义接口的名字或者是使用上的内容
get 方式 获取数据
post方式 发送数据
delete方式 删除数据
put方式或者patch方式 修改更新数据
能加密也能解密的字符串(通常是用来保存用户的登录状态)
使用jsonwebtoken 库来实现token
npm install --save jsonwebtoken
1.加密 -------sign()
sign( 你要加密的数据,密钥)
密钥:我们自己定义一段越乱越好的乱码
2.解密—verify()
verify( 你要解密的数据, 密钥(必须和你加密时候的密钥相同) ,回调函数 )
1.用户在登录成功之后 生成一个token 并且一并返回给前台
2.前台得到这个token存起来(本地存储 cookice)
3.每次页面切换或者是需要这个知道用户是否登录的时候 我们就把这个token取出来 并且发送给后台 后台会有一个专门解密这个token的接口来判断用户是否登录过
4.把用户是否登录告诉前台 从而我们做出对应的反应
react起源于Facebook的内部项目 facebook觉得市场上所有的js看框架都不满意 所以自己写了一套 用于instagram网站 他在做出来以后 发现很好用 在13年5年开源了
react不是一个MVC框架 最多你可以认为是一个MVC中的V层 react并不非常的认可MVC这种开发模式 react构建用户界面可以简单的理解为他就是一个组件话的框架 来完成页面
1.声明式设计
2.高效
3.灵活 可以非常方便的与第三方进行整合
4.jsx的支持
5.组件化
6单向数据流
近期cra更新了 它里面对node的版本有要求 不能低于14版本
但是win7最高只能支持到12
1.全部安装
npm install -g create-react-app
2.查看版本
create-react-app --version
3.cd到指定文件夹下
4新建项目 create-react-app 项目名
在等待创建项目的时候实质上这个过程会安装三个主要的内容
react库:react的核心文件
react-dom库: 因为react有很多的运行环境 比如react就有手机端的react-native 但是我们现在下载的是web端 所以我们需要下载react-dom库来支持web端
react-scripts 包含了react的运行于打包程序的配置库
babel库:翻译器啊浏览器不认识的翻译成认识的
5.cd到项目名下
6npm start 启动
把cmd的默认镜像切换成淘宝镜像 npm config set registry https:``//registry.npm.taobao.org/
yarn(facebook出品)和npm一样都是包管理工具 只是两个厂家出的不同产品
yarn 安装 npm install -g yarn
yarn 切换淘宝镜像 yarn config set registry https://registry.npm.taobao.org/
功能 | npm | yarn |
---|---|---|
初始化 | npm init | yarn init |
安装依赖 | npm install | yarn install 或者 yarn |
添加依赖 | npm install --save xxx | yarn add xxx |
全局安装 | npm install -g xxx | yarn global add xxx |
安装多个依赖 | npm install --save xx1 xx2 | yarn add xx1 xx2 |
删除依赖 | npm uninstall --save xxx | yarn remove xxx |
把src下的所有内容删除了
新建index.js写入如下内容
// 1.引用react
import React from "react"
// 2引用dom库
import ReactDom from "react-dom"
// 3.reactdom库中有一个render的渲染方法 他可以来构建页面内容 渲染内容
ReactDom.render(
你好么么哒
,document.getElementById("root")
)
JSX----javascript and XML 是一个语法要求非常严谨的一个语法扩展 在reacr中使用jsx语法对页面的内容部分进行描述
在实际开发中 jsx在编译阶段会被babel编译成js 让我们的代码会更加便于维护
jsx遇见<回当html解析 遇见{}当js解析
就是把页面ui拆分成一个个独立的并且可以重复使用的部件 把这些部件拼接在一起 就会形成一个页面
1.函数组件在创建的时候组件名必须首字母大写 件名必须首字母大写 件名必须首字母大写
2.首先是一个函数 在其中return一段jsx
// 函数组件名首字母大写
let Fun=()=>{
// return 一段jsx
return (
你好么么哒1
你好么么哒2
你好么么哒3
你好么么哒4
你好么么哒5
)
}
// 暴露
export default Fun
ES6的class来定义一个组件的方式 类组件在创建的时候需要使用类的继承 react.component 来进行组件的实现‘
类组件中必须有一个render渲染方法 并且在其中return jsx
import React from "react"
// 创建类组件
class Two extends React.Component{
render(){//渲染
return (
我是类组件1
我是类组件2
我是类组件3
我是类组件4
我是类组件5
我是类组件6
)
}
}
export default Two
可以安装插件 输入rcc快捷键生成代码
组件中插入变量使用的都是jsx的语法 {} 来进行插入的
let Fun=()=>{
let text="我是一个变量";
return (
你好么么哒1---{text}
)
}
export default Fun
import React, { Component } from 'react'
let text="我是一个变量么么哒!!!!!"
export default class two extends Component {
render() {
return (
two---{text}
)
}
}
行内样式需要传递一个对象
同函数组件
let Fun=()=>{
return (
{/* 行内样式 */}
{/* 行内样式需要传递一个对象进入 所以 外面的{}是jsx的解析语法
里面的{}是对象的写法
多个单词把-去掉 变大写
*/}
你好么么哒1
)
}
export default Fun
在react中给dom元素起类名 不能用class属性 因为class是es6的关键字 把class变成className
同下面的类组件写法
使用import 来引用css
import React, { Component } from 'react'
// 引用css 使用import
import "./two.css"
export default class two extends Component {
render() {
return (
{/* 在组件中起名字使用className来继续 */}
我是类组件
)
}
}
下载 npm install --save sass-loader@10 node-sass@6
直接编写scss文件 然后在需要使用的组件内 使用 import “你的样式文件路径即可”
空标签是 有一个包裹的作用 在一些特殊情况下 为了不生成无用的代码 所以我们可以使用
1.<>> 空标签
import React, { Component } from 'react'
export default class demo extends Component {
render() {
return (
// 空标签
<>
<h1>空标签1</h1>
<h1>空标签2</h1>
<h1>空标签3</h1>
<h1>空标签4</h1>
<h1>空标签5</h1>
<h1>空标签6</h1>
</>
)
}
}
import React, { Component } from 'react'
export default class demo extends Component {
render() {
return (
// 空标签
空标签1
空标签2
空标签3
空标签4
空标签5
空标签6
)
}
}
在react属性插入变量 使用的还是{} 属性={ 变量}
let Fun=()=>{
let text="点我去百度";
let ahref="http://www.baidu.com";
return (
<>
属性插变量
{text}
>
)
}
export default Fun
react推荐使用map方法来进行数据的便利
import React, { Component } from 'react'
let arr = [111, 222, 333, 444, 555, 666, 777];
export default class democ extends Component {
render() {
return (
便利数据
{
arr.map((v,i)=>{
return (
- {v}
)
})
}
)
}
}
便利复杂数据
import React, { Component } from 'react'
let arr = [111, 222, 333, 444, 555, 666, 777];
let obj=[
{name:"xix1i",age:181},
{name:"xix2i",age:182},
{name:"xix3i",age:183},
{name:"xix4i",age:184},
{name:"xix5i",age:185},
{name:"xix6i",age:186}
]
export default class democ extends Component {
render() {
return (
便利数据
{
arr.map((v,i)=>{
return (
- {v}
)
})
}
{
obj.map((v,i)=>{
return (
{v.name}
{v.age}
)
})
}
)
}
}
事件绑定 使用小驼峰命名法 鼠标左键点击事件 onclick------》onClick onchange------》onChange
import React, { Component } from 'react'
export default class one extends Component {
// 创建函数
fun=()=>{
alert("你好")
}
render() {
return (
我是类组件的事件使用
{/* 事件要用小驼峰 函数不加() */}
)
}
}
import React from "react"
let xiaoming=()=>{
alert("函数组件")
}
let Fun=()=>{
return (
函数组件使用事件
)
}
export default Fun
上面的代码大家发现函数在调用的时候没有() 没有()的话我们实参写在那?
import React from "react"
// 定义形参
let xiaoming=(num)=>{
alert("函数组件"+num)
}
let Fun=()=>{
return (
函数组件使用事件
{/* 通过bind传递实参 */}
)
}
export default Fun
2.使用箭头函数调用函数的方式
import React, { Component } from 'react'
export default class one extends Component {
// 创建函数
fun=(num)=>{
alert("你好"+num)
}
render() {
return (
我是类组件的事件使用
{/* 事件要用小驼峰 函数不加() */}
{/* */}
{/* 使用箭头函数调用函数传递函数的实参 */}
)
}
}
函数组件不能使用ref
进行dom操纵的
import React, { Component } from 'react'
export default class demoe extends Component {
fun=()=>{
// 使用
console.log(this.demoinput.value)
}
render() {
return (
ref的使用
{/* {创建一个变量=形参}} /> */}
{this.demoinput=el}} />
)
}
}
import React, { Component } from 'react'
export default class demof extends Component {
// 1.创建出ref
inputref=React.createRef()
fun=()=>{
// 3.使用
console.log(this.inputref.current.value)
}
render() {
return (
{/* 2.绑定 */}
)
}
}
在vue中插入字符串标签使用v-html这个指令即可完成
在今后实际工作的时候 会出现后台给你返回的就是一大段生成好的html 你需要把他展示在页面上
import React, { Component } from 'react'
export default class demod extends Component {
state={
newhtml:"我是h1我是一段字符串标签
"
}
render() {
return (
demod
{/* 插入字符串标签 */}
)
}
}
子组件
// 1.把props当成函数的形参传入
let Zi=(props)=>{
return (
<div>
{/* 2.使用props来进行数据的展示 */}
ziziziziziziz--{props.title}
</div>
)
}
export default Zi
父组件进行传递
import Zi from "./zi.jsx"
let Fu=()=>{
return (
FFUFUFUFUFUFUF
{/* 父组件传递 */}
)
}
export default Fu
公司的写法
import Zi from "./zi.jsx"
let Fu=()=>{
// 定义数据
let obj={
title:"你好么么哒!!!!!"
}
return (
FFUFUFUFUFUFUF
{/* 父组件使用扩展运符传递 */}
)
}
export default Fu
1.子组件 this.props.xxx
import React, { Component } from 'react'
export default class zi extends Component {
render() {
return (
zi
{/* 1.子组件定义props */}
父组件的数据式-----{this.props.title}
)
}
}
2.父组件传递
import React, { Component } from 'react'
import Zi from "./zi.jsx"
export default class fu extends Component {
render() {
return (
fu
{/* 父组件给子组件传递数据 */}
)
}
}
公司写法
子组件中使用结构来优化代码
import React, { Component } from 'react'
export default class zi extends Component {
render() {
// 使用解构的方式见到了this。props的重复出现率
let {title,age,name,sex,love}=this.props
return (
zi
{/* 1.子组件定义props */}
父组件的数据式-----{title}
父组件的数据式-----{age}
父组件的数据式-----{name}
父组件的数据式-----{sex}
父组件的数据式-----{love}
)
}
}
父组件使用扩展运算符传递数据
import React, { Component } from 'react'
import Zi from "./zi.jsx"
export default class fu extends Component {
render() {
let obj={
title:"我是title",
name:"我是name",
age:18,
sex:"男",
love:"女"
}
return (
fu
{/* 扩展运算符快速传递数据 */}
)
}
}
子组件把数据给父组件
子组件
import React, { Component } from 'react'
export default class zi extends Component {
render() {
return (
zizizizzizi
{/* 1.逆向传值必须通过事件来触发 一个父组件传递过来的函数*/}
)
}
}
父组件
import React, { Component } from 'react'
import Zi from "./zi.jsx"
export default class fu extends Component {
fufun=()=>{
}
render() {
return (
fuffufufufuf
{/* 2.父组件给子组件传递一个函数 */}
)
}
}
子组件
import React, { Component } from 'react'
export default class zi extends Component {
render() {
return (
zizizizzizi
{/* 1.逆向传值必须通过事件来触发 一个父组件传递过来的函数*/}
{/* 3.给函数进行实参的传递 */}
)
}
}
父组件
import React, { Component } from 'react'
import Zi from "./zi.jsx"
export default class fu extends Component {
// 4.父组件设置形参接收子组件绑定的实参
fufun=(text)=>{
console.log("我是父组件的函数",text)
}
render() {
return (
fuffufufufuf
{/* 2.父组件给子组件传递一个函数 */}
)
}
}
react中默认是不能进行同胞传值的 如果我们要进行 那么必须依赖 pubsub-js(是-js 千万不要记错了)库来实现
1.npm install --save pubsub-js
2.抛出 在需要传递的组件中使用 Pubsub.publish(“自定义事件名”,“数据”) publish创建自定义事件
import React, { Component } from 'react'
// 1.引用pubsub-js
import Pubsub from "pubsub-js"
export default class zia extends Component {
fun=()=>{
// 2.publish抛出自定义事件
Pubsub.publish("zia","我是zia的数据么么哒!!!!!")
}
render() {
return (
zia
)
}
}
3.接收 在需要接收数据的组件中使用Pubsub.subscribe(“你监听的事件”,()=>{})subscribe 监听自定义事件
import React, { Component } from 'react'
// 3.引用pubsub
import Pubsub from "pubsub-js"
export default class zib extends Component {
constructor(){
super()
console.log("1.react初始化数据")
}
componentWillMount(){
console.log("2.在渲染之前调用")
}
componentDidMount() {
// 接收 监听同胞传值的自定义事件
// 回调函数的第一个形参是你监听的自定义事件的名字
// 回调函数的第二个形参就是自定义事件上绑定的数据
Pubsub.subscribe("zia",(a,b)=>{
console.log(a)
console.log(b)
})
}
render() {
console.log("3开始渲染")
return (
zib
)
}
}
因为你们要面试 所以必须知道
状态提升 多个组件像反应相同的数据变化 那么这个时候 我们可以在需要反映相同数据变化的组件之上去寻找他们最近的父组件 在把这个数据放到这个父组件之上 在通过props进行传递
react中组件之间的数据传递是通过props来进行单向传递的 父组件一层一层的向下进行传递传递到子子孙孙 有的时候我们传值的层级比较多的时候那么这种方式就很麻烦 所以我们就可以使用下面的context/redux来进行跨层级的传值
context可以很方便的进行跨层级组件之间的数据通信
使用createContext这个方法来创建上下文对象
Provider 生产者-----》提供数据的
Consumer 消费者-----》使用数据的
1.要使用上下文对象createContext先把上下文对象创建出来
import React, { Component } from 'react'
// 1.引用createContext
// import {createContext} from "react"
// 2.创建出context对象
let context = React.createContext()
class Zi extends Component {
render() {
return (
Zi
{/* 3.在你想使用的地方用consumer来进行使用 */}
{/* 回调函数 回调函数的形参就是provider提供的数据 */}
{
(value)=>{
return (
{value.name}----{value.age}
)
}
}
)
}
}
class Fu extends Component {
render() {
return (
fu
)
}
}
export default class ye extends Component {
render() {
return (
// 使用provider来进行数据的提供 使用value属性来创建数据
ye
)
}
}
redux就是一个javascript的状态管理工具 可以集中的管理react中多个组件的状态 让我们组件之间数据传递变得非常的简单
redux是一个第三方的 也就是说他可以在react中用 也可以在vue中进行使用
如果组件需要进行跨层级传值 传统的方式 就是组件一层层的进行逆向传值传递到他们最近的一个父组件身上 然后再一层层的进行正向传值
1.单一数据源 :整个项目的数据都被存储在一个store对象中
2.state是只读的:如果我们想改变state的数据 那么必须触发action里面的修改动作来执行修改
3.使用纯函数来进行修改:reducer就是一个函数 我们通过reducer中的state和action动作来进行数据的修改
1.下载redux npm install --save redux
2.在项目的文件夹中创建一个store文件夹(容纳redux的代码)
3.在新建一个文件容纳基本代码
// 1.创建redux对象(先引用redux创建方法createStore)
import {createStore} from "redux"
// 6.创建创建state数据
let data={
name:"xixi",
age:18,
sex:"男"
}
// 5.创建reducer 是一个方法 其中保存的就是redux中存储的变量和修改变量的方法
// state就是数据状态
// action 修改上面数据状态的一些动作
// 7.把上面的数据传递给state
let reducer=(state=data,action)=>{
// 8把state return
return state
}
// 2.开始创建redux对象
// 4.把状态和修改状态的方法传递到初始化redux中
let store=createStore(reducer)
// 3.暴露redux对象
export default store
store.getState().你要读取的数据
import React, { Component } from 'react'
// 1.引用redux
import store from "../store/index.js"
export default class demoa extends Component {
// 2.把数据复制给组件的state中进行保存
state={
name:store.getState().name
}
render() {
return (
redux的基本使用
{/* 3.读取 */}
使用数据---{this.state.name}
)
}
}
我们需要通过dispatch()来调用写在action中的修改动作
千万不要和vuex搞混了 因为在vuex中 dispatch触发action是进行异步操纵的触发器
但是但是 在redux中 dispatch触发 的这个action里面存储的是修改状态的动作
fun=()=>{
// 通过dispatch来修改数据
// store.dispach({type:"你要触发的修改动作"})
store.dispach({type:"USER_UP_NAME"})
}
编写修改数据的动作
import {createStore} from "redux"
let data={
name:"xixi",
age:18,
sex:"男"
}
let reducer=(state=data,action)=>{
// 创建修改动作
switch (action.type) {
case "USER_UP_NAME":
console.log({...state,name:"我变了"})
return {...state,name:"我变了"}
break;
default:
return state
break;
}
}
let store=createStore(reducer)
export default store
但是大家运行后发现 数据修改了 但是页面并没有发生改变
原因很简单 因为 虽然你数据变了 但是组件中的render并没有重新执行 那么页面当然不会修改了
subscribe() 监听redux state的状态 改变就会触发
import React, { Component } from 'react'
// 1.引用redux
import store from "../store/index.js"
export default class demoa extends Component {
// 2.把数据复制给组件的state中进行保存
state={
name:store.getState().name
}
// 我们可以监控这redux中的state数据 如果redux中的数据改变了
// 我重启读取下并且在触发组件中的render那么 页面的内容就会改变
componentDidMount() {
store.subscribe(()=>{
// 当redux中的state数据改变了 那么subscribe就会触发
this.setState({
name:store.getState().name
})
})
}
fun=()=>{
// 通过dispatch来修改数据
// store.dispach({type:"你要触发的修改动作"})
store.dispatch({type:"USER_UP_NAME"})
}
render() {
return (
redux的基本使用
{/* 3.读取 */}
使用数据---{this.state.name}
)
}
}
随着项目的体积越来越大 项目的state和修改的动作也会越来越多
1.新建一个reducer.js(就是一个合并工厂 把今后拆分的一个个的小模块合并起来)
2.新建一个文件夹modules 里面放置我们拆分的一个个的小模块
3.开始拆分 把原来写在一起的state和原来写在一起的动作查分出来
// 里面存放的就是demoa的state数据和demoa的修改动作
let data={
name:"xixi",
}
let demoam=(state=data,action)=>{
// 创建修改动作
switch (action.type) {
case "USER_UP_NAME":
console.log({...state,name:"我变了"})
return {...state,name:"我变了"}
break;
default:
return state
break;
}
}
export default demoam
4.开始合并reducers.js中进行
// reducer合并工厂中吧modules文件夹中多个小模块进行合并
// 1.把你要合并的所有模块引用进来
import demoam from "./modules/demoam.js"
import demobm from "./modules/demobm.js"
// 2.引用合并模块的方法
import {combineReducers} from "redux"
// 3.开始合并
let reducer=combineReducers({
demoam,
demobm
})
// 4.暴露
export default reducer
5.把合并好的模块 注入到redux实例中
import {createStore} from "redux"
// 引用合并好的reducer
import reducer from "./reducers.js"
let store=createStore(reducer)
export default store
大家会发现 我们合并好模块之后 在页面不显示数据了 因为我们把内容都合并成了模块所以要使用的时候
store.getState().模块名.xxxx
react-redux 是一个专门为react开发的状态管理工具 而redux是第三方的
之前redux的写法 和react的耦合度太高 (在react中吧第三方的redux集成在项目里面 会造成代码的可读性太低)
react-redux 就可以简化我们在react中使用redux的复杂度
1.下载 npm install --save react-redux
2.我们需要在项目的全局组件之上 设置Provider 发布者
import React from 'react';
import ReactDOM from 'react-dom';
import App from "./components/demob.jsx"
// 1.引用provider
import { Provider } from "react-redux"
import store from "./store/index.js"
ReactDOM.render(
// 2.使用provider把redux对象传递到所有的子组件身上
// 3.传入store对象
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
2.设置组件与redux的连接
import React, { Component } from 'react'
// 1.引用react-redux给我们提供的连接方法
// connect是一个函数 当这个函数被调用的时候就是一个高阶组件
import {connect} from "react-redux"
class demob extends Component {
add=()=>{
}
del=()=>{
}
render() {
return (
demob
读取redux存储的age
)
}
}
// connect是一个函数 当这个函数被调用的时候就是一个高阶组件
// 第一个() 就是调用函数的语法
// 第二个() 就是高阶组件的语法
export default connect()(demob)
3.得到redux中的数据
import React, { Component } from 'react'
// 1.引用react-redux给我们提供的连接方法
// connect是一个函数 当这个函数被调用的时候就是一个高阶组件
import {connect} from "react-redux"
class demob extends Component {
add=()=>{
}
del=()=>{
}
render() {
return (
demob
{/* 使用react-redux读取数据 this.props.state.模块名.xxx */}
读取redux存储的age--{this.props.state.demobm.age}
)
}
}
// connect是一个函数 当这个函数被调用的时候就是一个高阶组件
// 第一个() 就是调用函数的语法
// 第二个() 就是高阶组件的语法
// 形参的state今后就是redux中的数据
export default connect(state=>({state}))(demob)
在组件中调用dispatch就可以直接完成修改操作
add=()=>{
// react-redux修改数据
// 还是使用dispatch触发action的动作
this.props.dispatch({type:"AGE_NUMBER_ADD_ONE",num:3})
}
1.挂载阶段
import React, { Component } from 'react'
export default class zib extends Component {
constructor(){
super()
console.log("1.react初始化数据")
}
componentWillMount(){
console.log("2.在渲染之前调用")
}
componentDidMount() {
console.log("4在渲染之后调用")
}
render() {
console.log("3开始渲染")
return (
zib
)
}
}
2.更新阶段
import React, { Component } from 'react'
export default class demog extends Component {
componentWillUpdate(){
console.log("开始准备更新")
}
componentDidUpdate() {
console.log("更新完成")
}
render() {
return (
demog
)
}
}
3.销毁阶段
componentWillUnmount(){
console.log("准备销毁")
}
思考
在react组件调用中我们的开标前和关标签中能否插入内容 ?
不能 因为组件是一个完整的独立的个体 默认不能插入
this.props.children 他表示所有组件的子节点(默认写上没有任何作用 在组件被调用的时候 如果我们在他的开关标签中插入dom元素 那么this.props.chilren 就会接收并且显示)
状态(变量/数据)机制 在react中我们只需要把数据定义在state中 那么数据改变了页面也会发生改变
函数组件也叫无状态组件 所以函数组件中不能使用状态 (react16.8新增了一个叫HOOK的技术可以实现现在听听就好)
函数组件也叫无状态组件 所以函数组件中不能使用状态
函数组件也叫无状态组件 所以函数组件中不能使用状态
函数组件也叫无状态组件 所以函数组件中不能使用状态
函数组件也叫无状态组件 所以函数组件中不能使用状态
1.定义状态数据
import React, { Component } from 'react'
export default class demob extends Component {
// 初始化state状态数据需要放到constructor中进行初始化
// es6中继承的规则中得知 子类是可以不写constructor 他会在实例化的时候
// 自动补充一个
// 但是如果你写了 那么必须在其中写super() 因为super就是调用父类的构造方法
// 此时子类才有this
constructor() {
super()
// 初始化state
this.state={
text:"我是字符串",
num:888,
bool:true,
arr:[1111,2222,333],
obj:{
name:"xixi"
}
}
}
render() {
return (
<>
我是测试state使用的例子
>
)
}
}
2.使用state数据
import React, { Component } from 'react'
export default class demob extends Component {
// 初始化state状态数据需要放到constructor中进行初始化
// es6中继承的规则中得知 子类是可以不写constructor 他会在实例化的时候
// 自动补充一个
// 但是如果你写了 那么必须在其中写super() 因为super就是调用父类的构造方法
// 此时子类才有this
constructor() {
super()
// 初始化state
this.state={
text:"我是字符串",
num:888,
bool:true,
arr:[1111,2222,333],
obj:{
name:"xixi"
}
}
}
render() {
return (
<>
{/* 2.使用state数据 */}
我是测试state使用的例子----{this.state.num}
>
)
}
}
3.修改state的数据
this.setState({你修改谁:修改成什么})
修改state的数据必须使用setState修改之后页面才会发生改变
import React, { Component } from 'react'
export default class demob extends Component {
// 初始化state状态数据需要放到constructor中进行初始化
// es6中继承的规则中得知 子类是可以不写constructor 他会在实例化的时候
// 自动补充一个
// 但是如果你写了 那么必须在其中写super() 因为super就是调用父类的构造方法
// 此时子类才有this
constructor() {
super()
// 初始化state
this.state={
text:"我是字符串",
num:888,
bool:true,
arr:[1111,2222,333],
obj:{
name:"xixi"
}
}
}
fun=()=>{
// 修改state的数据
this.setState({
num:123,
text:"xixi"
})
}
render() {
return (
<>
{/* 2.使用state数据 */}
我是测试state使用的例子----{this.state.num}---{this.state.text}
>
)
}
}
(如果有大量数据修改的话不会因为修改数据而造成程序的卡顿)
import React, { Component } from 'react'
export default class demob extends Component {
// 初始化state状态数据需要放到constructor中进行初始化
// es6中继承的规则中得知 子类是可以不写constructor 他会在实例化的时候
// 自动补充一个
// 但是如果你写了 那么必须在其中写super() 因为super就是调用父类的构造方法
// 此时子类才有this
constructor() {
super()
// 初始化state
this.state={
text:"我是字符串",
num:888,
bool:true,
arr:[1111,2222,333],
obj:{
name:"xixi"
}
}
}
fun=()=>{
// 修改state的数据
// this.setState({
// num:123,
// text:"xixi"
// })
// 下面的console.log打印的结果是修改之后的 还是修改之前的?
// 是修改之前的结果 所以从而证明了setState是一个异步任务
// console.log(this.state.num)
// 但是我就是想setState修改完数据之后 打印新的结果怎么办?
// 因为setState是异步 异步都会有回调函数
this.setState({
num:123,
text:"xixi"
},()=>{
// setState第二个参数是一个回调函数 当数据修改完他才会调用
console.log(this.state.num)
})
}
render() {
return (
<>
{/* 2.使用state数据 */}
我是测试state使用的例子----{this.state.num}---{this.state.text}
>
)
}
}
render就是渲染方法 只有render方法执行了 那么页面才会根据数据的改变而随之发生改变
render就是渲染方法 只有render方法执行了 那么页面才会根据数据的改变而随之发生改变
render就是渲染方法 只有render方法执行了 那么页面才会根据数据的改变而随之发生改变
render就是渲染方法 只有render方法执行了 那么页面才会根据数据的改变而随之发生改变
强制触发render渲染
import React, { Component } from 'react'
export default class demob extends Component {
constructor(){
super()
this.xiaoming="你好"
}
fun=()=>{
this.xiaoming="你坏"
console.log(this.xiaoming)
// 我们可以强制触发render重新渲染页面
this.forceUpdate()
}
render() {
return (
<>
强制刷新
{this.xiaoming}
>
)
}
}
在react16x之后componentWillMount会有一个问题 就是可能会被执行多次 所以最好不要在当前钩子中进行数据请求的发送
最好在componentDidMount中进行数据请求的发送
同vue
1.下载jquery npm install --save jquery
import React, { Component } from 'react'
// 1.引用
import $ from "jquery"
export default class democ extends Component {
componentDidMount(){
$.ajax({
url:"http://localhost:8888/one",
type:"GET",
success(ok){
console.log(ok)
}
})
}
render() {
return (
democ
)
}
}
fetch 最新的前后台异步数据交互的方式 传统的方式 axios或者是原生 jqueryajax 都是基于XMLHttpRequest方法来进行实现的 但是fetch不是因为Es最新规范中给我们提供了fetchAPI通过这个fetch
Api来进行前后台的数据交互
import React, { Component } from 'react'
export default class demob extends Component {
componentWillMount(){
console.log("will")
}
componentDidMount() {
console.log("did")
// fetch使用
fetch("http://localhost:8888/one")
// 把数据转换成json
.then(ok=>ok.json())
.then((ok)=>{
console.log(ok)
})
}
render() {
return (
demob
)
}
}
其他的方式
import React, { Component } from 'react'
export default class demob extends Component {
componentWillMount(){
console.log("will")
}
componentDidMount() {
console.log("did")
// fetch使用
fetch("http://localhost:8888/one")
// 把数据转换成json
.then(ok=>ok.json())
.then((ok)=>{
console.log(ok)
})
// 发送数据get
fetch("url/?key=val&key=val",{method:"GET"})
// 把数据转换成json
.then(ok=>ok.json())
.then((ok)=>{
console.log(ok)
})
// 发送post
fetch(
"url",{
method:"POST",
body:"key=val&key=val"
}
)
// 把数据转换成json
.then(ok=>ok.json())
.then((ok)=>{
console.log(ok)
})
}
render() {
return (
demob
)
}
}
1.传统的ajax 就是值使用XMLHttpRequest方法实现的数据请求 他隶属于原生的js 核心就是XMLHttpRequest对象 如果多个请求有先后顺序的话 那么容易造成回调地狱问题
jqueryajax 就是对原生XMLHttpRequest封装
2.axios 是基于promise封装的 本质上还是XMLHttpRequest的封装 只不过他是基于最新的语法进行封装的
3.fetch 就是原生js最新标准 和XMLHttpRequest没有半点关系
同vue一样也是对devServer进行代理跨域 但是唯一的不同的写跨域的文件不一样
需要到node_modules/react-scripts/config/webpackDevServer.config.js中进行配置
找到proxy 进行设置
但是不要忘了修改请求的地址为/api 与重启项目
在项目中用来进行模拟数据的
1.下载 npm install -g json-server
2.查看版本 json-server --version
3.创建模拟数据文件夹mock 在其中写入数据的json文件
{
"one":[
{"name":"xixi","age":18}
]
}
4.启动
(4-1)cd到mock文件夹下
(4-2)json-server --watch 你的json文件名字 --port 你的端口
疑问 上面这个名字太难记了 我怎么修改他?
1.cd到mock文件夹下 npm init -y 初始化一个package.json 文件
2。到package.json文件中 在scripts节点中设置你的启动命令
{
"name": "mock",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
我是配置启动命令的
"xiaoming":"json-server --watch data.json --port 8877",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
大家发现刚才跨域的方式路径非常深 麻烦 我们有没有办法把这些配置文件放到合适好找的地方
就可以使用弹射来完成(把层级很深的配置文件 弹射到根路径下)
注意:去公司没事别弹 弹之前 问清楚经理 可以你在弹 因为弹射是不可逆的 弹出来就回不去了
注意:去公司没事别弹 弹之前 问清楚经理 可以你在弹 因为弹射是不可逆的 弹出来就回不去了
注意:去公司没事别弹 弹之前 问清楚经理 可以你在弹 因为弹射是不可逆的 弹出来就回不去了
注意:去公司没事别弹 弹之前 问清楚经理 可以你在弹 因为弹射是不可逆的 弹出来就回不去了
注意:去公司没事别弹 弹之前 问清楚经理 可以你在弹 因为弹射是不可逆的 弹出来就回不去了
注意:去公司没事别弹 弹之前 问清楚经理 可以你在弹 因为弹射是不可逆的 弹出来就回不去了
第一次弹射可能会出错 所以你在git add 在commit提交一次
使用npm run eject 进行弹射
就会发现项目的根路径下 有了那么配置文件
根据url的不同来切换对应的组件页面
路由可以实现spa单页面应用 一个项目只有一个完整的页面 我们通过切换页面的显示内容 已达到不刷新页面进行切换的效果
仅仅只包含了路由最基本的功能没有一些辅助的api 但是他轻量级
除了基本的路由功能以外 还有很多便捷性的api方便我们开发者实现路由功能
npm install --save react-router-dom
带# 不会丢失
不带# 上线刷新404
1.下载 npm install --save react-router-dom@5
2.设置路由模式 index.js中设置
import React from 'react';
import ReactDOM from 'react-dom';
// 1.引用路由模式
import {HashRouter} from "react-router-dom"
ReactDOM.render(
// 2.设置路由模式 包裹根组件
,
document.getElementById("root"))
3.开始设置路由页面 写在views或者pages
4.设置路由规则与出口 新建router文件夹在新建index.js
import React, { Component } from 'react'
// 1.把你要用的路由页面进行引用
import Home from "../views/home.jsx"
import Phone from "../views/phone.jsx"
import User from "../views/user.jsx"
import Shop from "../views/shop.jsx"
// 2-1 引用Route
import {Route} from "react-router-dom"
export default class index extends Component {
render() {
return (
<>
{/* 路由规则与路由出口 */}
{/* */}
{/* 2-2.配置出口与规则 */}
>
)
}
}
设置路由配置组件为根组件index.js中
import React from 'react';
import ReactDOM from 'react-dom';
// 引用路由配置组件
import Index from "./router/index.js"
// 1.引用路由模式
import {HashRouter} from "react-router-dom"
ReactDOM.render(
// 2.设置路由模式 包裹根组件
{/* 注入路由组件 */}
,
document.getElementById("root"))
<关键字 to=“去哪里”>关键字>
Link 就是一个组基本的路由导航
NavLink 处理基本路由跳转的功能以外 还添加了自动选中类名的设置 active类名
但是 如果这个active的类名 已经存在了怎么办?
修改navlink的选中类名 activeClassName=“你要修改的类名”
注意
有的同学navlink可能在电脑上不加类名 如果出现这种问题 那么就不要用vscode内置的cmd打开项目 而是用外部的cmd启动项目即可解决
this.props.history.push("/你要去的路径")
{/* 编程式导航 */}
大家会发现上面的编程式导航 有的时候可以 有的时候不行
不行的时候会报错 说push没有定义
是因为我们如果要使用编程式导航 那么就要使用路由中提供的history对象 但是我们如果把这个编程式导航写在了(不是被路由所管理的页面中 —就是在路由规则中配置过的页面叫被路由管理的页面 才有history对象 不在路由中配置过的页面就没有history对象)从而不能使用编程式导航 会报错
上面说了 不在路由配置过的页面就一定不能使用编程式导航吗?
默认直接使用是不行的
如果我们要使用
withRouter是一个高阶组件 作用就是让不是被路由所管理的页面也具有history对象
import React, { Component } from 'react'
// 1引用
import {withRouter} from "react-router-dom"
// 2.修改暴漏到最下面
class toplink extends Component {
render() {
return (
{/* 编程式导航 */}
)
}
}
// 3.使用withRouter来把功能传递给当前组件
export default withRouter(toplink)
replace("/去哪里") 替换
goBack() 后退
goForward() 前进
1.编写二级路由页面
2.配置规则与出口 只需要在对应的一级路由页面中进行route的配置
import React, { Component } from 'react'
import {Route,NavLink} from "react-router-dom"
import Era from "./er/era.jsx"
import Erc from "./er/erc.jsx"
export default class phone extends Component {
render() {
return (
phone
era
erc
{/* 配置二级路由规则与出口 */}
)
}
}
1.创建页面
2.配置404页面规则
<>
{/* 路由导航的组件 */}
{/* 路由规则与路由出口 */}
{/* */}
{/* 2-2.配置出口与规则 */}
{/* 404页面必须放在最下面 */}
>
大家会发现当我们加入了404页面之后 每个页面都会把404显示出来 因为reacrt的路由在匹配到之后 还会一直向下进行 直到最后
用switch包裹的内容会渲染上之后不继续向下进行 只会匹配到第一个匹配的内容
{/* 唯一渲染 */}
{/* 2-2.配置出口与规则 */}
{/* 404页面必须放在最下面 */}
重新定位方向
{/* 唯一渲染 */}
{/* 2-2.配置出口与规则 */}
{/* 重定向 */}
{/* 精准匹配 exact */}
{/* 404页面必须放在最下面 */}
就是把数据从一个页面总传递到另外一个页面
1.在路由配置i规则中设置接收参数(谁接受数据 谁配置规则)
{/* */}
{/* parmas传参设置路径接受参数 */}
2.发送数据
编程式
this.props.history.push("/user/我是传递给user的数据params")
声明式
home
{/* 声明式 发送数据*/}
3.接受数据
componentDidMount() {
// 接受传递过来的数据
console.log(this.props.match.params.xiaoming)
}
优点 : 刷新之后数据依然存在
确定: 只能传递字符串 如果数据太多url会比较难看
1.发送
声明式
编程式
fun=()=>{
// this.props.history.push({pathname:"你要去哪里",state:{你的key:val}})
this.props.history.push({pathname:"/user",state:{xiaobai:"我是state方式传递的数据"}})
}
2.接受
this.props.location.state.xxx
// state方式接受数据
console.log(this.props.location.state.xiaobai)
优点:传递数据的时候url是不显示数据的 可以传递对象 并且安全
缺点: 刷新之后传递的数据会丢失
可以让我们在进行路由跳转的时候完成一些权限验证
修改路由规则上面的写法
{/* 路由判断路由守卫 */}
{return 你的渲染组件}}/>
把原有的component变成了render调用一个函数(因为有了函数 那么我们就可以在函数中编写特定的逻辑)
在react中我们创建项目的时候 经常会有一些特定的逻辑要在多个组件中继续进行使用 传统方式就是把这些逻辑在每个组件中都写一次 然后调用(会造成代码的冗余)
所以我们就想办法需要把这重复的 冗余逻辑 可以封装起来 并且组件还要很方便的进行复用 那么我们就可以使用react中提供的高阶组件HOC来进行封装
语法:
在创建高阶组件的时候本质上来说他是一个函数 返回一个组件 但是这个高阶组件的名字建议大家叫withxxx
let withLink=()=>{
return 组件
}
HOC参数是一个组件返回值还是一个组件
调用高阶组件分三部
1.引用
2.修改组件的暴漏到最下面
3.使用高阶组件来传递内容
例子 在项目中有两个组件都需要发送一个请求 并且这个请求来的数据还需要在页面中进行展示
HOC的反向继承 说的简单点就是渲染劫持 在使用HOC的时候可以进行一个高阶组件中的条件渲染
typescript 是有微软推出的一个开源的编程语言。他是javascript的超集(超集集合) 本质上他就是扩展了js现有的语法 但是他会向下兼容js 同时解决了js的很多痛点 弱类型 ts在语法生更加的严格
ts可以在任何的浏览器 操纵系统中进行运行 并且是开源的
浏览器默认情况下只认识 html css js 默认是不认识ts的 所以我们写的ts需要通过一个ts解析器去翻译ts 把ts编译成js 从而在任何浏览器上都可以运行 ts的编译器 可以在任何操纵系统上运行
1.电脑上必须有node
2.需要在电脑上去安装ts解析器
npm install -g typescript
3.查看是否安装成功 tsc空格-v
4.创建一个以ts结尾的文件 用来编写ts代码
5.cd到你要运行的ts文件夹中
6.使用tsc空格文件名 (就会把我们写的ts代码翻译成js)
每次我们在写好ts文件的时候 都需要执行下 tsx 文件名的编译命令 比较麻烦 我们能不能用简单的方式来编译ts
在市级开发项目的时候 我们可以通过配置的方式进行自动编译
1.cd到ts的文件夹下
2.使用tsc -init命令来初始化ts项目 初始化完成之后 会生成一个tsconfig.json( 设置配置我们当前ts项目的选项)
1点击vscode的 终端-----》运行任务-----》typescript-----》在选择你要监视的ts配置文件
监控单个文件
tsc 文件名 -w
监控所有的文件
tsc -w
和js一样
使用var 或者let来创建变量 使用const来创建常量
注意:let 变量不能重复声明
注意:const和let 是块级作用域
注意:变量的命名 除了下划线_ 和美元$符号以外不能包含其他的特殊字符
语法:
js
let 变量名 = 变量值
ts
let 变量名:数据类型= 变量值
常见类型
string number boolean object array
// 1.创建字符串类型
let text:string="666";
// 创建number类型
let num:number=123;
// 布尔类型
let bool:boolean=true;
// 创建数组
// 数组概念
// 数组是用来存储相同数据类型的一个或多个值得集合
// 数组是用来存储不同数据类型的一个或多个值得集合
// 方式1
let arr:number[]=[111,2222,33333,44444,5555,66666]
// 方式2
let arrb:Array<string>=["11","222","333"]
// 创建对象
let obj:object={
name:"xixi",
age:18
}
// 创建数组对象
let user:object[]=[
{name:"xixi",age:18},
{name:"xixi",age:18},
{name:"xixi",age:18},
{name:"xixi",age:18}
]
新的数据类型
any 类型:任意类型
任意类型 在一些特殊的时候 我们没有办法确定变量中存储的数据类型是什么 那么这个时候我们就可以使用any类型 ts编译器会关闭类型检测 从而实现任意类型
工作中能不要用就不要用
// any类型
let xiaoming:any="true";
let arrc:any[]=[111,"字符串",true]
tuple元祖类型:
已知数量和数据类型的数组
// 元祖
let xiaohong:[string,number,string]=["1",2,"3"]
enum 枚举类型:
一组命名空间的集合 就是可以给一组数值起一个友好的名字
// 枚举类型
// enum demo{one,two,three};
// console.log(demo.one);//每个值默认是从0开始以此类推
// 枚举赋值 number类型 在赋值后面的内容还是会自增1 但是前面的内容不影响
// enum demo{one,two=666,three};
// console.log(demo.one);
// console.log(demo.three);
// 枚举赋值 string类型 在赋值字符串类型之后 前面的不影响 但是赋值之后的内容必须都给他设置对应的值
enum demo{one,two="你好",three="你坏"};
console.log(demo.one);
console.log(demo.three);
never 没有值
void 空值 或者 undefined
ts用用自动类型判断的机制 当对变量声明和赋值的时候是同时进行的 ts的解析器就会自动的判断变量的类型
就是给原来存在的一个数据类型起一个新名字 type创建类型别名
// 类型别名
type xiaoming=string;
let text:xiaoming="你好"
原来我们只能给一个变量起一个数据类型 如果这个变量想存的数据是多种怎么办?
// 联合类型
let num:string|number =111
// 类型别名和联合类型整合
type xiaohong=string|number
let demo:xiaohong="111"
// 函数形参
function fun(num:string){
console.log(num)
}
fun("123")
// 函数返回值
// 就是表明当前函数的返回值类型为number
function funb():number{
return 123
}
// 函数没有返回值
function func():void{
}
就是我们可以手动的来指定一个值的类型
语法:
值 as 类型
<类型>值
// 类型断言
// 告诉我们string|number上没有toUppserCase
// 并且又说了 number上面没有toUppserCase
function fund(num:string|number):void{
console.log((num as string).toUpperCase())
}
是一种思想 很多同学会认为这是个很难的东西 但是不然 他是一个简单的思想 用这个思想来构建我们的项目
我们已经学过了很多面向对象的写法
1.操纵浏览器使用window对象
2.操纵网页 使用 document对象
3.操纵浏览器的控制台 使用console对象
定义对象 包含 属性(数据)与方法(动作)
创建对象的时候可以定义一个类来进行
语法:
class 类名{
属性名:类型
constructor(参数:类型){
this.属性名=参数
}
方法(){
}
}
// 类
class User{
// 属性
name:String;
age:Number;
constructor(newname:string,newage:number){
this.name=newname;
this.age=newage;
}
// 方法
showname(){
console.log(this.age)
}
}
// 使用类
// new关键字来进行实例化这个类
let user=new User("小明",666)
console.log(user.name)
user.showname()
本质上就是对属性和方法的一个容器 主要的作用就是用来存储属性和方法 这就是所谓的封装
默认情况下 对象的属性可以任意的修改 为了安全性 那么我们在ts中就可以对封装的属性进行权限上的设置
public(默认值) 公开的 谁都可以用
// public公开的谁都可以用
// 是默认值 写了更好 你没有写 编译的时候会自动给你加一个
class a{
public name:string="小红"
public showname(){
console.log("我是方法")
}
}
let demoa=new a()
console.log(demoa.name)
protected 受保护的 只能类和子类中进行使用
// protected 受保护的 只能类和子类中进行使用
class b{
protected name:String="小白"
protected showname(){
console.log("我是受保护的方法"+this.name)
}
}
let demob=new b()
console.log(demob.name)//会报错使用不了
demob.showname()//会报错使用不了
private 私有的 只能自己有谁都用不了只能在当前类中使用
class b{
private name:String="小白"
private showname(){
console.log("我是受保护的方法"+this.name)
}
}
let demob=new b()
console.log(demob.name)//会报错使用不了
demob.showname()//会报错使用不了
静态属性static 也称之为 类属性 使用静态属性无需实例化即可是直接使用
class c{
static num:number=123456;
}
// 不需要实例化就可以直接使用
console.log(c.num)
继承是面向对象中另外一个重要 的特性 通过继承可以将父类中的属性和方法在子类中进行使用
// 继承
class Fu{
public name:String="xixix"
public age:Number=18
}
class Zi extends Fu{
showname(){
console.log(this.name)
}
}
let zi=new Zi()
zi.showname()
如果要实现多态 那么必须先要实现继承
在子类中的方法会替换到父类中同名的方法 这个就叫多态
// 多态
class Demofu{
run(){
console.log("我是父类的方法")
}
}
class Demozi extends Demofu{
run(){
console.log("我是子类的方法")
}
}
let demozi=new Demozi()
demozi.run()
接口就是定义了一些规范 在这些规范中来约束我们的行为和动作
接口主要就是来复杂定义一个类的结构 去限制这个对象或者是类中的属性
使用接口 使用interface关键字来进行定义
interface 接口名(建议首字母使用大写I来进行定义其后就是接口名){
数据:数据类型
}
// 接口
interface IObj{
name:String,
num:Number,
sex:boolean
}
let obj:IObj={
name:"xixi",
num:567,
sex:true
}
接口中定义了三个数据 那么我在实现的时候用不到这么多怎么办?
在定义接口的时候 我们可以吧其中的约束 定义成可选 那么在实现的时候 这些可选属性就可以不用实现
// 接口
interface IObj{
name:String,
// 我是给num和sex定义成了可选属性 那么这样我们在
// 实现的时候就不一定必须要把下面两个实现出来
num?:Number,
sex?:boolean
}
let obj:IObj={
name:"xixi"
}
泛型 是指在定义函数 接口或者类的时候 不需要现制定数据类型了 而是在使用的时候在进行类型的指定
// 泛型
class My<T>{
name:T
constructor(newname:T){
this.name=newname
}
}
创建项目 使用 create-react-app 项目名 --template typescript
teact+ts项目使用的时候文件的名字需要是tsx
创建组件的时候和原来创建的方式是一样的
import React, { Component } from 'react'
export default class app extends Component {
render() {
return (
app
)
}
}
注意在引用的时候不加.tsx结尾否则会报错
import React from 'react';
import ReactDOM from 'react-dom';
//不加结尾不加结否则会被错
//不加结尾不加结否则会被错
//不加结尾不加结否则会被错
//不加结尾不加结否则会被错
import App from "./app"
ReactDOM.render(
<App />,
document.getElementById('root')
);
父子组件在使用的时候正常用 就是注意在引用的时候不加.tsx结尾
传统js的写法
父组件
import React, { Component } from 'react'
import Zi from "./zi"
export default class fu extends Component {
render() {
return (
<>
fu
>
)
}
}
子组件、
import React, { Component } from 'react'
export default class zi extends Component {
render() {
return (
zi--{this.props.text}
)
}
}
ts中实现props需要使用接口来进行数据类型的定义
子组件需要使用接口来进行数据类型的设置 但是父组件没有改变
import React, { Component } from 'react'
// 1.使用props那么必须定义props的接口类型
interface IProps{
text:String
}
// 2.需要把接口传递到下方组件中使用泛型传递
export default class zi extends Component {
render() {
return (
zi--{this.props.text}
)
}
}
import React, { Component } from 'react'
// 3.定义接口约束props的类型
interface IProps{
fufun:any
}
// 4.把props的接口传递到组件上
export default class zi extends Component {
fun=()=>{
// 2.使用props接收父组件传递过来的函数
// 5.直接传参
this.props.fufun("我是子组件的数据")
}
render() {
return (
zi
{/* 1.使用事件触发 */}
)
}
}
父组件
import React, { Component } from 'react'
import Zi from "./zi"
export default class fu extends Component {
fun=(val:string)=>{
console.log(val)
}
render() {
return (
fu
)
}
}
传统使用简写state的写法可以直接用 但是公司很多都会用如下的写法
import React, { Component } from 'react'
export default class statedemo extends Component {
constructor(props:any){
super(props)
this.state={
text:"你好"
}
}
fun=()=>{
this.setState({
text:"我变了"
})
}
render() {
return (
<div>
statedemo---
{this.state.text}
<button onClick={this.fun}>点我修改</button>
</div>
)
}
}
大家用传统的写法会发现this.state.text报错了
import React, { Component } from 'react'
// 使用接口定义类型
interface IState{
text:String
}
// 2.把接口传递到组件之中
// 下面的泛型中<是props的接口,state的接口>
export default class statedemo extends Component<{},IState> {
constructor(props:any){
super(props)
this.state={
text:"你好"
}
}
fun=()=>{
this.setState({
text:"我变了"
})
}
render() {
return (
statedemo---
{this.state.text}
)
}
}
import React, { Component } from 'react'
export default class demo extends Component {
inputref=React.createRef()
public fun = () => {
console.log((this.inputref.current as HTMLInputElement).value)
}
public render() {
return (
demo
)
}
}
函数组件又称之为无状态组件
因为函数组件的可读性更好 减少了大量的冗余代码 在函数组件中 只有一个jsx简化了组件的创建难度
优势
函数组件不会被实例化 渲染的效率更高
函数组件不使用this
既然函数组件不会被实例化 那么他就在创建的时候可以大大减少内存的消耗 提高性能
缺点
函数组件默认不能使用状态 不能使用ref 不能使用生命周期
因为 在react16.8之后 推出了一个技术叫HOOK 通过HOOK就可以让函数组件使用上面不能用的东西了
// js方式创建的函数组件
// let Fun=()=>{
// return (
// <>
// 我是一个函数组件
// >
// )
// }
// export default Fun
// ts函数组件创建方式
import React from "react"
// FC FunctionComponent的简写
let Fun:React.FC<{}>=()=>{
return (
我是ts创建的函数组件
)
}
export default Fun
import React from "react"
interface IProps{
title:String
}
// FC FunctionComponent的简写
let Zi:React.FC=(props)=>{
return (
zizizziziziz---{props.title}
)
}
export default Zi
在react的HOOK是react16.8版本新增的一个特性 主要的作用 就是让函数组件使用原来使用不了的东西
函数组件又称之为无状态组件
因为函数组件的可读性更好 减少了大量的冗余代码 在函数组件中 只有一个jsx简化了组件的创建难度
优势
函数组件不会被实例化 渲染的效率更高
函数组件不使用this
既然函数组件不会被实例化 那么他就在创建的时候可以大大减少内存的消耗 提高性能
缺点
函数组件默认不能使用状态 不能使用ref 不能使用生命周期
因为 在react16.8之后 推出了一个技术叫HOOK 通过HOOK就可以让函数组件使用上面不能用的东西了
主要作用就是让函数组件可以使用状态
语法:
useState会返回一个数组长度为2的一个数组
let [就是存放初始化值的变量 , 修改这个变量状态的方法]=useState(“初始化值”)
// 编写函数组件
// 1.引用useState
import React,{useState} from 'react'
function Demod() {
// 2.创建状态
let [text,xiaoming]=useState("我是初始值")
// 4.修改
let fun=()=>{
xiaoming("我变了")
}
return (
{/* 3.使用状态 */}
demod---{text}
)
}
export default Demod
方式1 low的方式
// 创建多个useState的方式创建多个状态
let [text,xiaoming]=useState("我是初始值")
let [texta,xiaominga]=useState("我是初始值1")
let [textb,xiaomingb]=useState("我是初始值2")
let [textc,xiaomingc]=useState("我是初始值3")
let [textd,xiaomingd]=useState("我是初始值4")
方式2 一次性创建多个 推荐使用
let [text,xiaoming]=useState({
texta:"我是第一个",
textb:"我是第2个",
textc:"我是第3个",
textd:"我是第4个",
texte:"我是第5个"
})
使用
text.texta来进行使用
修改
xiaoming({...text,textc:"我是第三个我变了!!!"})
import React,{useState} from 'react'
let Demoe:React.FC<{}>=()=> {
let [xiaoming,setXiaoming]=useState("我是状态")
let fun=():void=>{
setXiaoming("我变了")
}
return (
demoe--{xiaoming}
)
}
export default Demoe
就是让函数组件可以使用ref的一个技术
// 1.先引用
import React,{useRef} from 'react'
function Demof() {
// 2.创建ref
let inputref=useRef(null)
let fun=()=>{
// 4.使用ref
console.log(inputref.current.value)
}
return (
{/* 3.绑定ref */}
)
}
export default Demof
函数组件中是不能使用生命周期的 所以我们在函数组件中默认是没有办法自动执行一些操作的 比如发送请求
useEffect就可以让函数组件使用生命周期 他是 componentDidMount 与 componentDidUpdate componentWillUnmount 三个钩子的综合体
// 1.引用
import React,{useEffect,useState} from 'react'
function Demoh() {
let [xiaoming,setxiaoming]=useState("我是初始值")
// 2.使用
useEffect(()=>{
console.log("我是钩子函数")
})
return (
D--{xiaoming}
)
}
export default Demoh
默认情况下他在三个情况下都会执行 我如果只让useEffect在特定情况下执行怎么办?
在useEffect中传递第二个参数为空数组的时候他就会模拟componentDidMount
useEffect(()=>{},[])
useEffect(()=>{
console.log("我是钩子函数")
},[])
要注意 这个不能完全的模拟 因为初始化的时候还是会触发
在useEffect中不传递第二参数
在useEffect中函数中返回一个函数
import React,{useState,useEffect} from 'react'
function Zi() {
useEffect(()=>{
return ()=>{
console.log("我被销毁了")
}
})
return (
zi
)
}
function Fu() {
let [bool,setbool]=useState(true)
return (
fu--{bool?'真':"假"}
{
bool&&
}
)
}
export default Fu
主要就是为了简化我们在函数组件中使用上下文对象的复杂度 useContext接受一个context对象 并且返回context中存储的数据
// 1.引用创建上下文对象
import React, { createContext,useContext } from 'react'
// 2.开始创建
let context = createContext()
function Sun() {
let value=useContext(context)
return (
Sun--{value.age}
)
}
function Fu() {
return (
Fu
)
}
function Ye() {
return (
Ye
)
}
export default Ye
useReducer和redux没有任何关系 主要就是如果组件中对一个state有频繁的多次修改 那么我们可以使用useReducer来替代useState
语法:
let [数据变量名,调用修改数据的方法]=useReducer(修改数据的方法动作,“初始化数据”)
// 1.引用
import React,{useReducer} from 'react'
function Demok() {
let reducer=(state,action)=>{
switch (action.type) {
case "ADD":
return state+1
break;
case "DEL":
return state-1
break;
default:
return state
break;
}
}
// 2.创建数据与多个修改的动作
let [state,dispatch] = useReducer(reducer,10)
return (
D--{state}
)
}
export default Demok
知道我们修改该数据的时候函数组件会被内重新执行 重新执行话里面的函数也会被冲新调用 那么这样一来性能比较差 所以我们可以使用上面两包裹我们创建的函数 就少重复渲染的次数
语法
useCallbak(()=>{
你的函数
})
react开发中 使用css样式比较容易造成项目的样式作用域冲突 因为css定义的样式都是全局的 在vue中使用scoped来解决这同杨的问腿 但是有没有其他的方式解决?
不要用标签选择器 要使用class选择器
1.创建对应的css文件 但是文件名 xxx.module.css
写入相关样式
.demoel{
color:red;
}
2.在你想使用的组件中引用
import from
3.使用
import React from 'react'
// import "./css/css.css"
// 原来使用import 引用样式
import demo from "./css/css.module.css"
import demob from "./css/cssb.module.css"
function Zi() {
return (
Zi
Zi
我是子组件的h1
我是子组件的h1
)
}
function Demol() {
return (
我是demo1的组件
)
}
export default Demol
技术选型 react+HOOK–antd
1.新建项目
2.删除掉项目中没有用的内容
3.创建根组件 app.js
详见上面的笔记
详见上面的笔记
1.下载 npm install --save styled-components
2.在合适的位置新建xxx.js用来容纳你写的样式
3.开始编写
// 设置styled-Components
import styled from "styled-components"
// 开始编写 (首字母要大写)
let Title=styled.div`
.logo{
font-size:18px;
color:yellow;
font-weight: bold;
}
`
export default Title
4.在你要使用的组件中 先引用 然后再使用
import Title from "./leftList_styled.js"引用
{/* 使用样式 */}
<Title>
<div className="logo">
新闻发布系统
</div>
</Title>
json-server
使用react+HOOK技术栈完成
后台数据使用json-server进行数据模拟 请求封装 配合拦截器对数据进行前后台的获取
项目中有大量的权限设置 需要我们着重观察 并且页面全部动态展示配合antd何以非常快速的让大家体会到项目的整体性和完整性
1 create-react-app 项目名 创建项目
2.在项目中删除没有的初始化文件 并且新建index.js(全局配置文件)与app.js
index.js 全局配置文件
import React from 'react'
import ReactDOM from 'react-dom'
import App from "./app.js"
ReactDOM.render(
,
document.getElementById('root')
)
app.js 根组件
let App=()=>{
return (
<>
我是根组件
>
)
}
export default App
css模块化
react中使用普通的css样式表会造成作用域的冲突,css定义的样式的作用域是全局,在Vue 中我们还可以使用scope来定义作用域,但是在react中并没有指令一说,所以只能另辟蹊径了。 所以我们可以使用css模块化来解决这个问题
在传统代码中如果有两个组件 并且有相同的类名 在渲染组件的时候样式就会被污染
1.创建xxx.module.css文件用来编写css (不要用标签选择器 尽量用class选择器)写入你的样式
.demoh{
color:yellow;
}
2.在组件中引用css 并且使用
import React, { Component } from 'react'
// 1.引用
import style from "./demo.module.css"
export default class demo extends Component {
render() {
return (
<>
{/* 2.使用 */}
我是第一个组件
>
)
}
}
如果在项目上面直接使用scss (尝试修改css文件)
项目会报 如下错误
Compiled with problems:X
ERROR in ./src/demo.module.scss (./node_modules/[email protected]@css-loader/dist/cjs.js??ruleSet[1].rules[1].oneOf[8].use[1]!./node_modules/[email protected]@postcss-loader/dist/cjs.js??ruleSet[1].rules[1].oneOf[8].use[2]!./node_modules/[email protected]@resolve-url-loader/index.js??ruleSet[1].rules[1].oneOf[8].use[3]!./node_modules/[email protected]@sass-loader/dist/cjs.js??ruleSet[1].rules[1].oneOf[8].use[4]!./src/demo.module.scss)
Module Error (from ./node_modules/[email protected]@sass-loader/dist/cjs.js):
Cannot find module 'sass'
Require stack:
- C:\Users\54407\Desktop\react全家桶\myapp\node_modules\[email protected]@sass-loader\dist\utils.js
- C:\Users\54407\Desktop\react全家桶\myapp\node_modules\[email protected]@sass-loader\dist\index.js
- C:\Users\54407\Desktop\react全家桶\myapp\node_modules\[email protected]@sass-loader\dist\cjs.js
- C:\Users\54407\Desktop\react全家桶\myapp\node_modules\[email protected]@loader-
所以我们下载scss模块
cnpm install --save sass
即可在项目中安装sass
详见之前内容
在没有授权登录的时候不会进入到NewSandBox相关内容 会被重定向到/login
1.下载路由 npm install --save react-router-dom@5
2.创建路由文件夹与容纳路由的文件(router文件夹与index.js路由文件)
3.设置路由 切记路由模式设置成Hash模式 Browser模式的话打包上线会有404(也可以打包项目时候修改 不影响项目开发)
4.设置路由模式
import React, { Component } from 'react'
// 引用路由模式
import {HashRouter} from "react-router-dom"
export default class index extends Component {
render() {
return (
// 设置路由模式
)
}
}
5.创建components 与 views 文件夹 并且创建登录页面 与 首页NewSandBox 路由页面与路由配置
6.设置基础页面权限
import React, { Component } from 'react'
// 引用路由模式
import { HashRouter, Route, Redirect, Switch } from "react-router-dom"
import Login from "../views/login.jsx"
import NewSandBox from "../views/NewSandBox.jsx"
export default class index extends Component {
render() {
return (
// 设置路由模式
{/* 判断用户是否登陆过如果有那么就进入首页 否则 重定向到登录页面 */}
{/* {return 判断用户是否登陆过 ? : */}
{return localStorage.getItem("token") ? :
} } />
)
}
}
下图大家会发现在首页中 左侧 与 右侧顶部 是不会变化的 右侧下面区域才是我们需要每次点击导航需要改变的内容所以我们可以使用二级路由来完成
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pcJaaXLf-1648039840000)(./img/2b.png)]1.创建左侧和右侧顶部的组件 在components下创建leftList.jsx与rightTop.jsx用来容纳
2.在首页NewSandBox.jsx中引用两个组件
// 引用左侧与右侧顶部的组件
import LeftList from "../components/leftList.jsx"
import RightTop from "../components/rightTop.jsx"
let NewSandBox=()=>{
return (
{/* 使用 */}
)
}
export default NewSandBox
3.设置右侧下半部分的二级路由
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-38tW9HJg-1648039840003)(./img/1cc.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UXPAtBcS-1648039840004)(./img/3.png)]
1.创建二级路由页面 分别为在views文件夹下
创建home文件夹 home.jsx(首页欢迎页面)
创建user-manage文件夹并在其中创建list.jsx用户列表页面
创建right-manage文件夹中新建 list.jsx 角色列表组件 roleList.jsx权限列表组件
创建no文件夹 no.jsx 404错误页面
2.配置路由规则 在NewSandBox.jsx中配置
// 引用左侧与右侧顶部的组件
import LeftList from "../components/leftList.jsx"
import RightTop from "../components/rightTop.jsx"
// 引用二级路由页面
import Home from "./home/home.jsx"
import Rlist from "../views/right-manage/list.jsx"
import RoleList from "../views/right-manage/roleList.jsx"
import Ulist from "../views/user-manage/list.jsx"
import No from "../views/no/no.jsx"
import { Route, Switch, Redirect } from "react-router-dom"
let NewSandBox = () => {
return (
{/* 使用 */}
{/* 配置二级路由规则 */}
{/* 设置重定向保证第一次进入就显示欢迎页面home */}
{/* 在设置404错误页面 */}
)
}
export default NewSandBox
Antd 式蚂蚁集团 开发的一款企业级的后台pc端 React UI类库。
官网:https://ant-design.gitee.io/index-cn
大家一定要记住 文档在手 天下我有
1.下载: yarn add antd 或 npm install --save antd
2.根据文档提示 我们可以使用它的button组件
import React, { Component } from 'react'
// 引用指定内容
import { Button } from 'antd';
export default class Home extends Component {
render() {
return (
首页欢迎
{/* 使用 */}
)
}
}
3.设置样式antd样式
官方式这样说的:
修改 src/App.css
,在文件顶部引入 antd/dist/antd.css
但是我们可以:
在views文件夹设置一个css 在其中引用antd的样式
@import '~antd/dist/antd.css';
并且把刚设置的css 在views下的index.js中引用
import "./index.css";
到此antd就已经成功安装到我们的项目中了
在官网中发现下面的布局很符合我们的要求
分析代码我们发现需要改造之前的内容
1.修改整体页面布局NewSandBox.jsx中 把最外层的div 修改成layout 标签 但是不要忘了引用
xxxxxx
xxxxx
xxxx
// 引用
import { Layout } from 'antd';
let NewSandBox = () => {
return (
// 修改成Layout
xxxxxx
)
}
export default NewSandBox
2.设置左边导航修改Leftlist.jsx中设置
// 不要忘了引用
import { Layout, Menu } from 'antd';
import {
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
} from '@ant-design/icons';
const { Sider } = Layout;
let LeftList = () => {
return (
)
}
export default LeftList
3.设置有测的布局容器 在NewSandBox.jsx设置右侧内容的容器为layout
import LeftList from "../components/leftList.jsx"
import RightTop from "../components/rightTop.jsx"
// 引用二级路由页面
import Home from "./home/home.jsx"
import Rlist from "../views/right-manage/list.jsx"
import RoleList from "../views/right-manage/roleList.jsx"
import Ulist from "../views/user-manage/list.jsx"
import No from "../views/no/no.jsx"
// 引用左侧与右侧顶部的组件
import { Route, Switch, Redirect } from "react-router-dom"
// 引用
import "./NewSandBox.css"
import { Layout } from 'antd';
const {Content } = Layout;
let NewSandBox = () => {
return (
// 修改成Layout
{/* 使用 */}
设置有测容器为Layout
xxxxxxxx
)
}
export default NewSandBox
4.设置右侧顶部在 rightTop.jsx中
import React, { Component,useState } from 'react'
import { Layout } from 'antd';
import {
MenuUnfoldOutlined,
MenuFoldOutlined
} from '@ant-design/icons';
// 但是Header还需要引用
const { Header } = Layout;
let RightTop=()=>{
创建变量
const [collapsed]=useState(false)
return (
{/* {React.createElement(this.state.collapsed ? MenuUnfoldOutlined : MenuFoldOutlined, {
className: 'trigger',
onClick: this.toggle,
})} */}
{
collapsed? :
}
)
}
export default RightTop
5.使用content包裹路由设置内容 在NewSandBox中设置
import LeftList from "../components/leftList.jsx"
import RightTop from "../components/rightTop.jsx"
// 引用二级路由页面
import Home from "./home/home.jsx"
import Rlist from "../views/right-manage/list.jsx"
import RoleList from "../views/right-manage/roleList.jsx"
import Ulist from "../views/user-manage/list.jsx"
import No from "../views/no/no.jsx"
// 引用左侧与右侧顶部的组件
import { Route, Switch, Redirect } from "react-router-dom"
let NewSandBox = () => {
return (
// 修改成Layout
{/* 使用 */}
{/* 配置二级路由规则 */}
{/* 使用content组件包裹路由 不要忘了上面引用*/}
xxxxxxx
)
}
export default NewSandBox
6.引用样式在views下新建NewSandBox.css 并且在NewSandBox。.js中引用
#components-layout-demo-custom-trigger .trigger {
padding: 0 24px;
font-size: 18px;
line-height: 64px;
cursor: pointer;
transition: color 0.3s;
}
#components-layout-demo-custom-trigger .trigger:hover {
color: #1890ff;
}
#components-layout-demo-custom-trigger .logo {
height: 32px;
margin: 16px;
background: rgba(255, 255, 255, 0.3);
}
.site-layout .site-layout-background {
background: #fff;
}
NewSandBox中引用
import "./NewSandBox.css"
完成如下效果
1.设置页面高度100%;抓取后发现我们只需要把容器的height设置成100%即可
在NewSandBox.css中设置
#root,.ant-layout{
height: 100%;
}
2.设置右边header部分的图标部分rightTop中设置
设置下padding的位置
2.设置右边header部分的图标点击之后切换显示
import React, { useState } from 'react'
import { Layout } from 'antd';
import {
MenuUnfoldOutlined,
MenuFoldOutlined
} from '@ant-design/icons';
// 但是Header还需要引用
const { Header } = Layout;
let RightTop=()=>{
const [collapsed,upcollapsed]=useState(false)
// 修改下控制icon的变量取反
let iconup=()=>{
upcollapsed(!collapsed)
}
return (
{/* {React.createElement(this.state.collapsed ? MenuUnfoldOutlined : MenuFoldOutlined, {
className: 'trigger',
onClick: this.toggle,
})} */}
{
collapsed?:
}
)
}
export default RightTop
3.完成文字内容
欢迎xxspan>
4.设置鼠标移入下拉框
import React, { useState } from 'react'
import { Layout, Menu, Dropdown, Avatar } from 'antd';
import { DownOutlined } from '@ant-design/icons';
import {
MenuUnfoldOutlined,
MenuFoldOutlined,
UserOutlined
} from '@ant-design/icons';
// 但是Header还需要引用
const { Header } = Layout;
let RightTop = () => {
xxxxxxxx
let menu = (
);
return (
xxxxxx
欢迎xx
{/* 设置下拉框 不要忘了引用*/}
} />
)
}
export default RightTop
去文档找到siderhttps://ant-design.gitee.io/components/layout-cn/#Layout.Sider 会发现可以设置
collapsed 当前收起状态
// 不要忘了引用
import { Layout, Menu } from 'antd';
import {
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
} from '@ant-design/icons';
const { Sider } = Layout;
let LeftList = () => {
return (
// 设置之后会发现左侧菜单样式
)
}
export default LeftList
设置左侧导航标题文字
// 不要忘了引用
import { Layout, Menu } from 'antd';
import {
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
} from '@ant-design/icons';
const { Sider } = Layout;
let LeftList = () => {
return (
// 设置之后会发现左侧菜单样式
{/* 设置左侧导航标题文字 */}
全球新闻发布系统
xxxxxxx
xxxxxx
xxxxxx
)
}
export default LeftList
设置文字样式并且不要忘了在组件中引用
在components中新建index.css
.logo{
line-height: 32px;
color: white;
background-color: rgba(255,255,255,.3);
font-size: 18px;
margin: 10px;
text-align: center;
}
在组件中引用
import { Layout, Menu } from 'antd';
// 引用样式
import "./index.css"
import {
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
} from '@ant-design/icons';
const { Sider } = Layout;
完成如下效果