使用Vue创建自己的通信录
效果展示
未使用vue脚手架的代码逻辑展示
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"/>
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style type="text/css">
* {
margin: 0px;
padding: 0px;
}
body{
/*height: 2000px;*/
}
#app{
position: relative;
}
ul{
list-style: none;
}
/*头部的样式=============================*/
#myheader{
width: 100%;
height: 50px;
line-height: 50px;
color: white;
background-color: grey;
font-size: 20px;
text-align: center;
position: fixed;
left: 0px;
top: 0px;
z-index: 10;
}
/*第一个button*/
#myheader>button:nth-of-type(1){
height: 100%;
padding: 5px 15px 5px 15px;
font-size: 20px;
float: left;
}
#myheader>button:nth-of-type(2){
height: 100%;
padding: 5px 15px 5px 15px;
font-size: 20px;
float: right;
}
/*列表的样式====================*/
#mylist{
width: 100%;
position: absolute;
left: 0px;
top: 50px;
}
/*每一组索引的样式*/
.indexChar{
height: 50px;
line-height: 50px;
width: 100%;
background-color: #cccccc;
font-size: 20px;
text-indent: 10px;
border-bottom: 1px solid grey;
}
/*+号是兄弟选择器 >号是子选择器*/
/*每一个联系人的样式*/
.indexChar+ul>li{
height: 80px;
line-height: 80px;
width: 100%;
background-color: white;
font-size: 20px;
border-bottom: 1px solid grey;
}
.divHead{
width: 50px;
height: 50px;
border-radius: 50%;
border: 5px solid grey;
float: left;
margin: 5px 10px 5px 10px;
}
/*male图像*/
.male{
background: url("./imgs/male.jpg") 0 0 no-repeat;
background-size: contain;
}
/*女生图像*/
.female{
background: url("./imgs/female.jpg") 0 0 no-repeat;
background-size: contain;
}
.allChars{
width: 40px;
/*background-color: pink;*/
position: fixed;
font-size: 24px;
right: 5px;
top: 0px;
}
/*消息框的样式=====================*/
#mymsgbox{
width: 100%;
height: 2000px;
position: fixed;
top: 0px;
left: 0px;
background-color: rgba(0,0,0,0.5);
z-index: 20;
}
.content{
width: 80%;
height: 400px;
background-color: white;
border-radius: 10px;
margin: 80px auto;
}
.content>div:nth-of-type(1){
height: 15%;
line-height: 62px;
width: 100%;
border: 1px solid gray;
text-align: center;
font-size: 20px;
}
.content>div:nth-of-type(2){
height: 68%;
width: 100%;
border: 1px solid gray;
text-align: center;
font-size: 20px;
}
.content>div:nth-of-type(3){
height: 15%;
line-height: 62px;
width: 100%;
text-align: center;
font-size: 20px;
}
.content>div button{
font-size: 20px;
padding: 5px 15px 5px 15px;
}
.msghead{
width: 80px;
height: 80px;
border-radius: 50%;
border: 5px solid gray;
margin: 10px auto ;
animation: rotHead 5s linear infinite;
}
@keyframes rotHead {
0%{
transform: rotate(0deg);
}
100%{
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<div id="app">
<myheader :data-vue="dataVue"></myheader>
<mylist :persons="persons"></mylist>
</div>
<template id="myheader-tem">
<div id="myheader">
<button @click="backClick">返回</button>
{{dataVue.titleName}}
<button @click="homeClick">主页</button>
</div>
</template>
<template id="mylist-tem">
<div id="mylist">
<div>
<ul>
<li v-for="item in persons">
<div class="indexChar">{{item.index}}</div>
<ul>
<li @click="nameClick(it)" v-for="it in item.group1">
<div :class="it.sex == 'male'?'divHead male':'divHead female'"></div>
<div>{{it.name}}</div>
</li>
</ul>
</li>
</ul>
</div>
<div class="allChars" ref="allChars">
<ul>
<li v-for="item in persons" @click="clickIndex(item.index)">{{item.index}}</li>
<!-- 另一种方式<li v-for="item in allIndex" @click="clickIndex(item)">{{item}}</li> -->
</ul>
</div>
</div>
</template>
<template id="mymsgbox-tem">
<div id="mymsgbox" ref="mymsgbox">
<div class="content">
<div>通话</div>
<div>
<div :class="sex=='male' ? 'msghead male' : 'msghead female'"></div>
<div>
姓名:{{name}}<br/>
号码:{{phone}}
</div>
</div>
<div>
<button @click="callClick">呼叫</button>
<button @click="cancelClick">取消</button>
</div>
</div>
</div>
</template>
<script type="text/javascript">
var dataOut = {
titleName:"通讯录"
}
var persons = [{index:"A",group1:[
{name:"A雪风1",phone:"14785624492",sex:"male"},
{name:"A雪风2",phone:"14892248314",sex:"female"},
{name:"A雪风3",phone:"12548796531",sex:"male"}]},
{index:"B",group1:[
{name:"B雪风1",phone:"85294511235",sex:"female"},
{name:"B雪风2",phone:"78452361232",sex:"male"},
{name:"B雪风3",phone:"89587131317",sex:"female"}]},
{index:"C",group1:[
{name:"C雪风1",phone:"12548351737",sex:"female"},
{name:"C雪风2",phone:"14896213515",sex:"female"},
{name:"C雪风3",phone:"12565951384",sex:"male"}]},
{index:"D",group1:[
{name:"D雪风1",phone:"14434354375",sex:"male"},
{name:"D雪风2",phone:"13592535155",sex:"female"},
{name:"D雪风3",phone:"15343951384",sex:"female"}]},
]
// var emptyvue = new Vue();
//编写一个js组件
var mymsgbox = (function () {
var MyVue = Vue.extend({
template:"#mymsgbox-tem"
});
return function (params){
//创建新的div
var divNew = document.createElement("div");
//将div加入文档的最后
document.body.appendChild(divNew);
var msgVue = new MyVue({
el:divNew,
data:function () {
return{
name:params.name,
phone:params.phone,
sex:params.sex,
callClick:params.callClick,
cancelClick:params.cancelClick
}
}
});
}
})();
var app = new Vue({
el: "#app",
data: {
dataVue:dataOut,
persons:persons
},
components: {
myheader:{
template: "#myheader-tem",
props:["dataVue"],
methods:{
backClick:function (ev) {
alert("返回按钮被点击");
},
homeClick:function (ev) {
alert("主页按钮被点击");
}
}
},
mylist:{
template: "#mylist-tem",
props: {
persons:{
type:Array,
default:[]
}
},
computed:{
allIndex : function (){
var list = [];
for (var i =0 ; i<this.persons.length;i++){
list.push(this.persons[i].index);
}
return list;
}
},
methods:{
clickIndex:function (item) {
var divs = document.getElementsByClassName("indexChar");
for(var i = 0;i<divs.length;i++){
if(divs[i].innerText == item){
var topvalue = divs[i].offsetTop;
document.body.scrollTop = topvalue;
//解决浏览器兼容问题
if(document.body.scrollTop == 0){
document.documentElement.scrollTop = topvalue;
}
break;
}
}
},
nameClick:function (it) {
mymsgbox({
name:it.name,
phone:it.phone,
sex:it.sex,
callClick:function (ev) {
alert("打电话给"+this.name
+"\r\n号码是"+this.phone);
},
cancelClick:function (ev) {
var div = document.getElementById("mymsgbox");
document.body.removeChild(div);
}
});
// emptyvue.$emit("showMsg",it);
}
},
mounted:function () {
var winHeight = window.innerHeight;
var divHeight = this.$refs.allChars.offsetHeight;
var half = (winHeight-50-divHeight)/2;
this.$refs.allChars.style.marginTop = (half + 50)+'px';
}
},
// mymsgbox:{
// template:"#mymsgbox-tem",
// data:function (){
// return {
// name:"姓名",
// phone:"号码",
// sex:"male"
// }
// },
// mounted:function () {
// emptyvue.$on("showMsg",function (it){
// this.name = it.name;
// this.phone = it.phone;
// this.sex = it.sex;
// this.$refs.mymsgbox.style.display = "block";
// }.bind(this));
// },
// methods: {
// callClick:function (ev) {
// alert("打电话给"+this.name
// +"\r\n号码是"+this.phone);
// },
// cancelClick:function (ev) {
// this.$refs.mymsgbox.style.display = "none";
// }
// }
// }
}
})
</script>
</body>
</html>
安装vue脚手架
在WebstormProjects(专门放Webstorm工程文件夹)里创建一个新的文件VueWebpack
在安装Node.js前提下,使用管理员身份启动cmd窗口,并进入VueWebpack这个文件夹下,依次按照下图所示输入四个命令
成功之后,会生成一个文件夹,这个文件夹就是vue工程的原始模板,我们只需复制这个文件夹到我们新的工程中并重新命名就是一个新的vue工程
整合后的通讯录脚手架
main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import MyHeader from './components/MyHeader.vue'
import MyList from './components/MyList.vue'
Vue.config.productionTip = false
Vue.component(MyHeader.name,MyHeader)
Vue.component(MyList.name,MyList)
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
App.vue
<template>
<div id="app">
<myheader :data-vue="dataVue"></myheader>
<mylist :persons="persons"></mylist>
</div>
</template>
<script>
var dataOut = {
titleName:"通信录"
}
var persons = [{index:"A",group1:[
{name:"A张三1",phone:"18911111111",sex:"male"},
{name:"A张三2",phone:"18922222222",sex:"female"},
{name:"A张三3",phone:"18933333333",sex:"male"}]},
{index:"B",group1:[
{name:"B张三1",phone:"13911111111",sex:"male"},
{name:"B张三2",phone:"13922222222",sex:"female"},
{name:"B张三3",phone:"13933333333",sex:"female"}]},
{index:"C",group1:[
{name:"C张三1",phone:"17911111111",sex:"female"},
{name:"C张三2",phone:"17922222222",sex:"female"},
{name:"C张三3",phone:"17933333333",sex:"male"}]},
{index:"D",group1:[
{name:"D张三1",phone:"12911111111",sex:"male"},
{name:"D张三2",phone:"12922222222",sex:"male"},
{name:"D张三3",phone:"12933333333",sex:"female"}]},
]
export default {
name: 'App',
data: function () {
return {
dataVue:dataOut,
persons:persons
}
},
}
</script>
<style>
* {
margin: 0px;
padding: 0px;
}
ul{
list-style: none;
}
#app{
position: relative;
}
</style>
在assets下加入所需的图片
female.jpg
male.jpg
components文件夹
MyHeader.vue
<template>
<div id="myheader">
<button @click="backClick">返回</button>
{{dataVue.titleName}}
<button @click="homeClick">主页</button>
</div>
</template>
<script>
export default {
name: 'myheader',
props:["dataVue"],
methods:{
backClick: function (ev) {
alert("返回按钮被点击");
},
homeClick: function (ev) {
alert("主页按钮被点击");
},
}
}
</script>
<style>
/* 头部组件的样式=================================================*/
#myheader{
width:100%;
height:50px;
line-height:50px;
color:white;
background-color: grey;
font-size: 20px;
text-align: center;
position: fixed;
left: 0px;
top:0px;
z-index:10;
}
#myheader>button:nth-of-type(1){
height:100%;
padding: 5px 15px 5px 15px;
font-size: 20px;
float:left;
}
#myheader>button:nth-of-type(2){
height:100%;
padding: 5px 15px 5px 15px;
font-size: 20px;
float:right;
}
</style>
MyList.vue
<template>
<div id="mylist">
<div>
<ul>
<li v-for="item in persons">
<div class="indexChar">{{item.index}}</div>
<ul>
<li @click="nameClick(it)" v-for="it in item.group1">
<div :class="it.sex=='male'?'divHead male':'divHead female'"></div>
<div>{{it.name}}</div>
</li>
</ul>
</li>
</ul>
</div>
<div class="allChars" ref="allChars">
<ul>
<li v-for="item in allIndex" @click="clickIdx(item)">{{item}}</li>
</ul>
</div>
</div>
</template>
<script>
import mymsgbox from './MyMsgBox.js'
export default {
name: 'mylist',
props:{
persons:{
type:Array,
default:[]
}
},
computed:{
allIndex : function () {
var list = [];
for(var i = 0; i < this.persons.length; i++){
list.push(this.persons[i].index);
}
return list;
}
},
methods:{
clickIdx:function(item){
var divs = document.getElementsByClassName("indexChar");
for(var i = 0; i < divs.length; i++){
if(divs[i].innerText == item){
var topvalue = divs[i].offsetTop;
document.body.scrollTop = topvalue;
// 兼容浏览器
if(document.body.scrollTop == 0){
document.documentElement.scrollTop = topvalue;
}
break;
}
}
},
nameClick:function(it){
mymsgbox({
name:it.name,
phone:it.phone,
sex:it.sex,
callClick: function (ev) {
alert("打电话给" + it.name
+ "\r\n号码是:" + it.phone);
},
cancelClick: function (ev) {
var div = document.getElementById("mymsgbox")
document.body.removeChild(div)
},
});
}
},
mounted: function () {
var winHeight = window.innerHeight;
var divHeight = this.$refs.allChars.offsetHeight;
var half = (winHeight - 50 - divHeight) / 2;
this.$refs.allChars.style.marginTop = (half + 50) + 'px';
}
}
</script>
<style>
/* 列表的样式=================================================*/
#mylist{
width:100%;
position: absolute;
left: 0px;
top:50px;
}
/*每一组索引的样式*/
.indexChar{
height: 50px;
line-height: 50px;
width: 100%;
background-color: #cccccc;
font-size: 20px;
text-indent: 10px;
border-bottom: 1px solid grey;
}
/*每一个联系人的样式*/
.indexChar+ul>li{
height: 80px;
line-height: 80px;
width: 100%;
background-color: white;
font-size: 20px;
border-bottom: 1px solid grey;
}
.divHead{
width:50px;
height: 50px;
border-radius:50% ;
border: 5px solid gray;
float: left;
margin: 9px 10px 5px 10px;
}
/*男生头像*/
.male{
background: url("../assets/male.jpg") 0 0 no-repeat;
background-size: contain;
}
/*女生头像*/
.female{
background: url("../assets/female.jpg") 0 0 no-repeat;
background-size: contain;
}
.allChars{
width:40px;
/*background-color: pink;*/
position: fixed;
font-size: 24px;
right:5px;
top:0px;
}
</style>
MyMsgBox.vue
<template>
<div id="mymsgbox" ref="mymsgbox">
<div class="content">
<div>通话</div>
<div>
<div :class="sex='male'?'msghead male':'msghead female'"></div>
<div>
姓名:{{name}} <br/>
号码:{{phone}}
</div>
</div>
<div>
<button @click="callClick">呼叫</button>
<button @click="cancelClick">取消</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'mymsgbox',
}
</script>
<style>
/* 消息框的样式=================================================*/
#mymsgbox{
width:100%;
height:2000px;
position: fixed;
top:0px;
left:0px;
background-color: rgba(0,0,0,0.5);
z-index:20;
}
.content{
width:80%;
height:400px;
background-color: white;
border-radius: 10px;
margin: 80px auto;
}
.content>div:nth-of-type(1){
height: 15%;
line-height: 62px;
width: 100%;
border: 1px solid gray;
text-align: center;
font-size: 26px;
}
.content>div:nth-of-type(2){
height: 68%;
width: 100%;
border: 1px solid gray;
text-align: center;
font-size: 20px;
}
.content>div:nth-of-type(3){
height: 15%;
line-height: 62px;
width: 100%;
text-align: center;
font-size: 20px;
}
.content>div button{
font-size: 20px;
padding: 5px 15px 5px 15px;
}
.msghead{
width: 80px;
height: 80px;
border-radius: 50%;
border: 5px solid gray;
margin:10px auto;
animation: rotHead 5s linear infinite;
}
@keyframes rotHead {
0%{
transform: rotate(0deg);
}
100%{
transform: rotate(360deg);
}
}
</style>
MyMsgBox.js
import Vue from 'vue'
import MyMsgBox from './MyMsgBox.vue'
// 编写一个js组件
var mymsgbox = (function () {
var MyVue = Vue.extend(MyMsgBox);
return function (params) {
// 创建新div
var divNew = document.createElement("div");
// 把新div加入到文档的最后
document.body.appendChild(divNew);
var msgVue = new MyVue({
el:divNew,
data: function () {
return {
name:params.name,
phone:params.phone,
sex:params.sex,
callClick:params.callClick,
cancelClick:params.cancelClick
}
}
});
}
})();
export default mymsgbox