1、插槽与父子组件传值的合练
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<style type="text/css">
body{ margin:0; padding: 0}
.wholecontainer{width:600px; height:1000px; border:1px solid gray; margin:0 auto; padding: 0; background-color: bisque}
.myheadcontain{ width: 100%; height: 200px; background-color: aliceblue;margin:0; padding:0}
.myslidercontain{ float: left; width: 200px; height: 400px; background-color: aquamarine}
.mycontentcontain{float:right; width:380px; height: 400px; background-color:darkolivegreen}
.defualtbtn{ background-color:greenyellow}
.primary{ background-color: palevioletred}
.sub{ background-color: aqua}
</style>
</head>
<body>
<div id="app">
<div class="wholecontainer">
<div class="myheadcontain">
<myhead class="myhead"/><!--头部组件-->
</div>
<div class="slideandcontent">
<div class="myslidercontain"><mysilider/></div><!--侧边栏组件-->
<div class="mycontentcontain"><mycontent/></div><!--内容组件-->
</div>
</div>
</div>
<script>
//创建全局组件,既声明,有挂载了,也就是不用再父组件中单独挂载
Vue.component('mybutton',{
template:`
<button class="defualtbtn" :class="type"><slot></slot></button>
`,
data(){
return {
button_text:'pressme',
}
},
props:['type']
})
const myhead={
template:`
<div>
<mybutton>登录</mybutton>
我是头部组件
</div>
`
}
const mysilider={
template:`
<div>
<mybutton type="primary">注册</mybutton>
我是侧边栏组件
</div>
`
}
const mycontent={
template:`
<div>
<mybutton type="sub">登出</mybutton>
我是内容组件
</div>
`
}
new Vue({
el:"#app",
data:{
},
methods:{
},
components : {
myhead,
mysilider,
mycontent
}
})
</script>
</body>
</html>
2、具名插槽
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<ul>
<myli>
<div slot="two">占据第一个插槽</div>
<div slot="three">占据第二个插槽</div>
</myli>
</ul>
</div>
<script>
Vue.component('myli',{
template:`
<li>
<slot name="two"></slot>
<slot name="three"></slot>
</li>
`,
data(){
return {
}
},
})
new Vue({
el:"#app",
data:{
},
methods:{
},
components : {
}
})
</script>
</body>
</html>
3、使用过滤器
过滤器的职能就是给被过滤数据添油加醋
局部过滤器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<div>
<input type="number" v-model="price"/>
<div>{{price | mymonyshow}}</div>//通过管道符来使用过滤器
</div>
</div>
<script>
new Vue({
el:"#app",
data:{
price:0,
},
filters:{
//声明一个过滤器
mymonyshow:function(value){
return '¥' + value;
}
},
methods:{
},
components : {
}
})
</script>
</body>
</html>
全局过滤器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<div>
<input type="number" v-model="price"/>
<div>{{price | mymonyshow}}</div>
<div>{{msg | myreverse}}</div>
<div>{{msg | addsome('!!!')}}</div>
</div>
</div>
<script>
//定义一个全局过滤器
Vue.filter('myreverse',(value)=>{
return value.split('').reverse().join('')
})
//再定义一个全局过滤器,可以接收参数
Vue.filter('addsome',(value,param)=>{
return value+param
})
new Vue({
el:"#app",
data:{
price:0,
msg:'hello filter',
},
filters:{
//声明一个过滤器
mymonyshow:function(value){
return '¥' + value;
},
},
methods:{
},
components : {
}
})
</script>
</body>
</html>
4、watch监听
watch监听的事单个属性
基本数据类型简单监视
复杂类型深度监视
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<input type="text" v-model="msg">
<h3>{{msg}}</h3>
<input type="text" v-model="stus[0].name">
<h3>{{stus[0].name}}</h3>
</div>
<script>
new Vue({
el:"#app",
data:{
stus:[{name:'jack'}],//好几层内存地址,无法监听,需要深度监听
msg:'hello vue',
},
watch:{
msg:(newVal,oldValue)=>{
if(newVal=='zhangsan'){
console.log('i watch the newVal '+newVal);
}
},
stus:{
deep:true,//深度监视
handler:(newVal,oldVal)=>{
console.log(newVal[0].name)
}
}
},
methods:{
},
components : {
}
})
</script>
</body>
</html>
6、computed计算属性
计算属性的好处是可以不断地计算。如果单向绑定一个数据,这个数据是不方便响应事件,而计算属性实时计算,可以传递事件带来的改变。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<style type="text/css">
.current{color: red; background-color: aqua}
</style>
</head>
<body>
<div id="app">
<div>
<audio :src="getcurrenysrc" autoplay controls></audio>
<ul>
<li v-for="(item,index) in mysongs" @click="changesong(index)">
<span :class='{current:currentindex==index}'>{{item.id}} -- {{item.singer}} -- {{item.name}}</span></li>
</ul>
</div>
</div>
<script>
var songs=[
{id:1,singer:'张三',name:'风的季节',src:'./风的季节.mp3'},
{id:2,singer:'李四',name:'笑看风云',src:'./笑看风云.mp3'}
];
new Vue({
el:"#app",
data:{
iscurrent:false,
mysongs:songs,
currentindex:0,
currentstyle:''
},
computed:{
//计算属性默认是get
getcurrenysrc:function(){
//返回根据点击事件带来的索引值,从而改变currentindex。进而返回当前播放歌曲
return this.mysongs[this.currentindex].src
},
},
methods:{
changesong(index){
this.currentindex=index;
},
},
components : {
}
})
</script>
</body>
</html>
还可以进一步利用计算属性的set方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<style type="text/css">
.current{color: red; background-color: aqua}
</style>
</head>
<body>
<div id="app">
<div>
<audio :src="getcurrenysrc" autoplay controls></audio>
<ul>
<li v-for="(item,index) in mysongs" @click="changesong(index)">
<span :class='{current:currentindex==index}'>{{item.id}} -- {{item.singer}} -- {{item.name}}</span></li>
</ul>
</div>
</div>
<script>
var songs=[
{id:1,singer:'张三',name:'风的季节',src:'./风的季节.mp3'},
{id:2,singer:'李四',name:'笑看风云',src:'./笑看风云.mp3'}
];
new Vue({
el:"#app",
data:{
iscurrent:false,
mysongs:songs,
currentindex:0,
currentstyle:''
},
computed:{
//计算属性默认是get
getcurrenysrc:{
//返回根据点击事件带来的索引值,从而改变currentindex。进而返回当前播放歌曲
get:function(){
return this.mysongs[this.currentindex].src
},
set:function(newVal){
this.currentindex=newVal
}
},
},
methods:{
changesong(index){
this.getcurrenysrc=index;
},
},
components : {
}
})
</script>
</body>
</html>
6、组件的生命周期
实际就是钩子函数
7、使用$refs获取原生jsdom对象
ref的名字不能重名
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<style type="text/css">
.current{color: red; background-color: aqua}
</style>
</head>
<body>
<div id="app">
<myapp/>
</div>
<script>
Vue.component('mycom',{
template: `
<div>我的全局组件</div>
`
})
var myapp={
template:`
<div class=myapp>
<button ref="btn">我是按钮1</button>
<button ref="btn">我是按钮2</button>
<mycom class="tempclass" ref="myco"></mycom>
</div>
`,
created(){
//使用this.$refs的方式来获得原生的jsdom对象
console.log(this.$refs.btn)
},
beforeMount(){
console.log(this.$refs.btn)
},
mounted(){
console.log(this.$refs.btn)
console.log(this.$refs.myco)
},
}
new Vue({
el:"#app",
components : {
myapp
}
})
</script>
</body>
</html>
8、dom更新后使用$nextTick来回调方法
如果不使用$nextTick()来回调方法,则不能实现回调容易会出错
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<style type="text/css">
.current{color: red; background-color: aqua}
</style>
</head>
<body>
<div id="app">
<myapp/>
</div>
<script>
Vue.component('mycom',{
template: `
<div>我的全局组件</div>
`
})
var myapp={
data(){
return{
isshow:false,
}
},
template:`
<div class=myapp>
<input type="text" v-show="isshow" ref="input">
</div>
`,
mounted(){
this.isshow=true;
//dom更新需要使用$nextTick(),是在dom更新循环结束之后执行回调函数,在修改数据之后使用此方法
//在回调中获取更新之后的dom
this.$nextTick(()=>{
this.$refs.input.focus();
});
},
}
new Vue({
el:"#app",
components : {
myapp
}
})
</script>
</body>
</html>
另外:
new Vue({
//如果没用挂载el也可以动过$mount来实现
//el:"#app",
components : {
myapp
}
}).$mount(document.querySelector('#app'))
</script>
9、基本的路由配置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<!--引入vue-router模块-->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<myapp/>
</div>
<script>
var Login={
template: `
<div>我是login页面路由</div>
`
}
var Register={
template:`
<div>我是regiseter页面路由</div>
`
}
//让vue使用该vueRouter创建
Vue.use(VueRouter);
//创建router对象
var router=new VueRouter({
//配置路由对象
routes:[
//路由匹配的规则
{
path:"/login",
component:Login
},
{
path:"/regiseter",
component:Register
},
]
});
//引入vue-router后,会抛出两个全局的组件router-link(相当于a标签) to(相当于href) router-view是路由匹配的出口
var myapp={
data(){
return{
isshow:false,
}
},
template:`
<div>
<router-link to="/login">登录页面</router-link>
<router-link to="/regiseter">注册页面</router-link>
<router-view></router-view>
</div>
`,
}
new Vue({
el:"#app",
components : {
myapp
},
//把路由交给vue管理
router,
})
</script>
</body>
</html>
也可以直接给路由规则的单个路由起名字,以便调用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<!--引入vue-router模块-->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<myapp/>
</div>
<script>
var Login={
template: `
<div>我是login页面路由</div>
`
}
var Register={
template:`
<div>我是regiseter页面路由</div>
`
}
//让vue使用该vueRouter创建
Vue.use(VueRouter);
//创建router对象
var router=new VueRouter({
//配置路由对象
routes:[
//路由匹配的规则
{
path:"/login",
name:'login',
component:Login
},
{
path:"/regiseter",
name:'regiseter',
component:Register
},
]
});
//引入vue-router后,会抛出两个全局的组件router-link(相当于a标签) to(相当于href) router-view是路由匹配的出口
var myapp={
data(){
return{
isshow:false,
}
},
template:`
<div>
<router-link :to="{name:'login'}">登录页面</router-link>
<router-link :to="{name:'regiseter'}">注册页面</router-link>
<router-view></router-view>
</div>
`,
}
new Vue({
el:"#app",
components : {
myapp
},
//把路由交给vue管理
router,
})
</script>
</body>
</html>
还可以使用动态路由匹配,以冒号:的方式来配置规则,用paramsd来获取规则
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<!--引入vue-router模块-->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<myapp/>
</div>
<script>
var Login={
template: `
<div>我是login页面路由</div>
`
}
var Register={
template:`
<div>我是regiseter页面路由</div>
`
}
//让vue使用该vueRouter创建
Vue.use(VueRouter);
//创建router对象
var router=new VueRouter({
//配置路由对象
routes:[
//路由匹配的规则
{
path:"/login:id",
name:'login',
component:Login
},
{
path:"/regiseter:id",
name:'regiseter',
component:Register
},
]
});
//引入vue-router后,会抛出两个全局的组件router-link(相当于a标签) to(相当于href) router-view是路由匹配的出口
var myapp={
data(){
return{
isshow:false,
}
},
template:`
<div>
<router-link :to="{name:'login',params:{id:1}}">登录页面</router-link>
<router-link :to="{name:'regiseter',params:{id:2}}">注册页面</router-link>
<router-view></router-view>
</div>
`,
}
new Vue({
el:"#app",
components : {
myapp
},
//把路由交给vue管理
router,
})
</script>
</body>
</html>
10、嵌套路由
多层导航链接的嵌套路由,router-view套routerview
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<!--引入vue-router模块-->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<myapp/>
</div>
<script>
var Home={
template: `
<div>我是Home页面路由<br>
<router-link to="/home/songs">歌曲</router-link>
<router-link to="/home/movies">电影</router-link>
<router-view></router-view>
</div>
`
}
var Songs={
template: `
<div>我是songs页面子路由</div>
`
}
var Movies={
template: `
<div>我是movies页面子路由</div>
`
}
//让vue使用该vueRouter创建
Vue.use(VueRouter);
//创建router对象
var router=new VueRouter({
//配置路由对象
routes:[
//路由匹配的规则
{
path:"/home",
name:'home',
component:Home,
//子路由对象
children:[
{
path:'songs',
home:'songs',
component:Songs
},
{
path:'movies',
home:'movies',
component:Movies
}
]
}
]
});
//引入vue-router后,会抛出两个全局的组件router-link(相当于a标签) to(相当于href) router-view是路由匹配的出口
var myapp={
data(){
return{
isshow:false,
}
},
template:`
<div>
<router-link :to="{name:'home'}">登录页面</router-link>
<router-view></router-view>
</div>
`,
}
new Vue({
el:"#app",
components : {
myapp
},
//把路由交给vue管理
router,
})
</script>
</body>
</html>
11、小总结
组件通信
- 1、props $emti 解决父子通信的问题
- 2、$ attrs $listeners解决组件嵌套多层关系
- 3、中央事件总线 $bus 解决兄弟组件传值
路由的使用
- 1、引包
- 2、创建vueRouter对象
- 3、匹配路由规则
- 4、挂载到new Vue()实例化对象中
给vue实例化对象,挂载了两个对象this.$router(它就是VueRouter)和this. $router(配置路由信息的对象)
12、动态路由匹配
- 1、创建一个公共路由,路由内的页面内容动态生成
- 2、要生成动态路由,需要在每个路由的created()声明周期函数中动态对页面内容该改变
- 3、但由于复用,钩子(声明周期函数不会重新执行)
- 4、因此要实时动态刷新动态路由内的属性,需要使用watch监听 $route。
$route有两个参数,to(目标路由),from(其实路由) - 5、从to,和from中拿到一系列对象及值。进而动态修改路由内的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<!--引入vue-router模块-->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<myapp/>
</div>
<script>
var Timeline={
template: `
<div>我是Timeline首页<br>
<router-link :to="{name:'comDec',params:{id:'fronted'}}">前端</router-link>
<router-link :to="{name:'comDec',params:{id:'backed'}}">后端</router-link>
<router-view></router-view>
</div>
`
}
var Pins={
template: `
<div >我是pins页路由</div>
`
}
var ComDec={
data(){
return{
msg:''
}
},
template: `
<div>我是{{msg}},用于描述ComDec</div>
`,
//由于复用,钩子函数不会被重新执行
created(){
console.log('1')
this.msg='前端页面'
},
//通过watch监听$route,$route的两个参数to是目标路由,from是起始路由
watch:{
'$route'(to,from){
console.log(to,from);
switch (to.params.id) {
case 'backed':
this.msg='后端页面';
break;
case 'fronted':
this.msg='前端页面';
break;
default:
break
}
}
}
}
//让vue使用该vueRouter创建
Vue.use(VueRouter);
//创建router对象
var router=new VueRouter({
//配置路由对象
routes:[
//路由匹配的规则
{
path:"/timeline",
name:'timeline',
component:Timeline,
children:[
{
path:"/timeline/:id",
name:'comDec',
component:ComDec,
}
],
},
{
path:"/pins",
name:'pins',
component:Pins,
}
]
});
var myapp={
template:`
<div>
<router-link to="/timeline">首页</router-link>
<router-link to="/pins">沸点</router-link>
<router-view></router-view>
</div>
`,
}
new Vue({
el:"#app",
components : {
myapp
},
//把路由交给vue管理
router,
})
</script>
</body>
</html>
13、keep-alive状态保持
将router-view放在keep-alive(状态保持)里面就不会主动去销毁组件(看不到destroy组件的执行,红色也不会消失,会一直存在)
```php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<!--引入vue-router模块-->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<myapp/>
</div>
<script>
var Timeline={
template: `
<div>我是Timeline首页<br>
</div>
`,
created(){
console.log('首页组件创建了');
},
mounted(){
console.log('首页组件挂载了')
},
destroyed(){
console.log('首页组件销毁了')
}
}
var Pins={
template: `
<div > <h3 @click="clickHandler">我是pins页路由</h3></div>
`,
methods:{
clickHandler(e){
e.target.style.color='red'
}
},
created(){
console.log('沸点组件创建了');
},
mounted(){
console.log('沸点组件挂载了')
},
destroyed(){
console.log('沸点组件销毁了')
}
}
//让vue使用该vueRouter创建
Vue.use(VueRouter);
//创建router对象
var router=new VueRouter({
//配置路由对象
routes:[
//路由匹配的规则
{
path:"/timeline",
name:'timeline',
component:Timeline
},
{
path:"/pins",
name:'pins',
component:Pins,
}
]
});
var myapp={
//将router-view放在keep-alive(状态保持)里面就不会主动去销毁组件(看不到destroy组件的执行,红色也不会消失,会一直存在)
template:`
<div>
<router-link to="/timeline">首页</router-link>
<router-link to="/pins">沸点</router-link>
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
`,
}
new Vue({
el:"#app",
components : {
myapp
},
//把路由交给vue管理
router,
})
</script>
</body>
</html>
14、权限控制(全局守卫)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<!--引入vue-router模块-->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<router-link to="/home">首页</router-link>
<router-link to="/blog">我的博客</router-link>
<router-link to="/login">登录</router-link>
<a href="javascript:void(0)">退出</a>
<router-view></router-view>
</div>
<script>
//创建各个组件
var Home={
template:`
<div>我是首页组件</div>
`
}
var Blog={
template:`
<div>我是博客组件</div>
`
}
var Login={
data(){
return{
name:'',
pwd:''
}
},
template:`
<div>
<input type="text" v-model="name"/>
<input type="password" v-model="pwd"/>
<input type="button" value="登录" @click="loginhandler"/>
</div>
`,
methods:{
loginhandler(){
//登录,暂存下数据
localStorage.setItem('user',{name:this.name,pwd:this.pwd})
//跳转到博客页面
//使用编程式跳转
this.$router.push({
name:'blog',
})
}
}
}
//让vue使用该vueRouter创建
Vue.use(VueRouter);
//创建router对象
var router=new VueRouter({
//配置路由对象
routes:[
//路由匹配的规则
{
path:"/",
redirect:'/home',
component:Home
},
{
path:"/home",
name:'home',
component:Home
},
{
path:"/blog",
name:'blog',
component:Blog,
//给未来的路由做权限控制
meta:{
//证明用户访问该组件的时候需要登录
auth:true
}
},
{
path:"/login",
name:'login',
component:Login
},
]
});
//创建一个全局守卫,注意这个代码的位置,不要放在各个组件的前面,因为可能找不到to,from,报错为找不到beforeEach
router.beforeEach((to,from,next)=>{
if(to.meta.auth) {
//用户点击了博客连接,该用户需要登录
if (localStorage.getItem('user')) {
//如果localStorage不为空,就直接放行
next()
} else {
//用户需要登录
next({
path: '/login'
})
}
}else {
//直接放行
next()//如果不调用会卡住
}
});
new Vue({
el:"#app",
//把路由交给vue管理
router,
})
</script>
</body>
</html>
14、安装axios
用于前后端交互的
npm install axios
15、一个简单的请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<!--引入vue-router模块-->
<script src="./node_modules/axios/dist/axios.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<button @click="sendAjax">发请求</button>
</div>
<script>
//在原型上绑定axios,这样就可以在任何一个组件上发网络请求
Vue.prototype.$axios=axios;
new Vue({
el:"#app",
methods:{
sendAjax(){
this.$axios.get('http://123.207.32.32:8000/home/multidata')
.then(res=> {
console.log(res)
}).catch(err=>{
console.log(err)
})
}
}
})
</script>
</body>
</html>
16、执行多个并发请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fengray</title>
<script src="./vueSource/vue.js"></script>
<!--引入vue-router模块-->
<script src="./node_modules/axios/dist/axios.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
响应1:{{res1}}
响应2:{{res2}}
<button @click="multiSend">并发请求</button>
</div>
<script>
//在原型上绑定axios,这样就可以在任何一个组件上发网络请求
Vue.prototype.$axios=axios;
new Vue({
el:"#app",
data:{
res1:'',
res2:''
},
methods:{
multiSend(){
//配置默认http
this.$axios.defaults.baseURL='http://123.207.32.32:8000/home/multidata';
//请求1,get
var r1=this.$axios.get('')
var r2=this.$axios.post('add','a=1')//要视接口的具体情况
this.$axios.all([r1,r2])
.then(this.$axios.spread((res1,res2)=>{
//请求全部成功
this.res1=res1.data;
this.res2=res2.data;
})).catch(err=>{
console.log(err)
})
},
}
})
</script>
</body>
</html>