vue 组件传值之通讯录或地市选择和首字母排序组件代码
我是通过组件化的形式实现的父子组件传值,当中使用了vuex进行了数据共享最后合并成的城市组件<template><div id="app"><city-header:citylist=&am
·
我是通过组件化的形式实现的父子组件传值,当中使用了vuex进行了数据共享
设计稿
最后合并成的城市组件
<template>
<div id="app">
<city-header :citylist="ShowCityList"></city-header>
<section>
<city-list
:hot="HotCity"
:citylist="ShowCityList"
:letter="letter"
></city-list>
<city-alphabet :citylist="ShowCityList" @change="alphabetChange"></city-alphabet>
</section>
</div>
</template>
<script>
import CityHeader from "./components/CityHeader";
import CityList from "./components/CityList";
import CityAlphabet from "./components/CityAlphabet";
export default {
name: "City",
components: {CityAlphabet, CityList, CityHeader},
data(){
return{
CurrentCity:[],
HotCity:[],
ShowCityList:[],
letter:''
}
},
created(){
this.https.get("/api/city.json").then((res)=>{
res = res.data
if (res.ret && res.data) {
const data = res.data
this.HotCity = data.hotCities
this.ShowCityList = data.cities
}
})
},
methods:{
//接收字母的值并传递给list组件
alphabetChange(letter){
console.log(letter)
this.letter=letter
}
}
}
</script>
<style scoped>
section{
flex: 1;
}
</style>
头部搜索组件
<template>
<div class="header">
<div class="htop">
<a class="iconfont back-icon" @click="goBack"></a>
<h1>城市选择</h1>
</div>
<div class="hbottom">
<input type="text" v-model="keyword" placeholder="输入城市名或拼音"/>
</div>
<div
class="search-content"
ref="search"
v-show="keyword"
>
<ul>
<li
class="search-item border-bottom"
@click="CityClick(item.name)"
v-for="item of list"
:key="item.id"
>
{{item.name}}
</li>
<li class="search-item border-bottom" v-show="hasNoData">
没有找到匹配数据
</li>
</ul>
</div>
</div>
</template>
<script>
import BScroll from 'better-scroll'
import { mapMutations } from 'vuex'
export default {
name: "CityHeader",
props:{
citylist : ""
},
data(){
return{
keyword:"" ,//获取文本框的值
list:[],//声明个空数组用来存放搜索到的值
timer: null
}
},
created(){
},
methods:{
goBack(){
this.$router.push('/')
},
CityClick(city){
this.changeCity(city)
this.$router.push('/')
},
...mapMutations(["changeCity"])
},
computed: {
hasNoData () {
return !this.list.length
}
},
watch:{
keyword () {
if (this.timer) {
clearTimeout(this.timer)
}
if (!this.keyword) {
this.list = []
return
}
this.timer = setTimeout(() => {
const result = []
for (let i in this.citylist) {
this.citylist[i].forEach((value) => {
if (value.spell.indexOf(this.keyword) > -1 || value.name.indexOf(this.keyword) > -1) {
result.push(value)
}
})
}
this.list = result
}, 100)
}
},
mounted () {
this.scroll = new BScroll(this.$refs.search,{click:true})
}
}
</script>
<style lang="less" scoped>
.header{
width: 100%;
height: 2.135135rem;
background: #00bcd4;
.htop{ width: 100%;
height: 1.162162rem;
line-height: 1.162162rem;
color:#fff;
font-size: 16px;
text-align: center;
display: flex;
a{ display: block;
width: 5%;
height: 1.162162rem;
line-height: 1.162162rem;
text-align: center;
color:#fff;
}
h1{
width: 100%;
height: 1.162162rem;
line-height: 1.162162rem;
text-align: center;
}
}
.hbottom{
width: 100%;
height: 0.972972rem;
line-height: 0.972972rem;
text-align: center;
input{ width: 98%;
height: 0.7rem;
line-height: 0.7rem;
margin: 0.1rem;
text-align: center;
border-radius: 5.4px;
}
}
.search-content{
z-index: 1111111;
overflow: hidden;
position: absolute;
top: 2.1rem;
left: 0;
right: 0;
bottom: 0;
background: #eee;
.search-item{ line-height:0.62rem;
padding-left: 0.2rem;
background: #fff;
color: #666 }
}
}
</style>
头部下的列表组件
<template>
<div class="list" ref="wrapper">
<div class="main-list">
<div class="main-list-list">
<div class="main-list-top">
<div class="main-list-top-title">
当前城市
</div>
<div class="main-list-top-content">
<button
@click="CityClick(item.name)"
>{{this.city}}</button>
</div>
</div>
<div class="main-list-center">
<div class="main-list-center-title">
热门城市
</div>
<div class="main-list-center-content">
<button
v-for="item of hot"
:key="item.id"
@click="CityClick(item.name)"
>{{item.name}}</button>
</div>
</div>
<div class="main-content">
<div class="main-list-bottom" v-for="(item,key) of citylist" :key="key" :ref="key">
<div class="main-list-bottom-title">
{{key}}
</div>
<div class="main-list-bottom-content" v-for="val of item" :key="item.id" @click="CityClick(val.name)">
{{val.name}}
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import BScroll from 'better-scroll'
import {mapState,mapMutations} from 'vuex'
export default {
name: "CityList",
props:{
hot:Array,
citylist:"",
letter:String
},
data(){
return{
}
},
computed:{
...mapState(["city"])
},
methods:{
CityClick(city){
console.log(1)
this.changeCity(city)
this.$router.push('/')
},
...mapMutations(["changeCity"])
},
watch:{
letter(){
if(this.letter){
const element=this.$refs[this.letter][0]
// console.log(element)
this.scroll.scrollToElement(element)
// console.log(this)
}
}
},
mounted () {
this.scroll = new BScroll(this.$refs.wrapper,{click:true})
}
}
</script>
<style lang="less" scoped>
.list{
flex: 1;
width: 100%;
height: 15.837837rem;
overflow: hidden;
.main-list{ width: 100%;
display: flex;
flex-direction: column;
.main-list-top{ width: 100%;
height: 1.972972rem;
.main-list-top-title{ width: 97%;
height: 0.729729rem;
line-height: 0.729729rem;
font-size: 14px;
background: #EEEEEE;
color: #666;
padding-left: 0.3rem;
}
.main-list-top-content{
width: 97%;
height: 1.243243rem;
line-height: 1.243243rem;
background: #fff;
padding-left: 0.3rem;
button{ width: 2.783783rem;
height: 0.702702rem;
border: 1px solid #CCCCCC;
border-radius: 3.4px;
background: none;
margin-left: 0.2rem;
}
}
}
.main-list-center{
width:100%;
height: 2.216216rem;
.main-list-center-title{ width: 97%;
height: 0.729729rem;
line-height: 0.729729rem;
font-size: 14px;
background: #EEEEEE;
color: #666;
padding-left: 0.3rem;
}
.main-list-center-content{
width: 97%;
height: 2.216216rem;
line-height: 1.1rem;
background: #fff;
padding-left: 0.3rem;
button{ width: 2.783783rem;
height: 0.702702rem;
border: 1px solid #CCCCCC;
border-radius: 3.4px;
background: none;
margin-left: 0.2rem;
}
}
}
.main-content{
flex: 1;
margin-top: 28px;
.main-list-bottom{ .main-list-bottom-title{ width: 97%;
height: 0.729729rem;
line-height: 0.729729rem;
font-size: 14px;
background: #EEEEEE;
color: #666;
padding-left: 0.3rem;
}
.main-list-bottom-content{
width: 97%;
height: 1.027027rem;
line-height: 1.027027rem;
font-size: 14px;
background: #fff;
color: #666;
padding-left: 0.3rem;
border-top: 1px solid #ccc;
}
}
}
}
}
</style>
首字母渲染组件
<template>
<ul class="list">
<li
v-for="item of citylistArr"
:key="item"
:ref="item"
@click="handeClick"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend= "handleTouchEnd"
>{{item}}</li>
</ul>
</template>
<script>
export default {
name: "CityAlphabet",
props:{
citylist : ""
},
data(){
return{
bool:false,//表示位
starty:0,
timer:null
}
},
computed:{
//定义一个计算属性用于盛放传递过来的值
citylistArr(){
const newArr=[] //定义空数组并循环遍历
for (let i in this.citylist) {
newArr.push(i)
}
return newArr
}
},
updated(){
this.startY=this.$refs["A"][0].offsetTop
},
methods:{
handeClick(e){
this.$emit('change',e.target.innerText) //非父子组件传值
},
handleTouchStart(){
// 手指放上去
this.bool=true
},
handleTouchMove(e){
//在bool的判断为true的时候执行以下判断
if(this.bool) {
if(this.timer) {
clearInterval(this.timer)
}
//使用节流函数进行控制
this.timer = setTimeout(() => {
const touchY = e.touches[0].clientY -79//字母列表 到蓝色头部的距离
const index = Math.floor((touchY - this.startY ) / 20)
if(index >=0 && index < this.citylistArr.length) {
this.$emit('chang',this.citylistArr[index])
}
},16)
}
},
handleTouchEnd(){
// 手指离开
this.bool=false
}
}
}
</script>
<style scoped lang="less">
.list{
position: fixed;
top: 5rem;
width: 0.54054rem;
height: 15.891891rem;
text-align: center;
right: 0;
bottom: 0;
li{ width: 0.54054rem;
height: 0.54054rem;
line-height:0.54054rem;
text-align: center;
color: #25A4BB;
font-size: 16px;
}
}
</style>
效果图
更多推荐
已为社区贡献4条内容
所有评论(0)