1. 创建公共实例化对象
const bus=new Vue()
2. 在需要发送数据的组件中
绑定事件 使用 bus.$emit发送数据
<button @click="send">发送</button>
methods:{
send(){
bus.$emit('自定义事件名',要发送的数据)
}
}
3. 在需要接收数据的组件中
使用bus.$on监听数据改变 实时输出数据
bus.$on需要自动触发需要使用生命周期钩子函数created/mounted,一般使用created
created(){
bus.$on('自定义事件名',data=>{
console.log(data) //data就是传递过来的数据
})
}
4. 案例:cnode首页
<!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>Document</title>
<link rel="stylesheet" href="./css/public.css" />
<link rel="stylesheet" href="./css/bootstrap.min.css" />
<link rel="stylesheet" href="./css/index.css" />
</head>
<body>
<div id="app">
<heads></heads>
<labs></labs>
<lists></lists>
<chose></chose>
<fotters></fotters>
</div>
<script src="./js/vue.min.js"></script>
<script src="./js/axios.min.js"></script>
<script>
const bus = new Vue();
const heads = {
data() {
return {
tit: ["首页", "新手入门", "API", "关于", "注册", "登录"],
};
},
template: `
<div class="heads">
<div class="head-container">
<div class="lefthead">
<img src="https://static2.cnodejs.org/public/images/cnodejs_light.svg" alt="">
<input type="text">
</div>
<div class="righthead">
<ul>
<li v-for="(item,index) in tit" :key='index'>
{{item}}
</li>
</ul>
</div>
</div>
</div>
`,
};
const labs = {
data() {
return {
num: 0,
arrs: ["全部", "精华", "分享", "问答", "招聘", "客户端测试"],
};
},
template: `
<div class="labs">
<ul class="nav nav-tabs labsmenu">
<li role="presentation" @click="send(items,index)" :class="{menushow:num==index}" v-for="(items,index) in arrs " :key="items.id"><span>{{items}}</span></li>
</ul>
</div>
`,
methods: {
send(item,i) {
bus.$emit("send-name", item);
this.num=i
},
},
};
const lists = {
data() {
return {
items: [],
tab: "all",
time:"2022-07-27T06:03:34.611Z",
};
},
filters:{
fliterA(msg){
let times = new Date()
let tall=0
tall= Date.parse(times)
let msg1=0
msg1=Date.parse(msg)
var t=Math.floor((tall-msg1)/1000%60)
var min=Math.floor((tall-msg1)/1000/60)
var h=Math.floor((tall-msg1)/1000/60/60)
var day=Math.floor((tall-msg1)/1000/60/60/24)
var months=Math.floor((tall-msg1)/1000/60/60/24/30)
var year =Math.floor((tall-msg1)/1000/60/60/24/30/12)
if(h>24&&day<30){
msg= day + '天前'
}else if(h<24){
msg = h + '小时前'
}else if(day>30){
msg = months + '月前'
}
if(months>12){
msg = year + '年前'
}
if(min<60){
msg = min + '分钟前'
}
return msg
}
},
created() {
axios
.get("https://cnodejs.org/api/v1/topics", {
params: {
limit: 20,
},
})
.then((res) => {
this.items = [...res.data.data];
})
.catch((err) => {
console.log(err);
});
bus.$on("send-page", (data) => {
console.log(data);
this.getMonth(this.tab, data);
});
bus.$on("send-name", (data) => {
console.log(data);
this.tab =
data == "全部"
? "all"
: data == "精华"
? "good"
: data == "问答"
? "ask"
: data == "招聘"
? "job"
: data == "分享"
? "share"
: "dev";
this.getMonth(this.tab, 1);
});
},
template: `
<div class="lists">
<div class="list-group">
<div class="list-group-item lishe" v-for="(item,index) in items" :key="index">
<div class="lishe-left">
<div class="atpho">
<img :src="item.author.avatar_url" alt="">
</div>
<div class="atcount">
<span>{{item.reply_count}}/</span>
<span>{{item.visit_count}}</span>
</div>
<div v-show="item.good" class="attop">置顶</div>
<div v-show="!item.good" class="atshare">分享</div>
<p class="attit">{{item.title}}</p>
</div>
<div class="lishe-right">
<div>
<img :src="item.author.avatar_url" alt="">
<span>{{item.last_reply_at|fliterA}}</span>
</div>
</div>
</div>
</div>
</div>
`,
methods: {
getMonth(tab, page) {
this.items = [];
axios
.get("https://cnodejs.org/api/v1/topics", {
params: {
tab,
limit: 20,
page,
},
})
.then((res) => {
this.items = [...res.data.data];
})
.catch((err) => {
console.log(err);
});
},
},
};
const chose = {
template: `
<div class="chose">
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<li v-for="n in 5 " @click="send(n)"><span>{{n}}</span></li>
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
`,
methods: {
send(n) {
bus.$emit("send-page", n);
},
},
};
const fotters={
template:`
<div class="fotter">
<div class="fotter-container">
<ul class="fotter-menu">
<li>
<span>RSS</span>
|
<span>源码地址</span>
</li>
<li>CNode 社区为国内最专业的 Node.js 开源技术社区,致力于 Node.js 的技术研究。</li>
<li>
服务器搭建在
<img src=" https://static2.cnodejs.org/public/images/digitalocean.png" alt="">
,存储赞助商为
<img src="https://static2.cnodejs.org/public/images/qiniu.png" alt="">
</li>
<li>新手搭建 Node.js 服务器,推荐使用无需备案的 <a href="">DigitalOcean(https://www.digitalocean.com/)</a></li>
</ul>
</div>
</div>
`
}
Vue.component("labs", labs);
Vue.component("lists", lists);
Vue.component("chose", chose);
Vue.component("heads", heads);
Vue.component("fotters", fotters);
const vm=new Vue({
el: "#app",
});
</script>
</body>
</html>
body{
background: #e1e1e1;
}
.heads{
width: 100%;
height: 50px;
line-height: 50px;
background: #444444;
}
.head-container{
width: 1400px;
display: flex;
margin: auto;
justify-content: space-between;
}
.righthead ul{
display: flex;
}
.righthead ul li{
margin-right: 10px;
color: #ccc;
}
.lefthead{
display: flex;
height: 50px;
align-items: center;
}
.lefthead input{
margin-left: 20px;
width: 223px;
height: 26px;
background: #888888;
padding-left: 20px;
color: #fff;
border: 1px solid #888888;
border-radius: 10px;
}
.lefthead img{
width: 124px;
vertical-align: middle;
height: 36px;
}
.labs{
width: 1400px;
margin: 30px auto;
height: 40px;
margin-bottom: 0;
background-color: #f6f6f6;
}
.lists{
width: 1400px;
margin: auto;
min-height: 100vh;
}
.labsmenu{
height: 100%;
width: 100%;
padding-left: 10px;
display: flex;
align-items: center;
justify-content: flex-start;
}
.labsmenu li{
height: 26px;
cursor: pointer;
color: #80bd01;
padding: 2px 5px 2px 5px;
border-radius: 5px;
margin-right: 20px;
}
.menushow{
background: #80bd01;
color: #fff !important;
}
.home{
width: 1400px;
margin: auto;
}
.chose{
width: 1400px;
margin: auto;
cursor: pointer;
}
.lishe{
height: 50px;
padding-left: 5px;
display: flex;
align-items: center;
padding-left: 10px;
justify-content: space-between;
}
.lishe-left{
display: flex;
align-items: center;
}
.lishe-right img{
width: 18px;
height: 18px;
border-radius: 2px;
}
.lishe-right span{
font-size: 12px;
color: #778087;
margin-left: 10px;
}
p{
margin-bottom: 0;
}
.attop{
background: #80bd01;
padding: 1px 4px 0px 4px;
color: #fff;
border-radius: 3px;
margin-right: 5px;
font-size: 12px;
height: 20px;
}
.atshare{
background: #afb1aa;
padding: 1px 4px 0px 4px;
color: #fff;
border-radius: 3px;
margin-right: 5px;
font-size: 12px;
height: 20px;
}
.atcount{
margin-right: 10px;
}
.atcount>span:first-child{
font-size: 16px;
}
.atcount>span:last-child{
color: #afafaf;
}
.atpho{
margin-right: 10px;
}
.atpho img{
width: 30px;
height: 30px;
border-radius: 5px;
}
.attit{
font-size: 16px;
}
.fotter{
width: 100%;
background: #fff;
}
.fotter-container{
width: 90%;
max-width: 1400px;
min-width: 960px;
margin: 0 auto;
color: #bdb7b7;
padding: 20px 0;
font-size: 13px;
line-height: 2em;
}
.fotter-menu li:nth-child(1) span{
color: #666;
}