1、git 2、vue 3、js 4、css 6、html
一:git
1、解决移动手机端手机点击事件有300ms延迟方法:引入fastclick库,然后我们就可以没有顾忌的使用点击事件了,具体操作如下:
(1)打开项目终端对应gitbash界面,键入 npm install fastclick --save命令,运行即可,npm install fastclick意为把fastclick库安装到我们项目的依赖上,–save意为无论在开发环境中还是在打包生成的线上代码中都要使用fastclick库。
2.gitbash中control c可以退出当前运行环境
3、码云创建仓库,克隆/下载
(1)然后在项目目录的终端git bash,
(2)git init,这时候master会出现
(3) git remote add origin +克隆/下载那儿复制http地址,
(4)git pull origin master 命令,将码云上的仓库pull到本地文件夹
(5)git add .
git commit -m ‘操作名称’
git push origin master(只用git push会报错)
3.代码上传git仓库:
(1) git add :.将写的代码上传至本地缓存区
(2) git commit -m ‘project init’:其中git commit意为把缓存区代码提交到本地仓库, -m 'project init’意为备注一下这是一个project init(项目初始化)操作
(3)git push:将本地仓库代码传到线上
4、npm run start:重新启动项目
5、安装stylus到项目,要安装两个依赖:
(1)npm install stylus --save
(2)npm install stylus-loader --save
6、npm install [email protected] -g:安装制定版本的webpack
7.在公司级别的项目,每实现一个功能,都要再创建一个分支,在分支上进行代码的开发,开发完成后,分支上的代码就要合并到主分支master上。分支再线上创建完成后,在项目终端目录
(1)git pull:把分支拉到本地。
(2)git checkout 分支名:切换到新分支:git checkout branchName(到这你就可以开发写代码了)
(3)git status:显示工作目录和暂存区状态
8、创建新分支:git branch branchName
9、分支合并到master
(首先保证此刻是在刚开发代码的分支上,而不是在master或者其他分支上)
(1)git add .:到本地暂存区。
(2)git commit -m ‘change’:到本地仓库
(3)git push:到线上
(4)git checkout master;切换到我们要合并的master
(5) git merge origin/index-swiper:意为master要与线上分支index-swiper合并
(6)git push:合并后的代码推到线上
8、安装axios:npm install axios --sava
9、npm run start =npm run dev
10、如果现在git bush在index-ajax,而且index-ajax也没合并到master,我们可以用git merge index-recommend
来合并index-ajax和git merge index-recommend。
11、git merge:合并的意思
12、 git merge后,后悔怎么办?(摘取自https://www.cnblogs.com/princesong/p/7414880.html)
第一步:git checkout到你要恢复的那个分支上
1
1.git checkout develop
第二步:git reflog查出要回退到merge前的版本号
1
1. git reflog
第三步:git reset --hard [版本号]就回退到merge前的代码状态了
1
1.git reset --hard f82cfd2
至此回退代码的目标达成。
如果只是merge,但没有add,直接运行git merge --abort即可。
、
13、分支开发;
先在码云创建自己的分支,然后在git bash页面上操作
(1)git pull:从线上拉下代码到本地
(2)git checkout 分支名:切换到要开发的分支
(3)npm run dev:得到网址,然后到浏览器运行项目
14、怎么使用better-scroll?
要使用这个包,就要在控制台安装这个包,先关掉服务器,然后用
npm install better-scroll --save
12、提交了错误代码怎么办
https://blog.csdn.net/Java_HuiLong/article/details/86144055
https://www.cnblogs.com/chaoxiZ/p/9714085.html
二:vue
1.
home
列表页
2、为什么js中局部组件声明用的Homeheader,而这里用小写和横杠线的形式?因为vue中组件可以自动大小写关联,而且HTML中组件一般格式为小写和横杠线的形式
3、想要在Home.vue中使用局部组件,则要声明,并且js中也要用import导入对应的HomeHeader文件
export default {
name: 'Home',
//局部组件要使用就要声明
components:{
//es6中Homeheader相当于HomeHeader:HomeHeader
HomeHeader
}
}
4、在vue脚手架中些轮播图,使用vue-awesome-swiper插件。安装方法:
(1)npm install vue-awesome-swiper --save,最新版本有些小bug,所以我们做好安装2.6.7版本。所以命令为:npm install [email protected] --save
(2):插件安装好了以后,重启服务器(npm run start)
5、vue中请求数据使用ajax可以有很多种方式:
(1)浏览器中的fetch函数
(2)vue-resourse 这个第三方模块(vue以前推荐的)
(3)axios这个第三方模块(vue2017年推荐)
axios可以实现跨平台的请求,如在浏览器端可以帮助发送xhr请求,在node服务器端可以帮助发送http请求。本项目就用的axios请求ajax数据。
6、点击router-link包含的区域,都可以跳转到to指向的路径
{{this.city}}
router-link就是在区域外加了一个a标签,a标签默认#25a4bb这个颜色,所以有时候要在对应的样式更改颜色
补充:,这个意思就是回到根路径
7、template里只能包裹一个子组件
8、怎么实现组件的联动呢?(就是当点击字母区域,屏幕自动滚到响应区域) (1)比如我们在Alphabat组件中字母前绑定一个click事件,即@click=“handleLetterClick”,点击字母输出字母、 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190923144441864.png) 然后methods里handleLetterClick方法就写: handleLetterClick(e){//当点击事件发生后,会传一个事件e对象给方法 console.log(e.target.innerText)//就会输出你点击的字母,意为对象e的事件目标的文本 } (2)由于屏幕滚动对应区域是list组件,也就是我们要把e.target.innerText中的innerText传给Alphabat的兄弟组件list,兄弟组件传值可以用非父子组建的传值方式,也就是用总线的方式传值bus。就是Alphabat组件先值传给父组件City,再让父组件City把值传给子组件list 【1】子组件传值给父组件怎么传?(Alphabat----City) 在click事件的handleLetterClick方法中
handleLetterClick(e){
this.$emit("change",e.target.innerText)//调用this.emit()方法向外触发事件,事件名我们叫做change,事件携带的内容我们叫做e.target.innerText
console.log(e.target.innerText);//检测是否成功获取字母
}
子组件已经向外触发事件,则父组件要接受这个事件,就要在这个子组件上监听change事件
然后我们在父组件中定义方法handleLtterChange
handleLtterChange(letter){//这个方法可以接受到一个名为letter的参数,则letter的内容也就是前面的e.target.innerText
console.log(letter);
}
【2】父组件向子组件传值,(City—list)
我们常用data,然后在子组件上绑定数据,然后在子组件的props里注册,也就是父组件通过属性的形式传递
要把letter从City传给list,先在父组件里定义letter:‘’,再在方法中令this.letter=letter.
然后父组件在子组件上绑定letter,即:letter=“letter”,
然后子组件props里注册letter,即letter:String
【3】子组件已经接受到父组件传来的值了,当list.vue发现letter有改变的时候,我们就要让list中跟letter首字母相同的列表项显示出来,这里我们就要用到侦听器watch:{}来监听letter的变化,letter一旦变化就执行letter(){}中的代码
watch:{
letter () {//注意这里格式letter与括号之间有一个空格,括号后也有个空格
console.log(letter);
//BetterScroll提供我们这样一个接口,当this.letter不为空的时候我们可以调用this.scroll.scrollToElement()方法,它可以让BetterScroll滚动区自动滚动到某一个元素上
if(this.letter){
this.scroll.scrollToElement();
}
}
【4】我们给每一个div class=“area”的区域加一个ref,令:ref=“key”
有了这个ref,我们就可以在letter中写
const element = this.$refs[this.letter]//这样我们可以通过this.$refs[this.letter]获取到this.letter对应的class=“area”的区域
console.log(element);//打印这个数组
//但是我们不能直接就传入element 到this.scroll.scrollToElement,会报错,因为这里ref是通过v-for这样一个循环来输出的一个ref,所以输出的this.$refs[this.letter]是一个数组,而非DOM元素,或者DOM选择器,但是BetterScroll这个方法里面的参数必须是一个DOM元素,或者DOM选择器,怎么解决呢?在const element = this.$refs[this.letter]加个[0]就可获取到DOM元素,然后可以调用this.scroll.scrollToElement()方法了
const element = this.$refs[this.letter][0];
this.scroll.scrollToElement(element );
(3)上面实现了点击那个字母就去那个区域,对字母做上下拖拽的时候,区域也跟着变动
【1】首先做对Alphabat滚动事件的监听
绑定以下三个事件
我们希望只有在touchstart触发之后,touchmove才会触发,所以我们在data中绑定一个标识位touchStatus
下图代码就是说,当手指触摸的时候(即touchstart被触发时)touchStatus为true,当触摸结束时(touchend被触发时),touchStatus为false
【2】首先要知道你现在手指滑动的时候,页面是处于哪个字母要计算出来,
首先获得A字母距离顶部的高度,然后获得手指距离顶部的高度,二者差值除以每个字母高度就可以得出当前字母了。然后取这个字母触发change事件给web就可以啦!
【3】如果想要通过下标找到对应字母,我们就先用一个数组来储存这个字母列表。我们在计算属性computed中定义一个letters(){}返回一个字母数组
这个时候字母循环我们也可以直接用v-for=“item of letters”,字母部分用{{item}}
【4】开始写touchmove触发后的东西了、
首先计算A到顶部距离
让Alphabat中字母循环部分绑定一个:ref=“item”
然后用startY来记录A到顶部的高度,this.$refs[A][0}获取A对应的DOM元素,用offsetTop返回顶部高度
【5】计算触摸点到顶部高度
touchmove触发后悔传给handleTouchMove一个事件对象e,事件对象e里面呢,有一个touches[]数组,它的第0项就表示的我手指的一些信息。通过e.touches[0].clientY就可获取手指到做顶部的值
打印结果
我们就用最小打印结果减去顶部高度就是触点到绿沿高度43+36=79
(点击小箭头量高度)
二者差除以字母高度20取整得到是第几个字母
【6】如果index>=0,小于数组letters长度,向往触发change事件
10、列表性能的优化:
【1】在触摸时handleTouchMove都会被执行
【2】则offsetTop哪行代码会被执行多次;但是A标签的offsetTop一直都是固定的,每执行一次这个也会被重新计算一次,效率就会低
为优化这里,我们在data里定义startY:0,再写一个生命周期勾子updated(){},当页面完成数据更新且同时完成了页面渲染的时候,updated勾子就会执行,把offsetTop那行代码写在这里
##细说updated:当初次渲染Alphabat.vue时,用的什么渲染呢?打开City.vue中data我们可以看到,cities:{}是个空对象,所以页面刚加载的时候Alphabat中什么东西都不会显示出来。当City.vue用ajax获取到数据后cities的值才会有变化,Alphabat才会被渲染出来,当往Alphabat传的值有变化的时候,Alphabat这个组件才会重新渲染,当Alphabat重新渲染后,updated这个勾子才会被执行,这个时候已经展示出了城市列表所有内容。这个时候我们再去获取A所在的DOM对应的offsetTop的值
【2】第二步的性能优化:做一个函数节流
当鼠标在字母表来回移动的时候,move那个函数执行频率是非常高的。
【3】怎么做节流?
data中定义一个timer:null
然后在move那个函数里写
if(this.timer){//如果timer存在了,去除timer
clearTimerout(this.timer)
}
//如果不存在我们创建一个timer
this.timer=setTimeout(()=>{
},16)//()=>{}是一个箭头函数,函数的内容就是move函数需要执行的东西,16是指16ms的时间间隔
假设在这16ms期间,你又做了手指的滚动,那么他会把你上一次要做的操作给清除掉,重新执行你这一次要执行的东西,这样我们就可以节约handleTouchMove的执行频率,提高网页执行性能。
9、ref 有三种用法:源自,https://www.cnblogs.com/goloving/p/9404099.html
1、ref 加在普通的元素上,用this.ref.name 获取到的是dom元素
2、ref 加在子组件上,用this.ref.name 获取到的是组件实例,可以使用组件的所有方法。
3、如何利用 v-for 和 ref 获取一组数组或者dom 节点
注意:
1、ref 需要在dom渲染完成后才会有,在使用的时候确保dom已经渲染完成。比如在生命周期 mounted(){} 钩子中调用,或者在 this.$nextTick(()=>{}) 中调用。
2、如果ref 是循环出来的,有多个重名,那么ref的值会是一个数组 ,此时要拿到单个的ref 只需要循环就可以了。
10、在搜索框搜索北京或者拼音时,能够把结果显示出来
【1】在class=“search”的同层级加个div来显示搜索内容
然后v-model双向绑定input框中输入的内容。这个内容我们取名为keyword,并在data中定义。
然后search还要接受City传递的cities,记得要在search中props接收cities
【2】data中先写一个list:[],用它来存储有效的搜索
再写一个侦听器watch(){},来侦听keyword的改变,就是侦听器中写keyword(){},还要写一个节流函数在里面,所以data中timer:null别忘啦、
【3】节流函数
、【4】箭头函数里我们就写怎么得到有效结果
先定义一个const result = 【】,
再循环遍历cities,就是for(let i in this.cities){},
循环里面的内容就写this.cities[i].froEach(()=>{}),也就是把ABCD·····每一个键值对里面那个值,也就是那个数组再做一次遍历。
value有两个字段spell和name
这里的箭头函数写个(value)=>{
if(value.spell.indexOf(this.keyword)>-1 ||value.name.indexOf(this.keyword)>-1
//意为如果输入的关键字有匹配的spell或者name
result.push(value)//这样搜索结果存到了list里面
},最后让this.list=result,则list就存储了包含关键词的城市项目
【5】然后在列表做循环
【6】绿色部分意为给列表循环出的东西加一个下划线的边框
11、当输入a,你会发现结果页面不能滚动,这个可以通过BetterScroll来实现
【1】引入BetterScroll
【2】利用生命周期勾子mounted,在里面创建一个BetterScroll对象,并且创建时传入一个DOM选择器,这里我们search-content那个,令ref=“search”,则传入对象的就是this.$refs.search
【3】
到这里页面区域就可以正常滚动了。但是取消a后,结果列表还在,不会自动消失,这个时候我们在监听器watch里监听letter()中加个加个判断,如果keyword为空则list也为空就可以了
【4】当我们乱输入一串字母没有找到数据的时候,怎么弄呢?再加个
【3】首先安装VueX
【A】安装
npm install vuex --save
重启服务器进行开发
本来是要在main.js中 导入vueX,在通过Vue.use(VueX)显示安装vueX,但是这样不太好,因为我们后面做的vueX要做的文件夹比较复杂。我们就在【B】叙述
或者用全局安装
【B】在src中创建文件夹store,在其中创建文件index.js,在这个文件中引入vueX,在引入vueX后,使用new Vue.Store({})创建一个仓库,刚刚我们说了仓库三部分之一state:{}用于存储公共数据。这里存了个city:北京
然后在import中引入store中的index.js, url中只写到store,是因为store后的内容它会自己寻找。
并在根vue实例中把store传入进去,如果键值一样,就可以把store:store写成store
到这里可以重启服务器,到浏览器看看有没有报错,没有则说明vueX目前是没问题的
【C】怎么使用公共数据
首页header中可以使用这个数据
可见原来使用外部传值:city="city"的方式传值,现在不用了,直接去掉
以前city这个数据是通过后端然后ajax获取到的,但是现在不要了,我们要用前端的vueX,去掉data中的city,再去掉其他有关city的代码,还要去掉mock中index.json中的city;"北京”,以及header中原来用于引入city的props:{}也不要了
这时候页面上的北京就没有了,怎么让它显示出来,把原来显示北京的内容改为this. s t o r e . s t a t e . c i t y , 因 为 我 们 在 m a i n . j s 传 入 了 s t o r e , 所 以 其 他 组 件 都 可 以 直 接 t h i s . store.state.city,因为我们在main.js传入了store,所以其他组件都可以直接this. store.state.city,因为我们在main.js传入了store,所以其他组件都可以直接this.srore.state.数据名直接来用里面的数据
三:js
1、// 让home.vue也能使用HomeHeader.vue,js中写入
import HomeHeader from ‘./components/HomeHeader’
2、导出名为City的组件
四:css
1、移动手机端,1像素边框问题,就是在n倍屏中1像素的边框,实际为n px,可以用border.css解决(放在travel/src/style/border.css)
2、 lang="stylus“:既用stytus编写样式;scoped:保证只对header这个组件渲染,代码:
中导入stylus,用例如:@import ‘…/…/…/assets/styles/varibles.styl’:
(1)对于脚手架我们讲过@就相当于src,
A:在js中导入其他:
import ‘./assets/styles/border.css’ =import ‘@/assets/styles/border.css’
B:在css中导入其他:
@import ‘…/…/…/assets/styles/varibles.styl’=@import @/assets/styles/varibles.styl’,就是在js那种@之前加个
5、图片自动居中:
display:block
margin:0 auto
6、以下代码有点意思,它height 0,用padding-bottom: 54%,来表示高度实际为整个组件宽的54%
overflow: hidden
width: 100%
height: 0
padding-bottom: 54%
7、如何在字太多的时候显示、、、,在文本样式中添加下代码
overflow :hidden
white-space :nowrap
text-overflow ellipsis
如果项目中经常用到这个文件,我们可以单独创建一个文件来打包这个样式就会很方便,则stylus中的代码
ellipsis()
overflow :hidden
white-space :nowrap
text-overflow :ellipsis
然后在要用到的样式里导入这个stylus选项,并且在样式代码中写
ellipsis()
来调用这个打包的样式
8、一像素样式怎么引入。很简单,就在class里的样式名后加一个 border-bottom
、
9.router-link组件实际上是在外层加了一个a标签,但是a 标签默认#25a4bb这个颜色,记得修改
10、输入框内怎么让输入的文本和框边有一定的距离?
在input标签对应的样式中加
**box-sizing border-box
padding 0 .1rem**
11.设置边框样式
在样式名(这里是title)后面加border-topbottom,然后在单独对border-topbottom设置样式
.border-topbottom //意为border-topbottom这个类的before和after元素都设置成#ccc这个颜色,通过控制这个颜色,我们就控制了,页面上一像素边框的颜色,且页面上所有border-bottom和border-topbottom包含的边框颜色都是#ccc
&:before
border-color #ccc
&:after
border-color #ccc
12、在class后面加了borderbottom或者bordertopbottom,则对应的块就会有1像素边框(前提是引入了那个1像素边框的文档)
阿拉尔
13、overflow:hidden作用:当元素的内容溢出的时候,隐藏溢出内容
14、line-height是设置行高的,不能为负
15、以下代码让元素中超出的内容
隐藏,且不能页面拖动,怎么让页面能隐藏多余元素,又能拖动,我们可以使用better-scroll,better-scroll是is-scroll的封装,使用起来也比is-scroll更加友好。
overflow hidden
position absolute
16、怎么使用better-scroll?
(1)要使用这个包(在git Hub中搜索better-scroll就能找到这个包),就要在控制台安装这个包,先关掉服务器,然后用下命令安装
npm install better-scroll --save
(2)要我们的DOM中的html满足以下格式才可以,外面一层,里面再有一层,第二层包裹内容,里面是内容,内容可以是列表,也可以是多个div等等,第二层也可以是div来包裹内容
、
(3)
import BScroll from '@better-scroll/core' //引入better-scroll
let wrapper = document.querySelector('.wrapper') //dom 元素
let scroll = new BScroll(wrapper) //创建better-scroll实例,实例创建的时候要接受一个DOM元素或者DOM选择器
而对于我们这个项目具体做法就是在list.vue的script中先用 import Bscroll from ‘better-scroll’ 引入better-scroll,再在export里面写一个生命周期函数mounted(){},这个函数是在页面DOM挂载完毕后执行,函数里的内容就写一个名为scroll的better-scroll实例, this.scroll = new Bscroll(this. r e f s . w r a p p e r ) , 使 用 refs.wrapper), 使用 refs.wrapper),使用refs.DOM元素或者选择器的前提是:在BScroll能使用的格式最外层div要有ref,如本项目:
最终代码:
(4)在浏览器上拉页面试试效果,不仅可以拉,还带弹性。
五:html
1、ref作用可以帮我们获取DOM元素
六:webpack
1、webpack入门:https://segmentfault.com/a/1190000016777149
2、前面css.4讲了@=src,因为build—webpack.base.conf.js中有:
(1)
'@': resolve('src'),
意为@=src ;所以我们参见css.4总是用到styles,我们仿照源码添加一个:
'styles:resolve('scr/asset/styles')',
`(2)注意!!!!更改webpack.base.conf.js中代码后一定要重新运行服务器(npm run start),这样后js中这三句一样
import './assets/styles/border.css'
import '@/assets/styles/border.css'
import 'styles/border.css';
css中对应就是:
@import '../../../assets/styles/varibles.styl
@import ’~@/assets/styles/varibles.styl'
@import ’~styles/varibles.styl'
七:es
1、在es 5中,vue子组件绑定中,要在组件的data里面定义这个数据或者变量。我们知道子组件里定义data,data一定要是一个函数:
data: function(){
}
// 这是一个es5写法
es6中可以简化成:
data(){
}
我们知道data要返回一个数据,这个项目中是返回swiperoption,所以代码这么写,且放在export default{}中:
export default{
name:‘HomeSwiper’,
data(){
return {
swiperOption: {}
//初始化为空对象,什么都没有
}
}
}
八:问题
1、前面css 还有js导入用了简化后的就报错。但是头一天写本来不报错的。第二天导入那个vue-awesome-swiper插件后就报错,不知道为什么!!但是好像二者也没什么关系
九、ajax
1、这个项目我们请求一个ajax数据来传给其他各个组件就好了,所以我们就在home.vue里请求就可以了。
1、我们就住组件里的生命周期函数mounted来写ajax,mounted函数写在export default里,并且在这个界面axios才能写ajax请求:
import axios from 'axios'
然后我们使用axios,在mounted中引入this.getHomeInfo(),让页面挂载好了之后去执行 getHomeInfo()方法,:
mounted () {
this.getHomeInfo()
}
所以getHomeInfo()写在methods里面,getHomeInfo可以帮助我们获取ajax数据,我们采用axios.get(‘URL’)方法请求一个url,axios对象返回的是一个promise对象,所以我们用个.then(this.getHomeInfoSucc),所以methods中还该有一个方法
总的来说就是
(1)挂载完成后我们就去请求ajax数据
getHomeInfo(){
axios.get('/api/index.json')
}
(2)获取成功我们就打印出来
getHomeInfoSuccess(res){
console.log(res)
}
总的:
methods:{
getHomeInfo(){
axios.get('/static/mock/index.json').then(this.getHomeInfoSuccess)
},
getHomeInfoSuccess(res){
console.log(res);
}
},
mounted () {
this.getHomeInfo()
}
由于不存在’/api/index.json’这个文件。会报错
2、那如何在没有后端支持的时候,我们怎么进行数据模拟?
(1)static下建立index.json文件,并在文件中写上你想的内容:如hello world
(2)为什么要把数据写在static下?
因为整个脚手架目录只有static目录能被外部访问,
你可以试试在浏览器访问http://localhost:8080/static/index.json 结果如下:
但是换成static以外的路径,就直接显示主界面http://localhost:8080
(所以为了模拟后端数据,我们创建一个mock文件夹来保存类似index.json这样的模拟文件、数据)
(3)如果不想把static/mock的文件提交到线上,就在.gitignore文件添上static/mock
这样的话static/mock的文件也不会提交到本地仓库,更别说线上了
3、综上你好像以为我们可以直接写成 axios.get(’/static/mock/index.json’),这样是可以打印出来,也就是说ajax数据可以获取到了。(如图console那儿请求数据成功)
但是这样写的是本地模拟的一个地址,但是如果你的代码要上线千万别这样写,我们也不建议快上线了再挨个改URL为/api/index.json的形式。怎么办呢?vue提供了一个代理功能可以让对/api/index.json的请求转化到mock文件夹下。
做法:
(1)config下index.js文件中,我们可以看到官方文档下为我们提供了proxytable:{}这样的配置项
(2)如何配置
proxyTable: {
‘/api’:‘http://localhost:8080’,
pathRewrite:{
‘^/api’:’/static/mock’
}
},
意为
A:当我们请求api目录的时候,我们把请求转发到当前服务器 的8080端口上,只不过我们希望它把路径替换一下,’^/api’:’/static/mock’意为一旦请求api目录下的文件,我们就把/api转化为’/static/mock’路径下
(3)注意:这个功能不是vue提供的,是webpack- dev-server提供的,并且改动配置项要重启服务器
(4)补充,我们这个项目数据不可能是hello world,而是以下代码在index.json中
(1)“ret”: true,意为服务器正确响应
(2)data里是服务器响应的数据
{
"ret": true,
"data": {
"city":"北京",
"swiperList": [{
"id": "0001",
"imgUrl": "http://img1.qunarzz.com/piao/fusion/1801/1a/94428c6dea109402.jpg_640x200_2cf590d8.jpg"
},{
"id": "0002",
"imgUrl": "http://img1.qunarzz.com/piao/fusion/1802/42/7c92b9a381e46402.jpg_640x200_1cdce2a4.jpg"
},{
"id": "0003",
"imgUrl": "http://img1.qunarzz.com/piao/fusion/1802/51/e78f936a5b404102.jpg_640x200_c14f0b3a.jpg"
},{
"id": "0004",
"imgUrl": "http://img1.qunarzz.com/piao/fusion/1712/91/a275569091681d02.jpg_640x200_0519ccb9.jpg"
}],
"iconList": [{
"id": "0001",
"imgUrl": "http://img1.qunarzz.com/piao/fusion/1611/54/ace00878a52d9702.png",
"desc": "景点门票"
}, {
"id": "0002",
"imgUrl": "http://img1.qunarzz.com/piao/fusion/1711/df/86cbcfc533330d02.png",
"desc": "滑雪季"
}, {
"id": "0003",
"imgUrl": "http://img1.qunarzz.com/piao/fusion/1710/a6/83f636bd75ae6302.png",
"desc": "泡温泉"
}, {
"id": "0004",
"imgUrl": "http://img1.qunarzz.com/piao/fusion/1611/35/2640cab202c41b02.png",
"desc": "动植园"
}, {
"id": "0005",
"imgUrl": "http://img1.qunarzz.com/piao/fusion/1611/d0/e09575e66f4aa402.png",
"desc": "游乐园"
}, {
"id": "0006",
"imgUrl": "http://img1.qunarzz.com/piao/fusion/1611/59/569d3c096e542502.png",
"desc": "必游榜单"
}, {
"id": "0007",
"imgUrl": "http://img1.qunarzz.com/piao/fusion/1611/17/4bd370f3eb1acd02.png",
"desc": "演出"
}, {
"id": "0008",
"imgUrl": "http://img1.qunarzz.com/piao/fusion/1611/7f/b1ea3c8c7fb6db02.png",
"desc": "城市观光"
}, {
"id": "0009",
"imgUrl": "http://img1.qunarzz.com/piao/fusion/1611/a9/ffc620dbda9b9c02.png",
"desc": "一日游"
}],
"recommendList": [{
"id": "0001",
"imgUrl": "http://img1.qunarzz.com/sight/p0/1409/19/adca619faaab0898245dc4ec482b5722.jpg_140x140_80f63803.jpg",
"title": "故宫",
"desc": "东方宫殿建筑代表,世界宫殿建筑典范"
}, {
"id": "0002",
"imgUrl": "http://img1.qunarzz.com/sight/p0/1511/d2/d2aec2dfc5aa771290.water.jpg_140x140_abb362a7.jpg",
"title": "南山滑雪场",
"desc": "北京专业级滑雪圣地"
}, {
"id": "0003",
"imgUrl": "http://img1.qunarzz.com/sight/p0/1501/f4/f467729126949c3a.water.jpg_140x140_ef235b1c.jpg",
"title": "天安门广场",
"desc": "我爱北京天安门,天安门上太阳升"
}, {
"id": "0004",
"imgUrl": "http://img1.qunarzz.com/sight/p0/1501/40/40b2b6c951b28fdd.water.jpg_140x140_1c863e5c.jpg",
"title": "水立方",
"desc": "中国的荣耀,阳光下的晶莹水滴"
}, {
"id": "0005",
"imgUrl": "http://img1.qunarzz.com/sight/p0/201308/23/b283071686e64dfec8d65eac.jpg_140x140_8c5a7c49.jpg",
"title": "温都水城养生馆",
"desc": "各种亚热带植物掩映其间仿佛置身热带雨林"
}],
"weekendList": [{
"id": "0001",
"imgUrl": "http://img1.qunarzz.com/sight/source/1510/6e/1ea71e2f04e.jpg_r_640x214_aa6f091d.jpg",
"title": "北京温泉排行榜",
"desc": "细数北京温泉,温暖你的冬天"
}, {
"id": "0002",
"imgUrl": "http://img1.qunarzz.com/sight/source/1505/aa/7baaf8a851d221.jpg_r_640x214_1431200f.jpg",
"title": "北京必游TOP10",
"desc": "来北京必去的景点非这些地方莫属"
}, {
"id": "0003",
"imgUrl": "http://img1.qunarzz.com/sight/source/1505/9e/21df651e19af5d.jpg_r_640x214_3ea5bb38.jpg",
"title": "寻找北京的皇城范儿",
"desc": "数百年的宫廷庙宇,至今依旧威严霸气"
}, {
"id": "0004",
"imgUrl": "http://img1.qunarzz.com/sight/source/1505/ce/bc89bc2f0e33ea.jpg_r_640x214_3e408453.jpg",
"title": "学生最爱的博物馆",
"desc": "周末干嘛?北京很多博物馆已经免费开放啦"
}, {
"id": "0005",
"imgUrl": "http://img1.qunarzz.com/sight/source/1505/b2/fde1bfcd057a52.jpg_r_640x214_bbf3fa44.jpg",
"title": "儿童剧场,孩子的乐园",
"desc": "带宝贝观看演出,近距离体验艺术的无穷魅力"
}]
}
}
然后这个时候服务器就会响应正确的数据
(5)注意:index.json文件中数组最后一项别加逗号,list[{},{},{},],这个逗号可能会导致json文件解析失败,所以养成习惯千万别加这个逗号
5、如何用接收到的ajax数据,这里我们用首页父子组件传值来演示这个问题解答
(1)创建一个data保存我们成功获取到的res中的数据,如接收city这个值,默认给个空值,一定要记住data是返回一个值,所以是要return{}中放接收到的数据
data(){
return{
city:''
}
},
父组件给子组件传值是以属性形式传递,所以我们绑定到子组件上的, :city----意为绑定属性city,“city”—冒号中city是data中的city,:city=“city”—就是说绑定属性city值为data中的city
(2)子组件怎么接收这个city呢?
找到对应的子组件文件HomeHeader.vue的export default里创建一个props对象,对象中写
props:{
绑定属性名(是一个对象):接收数据的类型
}
//这个项目中示例
props:{
//对象city,类型String
city : String
}
然后在HomeHeader.vue对应地方写上this.city
这个时候城市就是默认的空值,只有一个下角符
(3)当ajax获取到数据以后呢(即前面提到的getHomeInfoSuccess(res){
console.log(res);
}这一步打印成功),我们要拿到数据的内容,怎么拿?
getHomeInfoSuccess(res){
//先让res=res.data,然后用if做个判断
res = res.data;
//如果后端正确返回了结果(res.ret)且res中有data项
if (res.ret && res.data){
//这句等价于this.city = res.data.city;,让该界面中得到data 里return{}里的city,不再为空值,而是我们获取到的数据res中data项中的data.city
const data = res.data;
this.city=data.city
}
console.log(res);
}
成功拿到
6、我们用类似5的方法来让子组件HomeSwiper接受它对应的swiperList,刷新结果如下
数据是有了,但是我们这有一个小问题,就是轮播图显示的是第四张图片,而不是第一张。怎么解决?
(1)为什么产生这个问题?(看到swiper.vue思考)这是因为当我们使用swiper组件的时候,也就是还没有获取ajax数据的时候,props里面接受的数据是home.vue中默认的swiperList是空数组。就是swiper最初创建时通过空数组创建的。在获取了ajax数据后,home.vue中swiperList变成真正的数据项,再传给了HomeSwiper的,home.vue中swiperList才能获得新的数据,然后重新渲染了新数据对应的幻灯片。因为swiper是根据空数组创建的,所以最容易出现刚才描述的问题,就是默认显示整个页面中最后一个页面
//Swiper.vue
(2)解决方法A,让初次创建swiper用我们完整的数据创建,而不是由空数组创建。在组件swiper上加v-if=“list.length”,即空数组时if=“list.length”=0,即为false,所以只有完整的数据才能创建swiper
解决方法B:之前提过模板中最好不要有v-if="list.length"这种逻辑性的代码。所以我们在data下面增加一个计算机属性
computed:{
showSwiper(){
return this.list.length
}
}
然后swiper里加v-if=“showSwiper”
7、怎么关掉home-icons这部分自动轮播?
在icon.vue中的swipers中加 :options=“swiperOption”
然后在data return{}中加swiperOption:{autoplay:false}
data () {
return {
swiperOption:{
autoplay:false
}
}
},
8、city-ajax
(1)ajax请求我们 一般放到最外层的组件上去做,这样一次ajax请求就可以让 所有组件获取到所需要的内容了。
(2)要用ajax,首先肯定要在City.vue中引入axios工具
import axios from 'axios'
然后在写一个生命周期函数mounted(){
},当然也可以用created函数,建议用mounted。mounted里面写一个方法的调用this.getCityInfo(),
这个方法定义在methods里面。这个方法要发一个axios请求
getCityinfo(){
axios.get(‘api/city.json’)//api/city.json请求的地址
.then(this.handleGetCityInfoSucc)//返回值为promise时,我们可以用,then()
},
//写个handleGetCityInfoSucc()方法与之对应,这个方法九合一接收到模拟数据的结果res,我们可以打印出这个结果
handleGetCityInfoSucc(res){
console.log(res);
}
写到这里大致是没问题,由于不存在api/city.json文件,所以会报错找不到文件。这里我们就可以好好看看ajax笔记中的第三点
(3)如图我们成功获取了cities,hotCitiesdeng数据
有了这些数据我们玩就可以做动态渲染了。怎么渲染?在city根组件里定义一组数据。这里我们需要两组数据,就return两组数据
data(){
return {
cities:{},
hotCities:[]
}
}
,数据ajax获取成功后,然后跟之前一样的方法拿数据
handleGetCitySuss(res){
//先让res=res.data,然后用if做个判断
res = res.data;
//如果后端正确返回了结果(res.ret)且res中有data项
if (res.ret && res.data){
//这句等价于this.city = res.data.city;,让该界面中得到data 里return{}里的city,不再为空值,而是我们获取到的数据res中data项中的data.city
const data = res.data;
this.cities=data.cities;//注意这里this.cities是指data中return{}里的cities,这个名字可以改成其他的,这个随return里的命名改动而带动。而data.cities的cities是指后端传来的数据名,这两个不一样
this.hotCities=data.hotCities;
}
}
然后把cities和hotCities先传给city-list这个组件,怎么传呢?
然后在子组件list接受一下这个数据,父组件向子组件传值,要通过props:{}来接收
hot是个数组类型,cities是个对象。有了这两组数据,我们就可以删除之前写死的html了,用循环来显示热门城市等等。
cities 是个对象,对象的循环方式来回忆一下
v-for=“(item,key)of cities”,key就是代表图示的A,B等对象序列
这里的父级循环的key值用cities中的key(即A、B、C···) 是可以的,因为他们都是不同的,即唯一的
前面只是循环了对象,针对红色区域,还要用一次对对象内部的二次循环
内层循环用v-for=“innerItem of item”,对象名字对应的值就是{{innerItem.name}}
它循环的key值为innerItem.id。
最后 ongoing相似的方法将字母传入Alphabat组件中