Vue项目核心要点总结

Vue核心要点理解

Vue性能操作

  • computed计算属性的缓存和methods,watch
  • v-if和v-show
  • :key 解决唯一性,循环遍历的时候最好用数据的id,而不是下标
  • 使用v-once来提高动态组件之间的切换,是组件第一次渲染之后放在内存中,后面操作直接调用,提高性能
  • 函数节流
  • 使用keep-alive结合钩子函数activated进行页面性能优化

Vue的数据传递

  • 父传子 通过v-bind:传递,子组件通过props接收
  • 子传父 子组件通过$emit发送事件,父组件通过v-on监听事件
  • 非父子 通过bus/发布订阅/总线机制来传递,或者使用vuex传递
  • 父传子可以通过slot插槽传递数据

MVVM和MVC

  1. MVVM:M表示数据model,是获取到的数据。V表示视图view,是展示的界面。VM表示视图模型,用来连接model和view,是vue底层自动实现,不需要认为操作。MVVM是数据驱动的。
  2. MVC: M表示数据model,是从后台用ajax获取到的数据。V表示视图层view,是前端渲染的页面。C表示控制器controler,用来将获取到的数据使用dom操作来更新页面,VMMC中数据和操作dom是混合的,controler控制器部分比较庞大,比如原始的jquery就是MVC模式。

虚拟DOM和Object的defineProperties

前端的组件化

父子组件之间的传值

  1. 父传子
    • 使用v-bind:属性名=变量值传递
    • 使用props: [属性名]接收
  2. 子传父
    • 子组件通过事件使用this.$emit(事件名,数据)发送事件和数据
    • 父组件通过v-on:事件名="父组件事件"监听并接收传递过来的数据

Vue的实例

vue的每一个组件都是一个vue的实例。

vue的项目都是用多个vue实例拼装而成的。

Vue的生命周期

生命周期函数就是vue实例在某个事件点会自动执行的函数

beforeCreate: 在此之前只有默认的一些事件和生命周期钩子函数

created: 在此过程中,data和methods都已经被初始化好了,最早可以在created中操作方法和数据

beforeMount: 表示模板已经在内存中编译完成了,但是尚未渲染到页面中,页面中的元素还没有替换过来,还是之前的模板字符串,页面数据还未编译到模板template中

mounted: 内存中的模板已经挂在到了页面中,实例已经被完全创建好了

beforeUpdate: 页面中的数据被更新了,此时data中的数据是最新的,页面尚未和最新的数据保持同步。

updated: 更新之后,页面和data中的数据保持同步,都是最新的。

beforeDestroy: 当调用了vm.$destroy()函数的时候触发

destroyed: 当vue实例被销毁的时候触发

计算属性

计算属性是基于它们的依赖进行缓存的,如果依赖的值没有发生改变,计算属性也不会执行

相对于watch监听和方法来说,同样的功能,计算属性相对来说比较简单而且有缓存

计算属性默认调用的是get,还可以设置set.

watch监听,和compute计算属性类似,也具有缓存。只有依赖发生改变时候才会触发,但是写法比较麻烦

get,set的使用

样式绑定

class

  1. 对象绑定

    :class={类名:变量}

  2. 数组绑定

    :class=[变量]

style

  1. 对象绑定

    :style={变量}

  2. 数组绑定

    :style=[变量]

iff算法

条件渲染

v-if: 每一次都会删除和添加dom,性能不好

v-show: 经常操作的可以使用v-show,性能好

问题:

# 解决vue的复用问题,在不添加key的时候,当切换显示和隐藏时候,vue会复用文本框,里面内容也不会改变,解决办法就是给元素加一个key就可以使之唯一,vue就会重新渲染。
<div id="app">
    <div v-if="isShow">
   		 用户名:<input type="text" key="username">
    </div>
    <div v-else>
   		 密码:<input type="password" key="password">
    </div>
</div>
<script>
var vm = new Vue({
    el: '#app',
    data: {
    	isShow: true,
    }
})
</script>

vue数组的变异方法

Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新。这些方法如下

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

改变数组内容的方法:变异方法和引用(list = [])、set方法(Vue.set(vm.userInfo,1,5))

改变对象内容的方法:引用(obj = {})、set方法(vm.$set(vm.userInfo,‘address’,‘beijing’))

template标签的使用

用来占位,包裹一些元素,但是不显示

使用is解决组件模板标签的bug问题

	<div id="box">
		<table>
			<tbody>
				<!-- <row></row> -->
				<tr is="row"></tr>
                <Ul>
                    <li is="row"></li>
                </Ul>
			</tbody>
		</table>
	</div>
	<script>
		Vue.component('row', {
			template: '<tr><td>this is a row</td></tr>'
		})
		var vm = new Vue({
			el: '#box'
		})
	</script>

子组件中定义data必须是函数

<div id="box">
		<table>
			<tbody>
				<tr is="row"></tr>
			</tbody>
		</table>
	</div>
	<script>
		Vue.component('row', {
			data: function(){
				return {
					content: 'this is a row'
				}
			},
			template: '<tr><td>{{content}}</td></tr>'
		})
		var vm = new Vue({
			el: '#box'
		})
	</script>
# 作用:是为了让每个可复用的组件拥有自己的独立数据

使用ref来获取dom

# 在html元素上的ref可以获取dom
<div id="box">
		<div ref="hello" @click="handleClick">hello world</div>
	</div>
	<script>
		var vm = new Vue({
			el: '#box',
			methods: {
				handleClick: function(){
					alert(this.$refs.hello.innerHTML)
				}
			}
		})
	</script>
# 使用发布订阅的方式,在组件上的ref可以获取该组件的引用
<div id="box">
		<counter ref="one" @change="handleChange"></counter>
		<counter ref="two" @change="handleChange"></counter>
		<div>{{total}}</div>
	</div>
	<script>
		Vue.component('counter', {
			template: '<div @click="handleClick">{{number}}</div>',
			data: function(){
				return {
					number: 0
				}
			},
			methods: {
				handleClick: function(){
					this.number ++
					this.$emit('change')
				}
			}
		})
		var vm = new Vue({
			el: '#box',
			data: {
				total: 0
			},
			methods: {
				handleChange: function(){
					this.total = this.$refs.one.number + this.$refs.two.number
					console.log(this.$refs.one)
				}
			}
		})
	</script>

父子组件之间的数据传递

vue中的单项数据流,只允许父组件向子组件传递数据,不允许子组件改变父组件传递过来的数据。如果需要修改父组件传递过来的数据,则可以将传递过来的数据保存为自己的变量,然后做更改。

组件参数校验

props: {
    content: String,
    age: Number,
    id: [Number, String],
    address: {
		type: String,
         required: true,
         default: 'default value',
         validator: function(value){
            return value.length > 5
         }
    }
}

非props属性

  • 非props特性:当父组件向子组件传递数据时候,子组件并没有用props接收;在子组件中无法使用
  • 非props特性传递给子组件的属性及属性值会显示到dom中html的属性中

给组件绑定原生事件

在组件上绑定事件的时候,这个事件是属于监听事件,而不是原生事件。因此当点击时候不会触发。如果需要触发,有以下两种操作:

  • 通过子组件使用事件$.emit(‘事件名’),发送一个事件,然后父组件监听@事件名='自己的事件’来触发
  • 通过事件修饰符,只需要在子组件上定义的事件后面加上一个.native.@click.native="chandleClick"

非父子组件间的传值

通过(Bus/总线/发布订阅模式/观察者模式)

  1. 非父子组件之间数据传递的方式
    • 逐层传递
    • 使用Vuex
    • 使用发布订阅模式总线机制传递
    <div id="box">
        <child content="Dell"></child>
        <child content="Lee"></child>
    </div>
    <script>
        Vue.prototype.bus = new Vue()

        Vue.component('child', {
            props: {
                content: String
            },
            data: function() {
                return {
                    selfContent: this.content
                }
            },
            template: '<div @click="handleClick">{{selfContent}}</div>',
            methods: {
                handleClick: function() {
                    this.bus.$emit('change', this.selfContent)
                }
            },
            mounted: function() {
                var that = this
                this.bus.$on('change', function(msg) {
                    that.selfContent = msg
                })
            }
        })

        var vm = new Vue({
            el: '#box'
        })
    </script>

Vue中的插槽

在vue中,父组件向子组件传递数据的时候,通过绑定属性向子组件传递,子组件通过props来接收

通过插槽的方式可以批量的在子组件内部传递数据,然后通过slot来接收,并且可以接收具名slot内容。

    <div id="box">
        <body-content>
            <div slot="header">header</div>
            <div slot="footer">footer</div>
        </body-content>
    </div>

    <script>
        Vue.component('body-content', {
            template: `
                <div>
                    <slot name="header"></slot>
                    <div>content</div>
                    <slot name="footer"></slot>
                </div>
            `
        })

        var vm = new Vue({
            el: '#box'
        })
    </script>

Vue中的作用域插槽

    <div id="box">
        <child>
            <template slot-scope="props">
                <h1>{{props.item}} - hello</h1>
            </template>
        </child>
    </div>
    <script>
        Vue.component('child', {
            data: function() {
                return {
                    list: [1, 2, 3, 4]
                }
            },
            template: `
                <div>
                    <ul>
                        <slot v-for="item of list" :item='item'>
                                
                        </slot>   
                    </ul>    
                </div>
            `
        })

        var vm = new Vue({
            el: '#box'
        })
    </script>

动态组件

    <div id="box">
        <component :is="type"></component>
        <!-- <child-one></child-one>
        <child-two></child-two> -->
        <button @click="handleBtnClick">动态组件</button>
    </div>

    <script>
        // v-once 减少性能的消耗
        Vue.component('child-one', {
            template: '<div v-once>child one</div>'
        })

        Vue.component('child-two', {
            template: '<div v-once>child two</div>'
        })

        var vm = new Vue({
            el: '#box',
            data: {
                type: 'child-one'
            },
            methods: {
                handleBtnClick: function() {
                    this.type = this.type === "child-one" ? "child-two" : "child-one";
                }
            }
        })
    </script>

在Vue中 使用animate.css库

<div id="box">
        <transition enter-active-class="animated swing" leave-active-class="animated shake" appear appear-active-class="animated shake">
            <div v-if="show">hello world</div>
        </transition>
        <button @click="handleClick">切换</button>
</div>

在Vue中同时使用过渡和动画

<style>
    .fade-enter, .fade-leave-to {
        opacity: 0
    }
    .fade-enter-active, .fade-leave-active {
        transition: opacity 1s
    }
</style>
<transition
    type=""
    :duration="{enter: 5000, leave: 10000}"
    name: "fade"
    appear
    enter-active-class="animated swing fade-enter-active"
    leave-active-class="animated shake fade-leave-active"
    appear-active-class="animated swing"
>
	<div v-show="show">
        hello world
    </div>
</transition>

Vue动画中属性声明javascript钩子

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"

  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>

Vue中使用Velocity.js

中文文档:http://www.mrfront.com/docs/velocity.js/index.html

Vue中多个元素/组件的过渡和动画

vue中的dom的复用,导致动画不会出现,需要添加不同的key值

<style>
    .v-enter,v-leave-to{
        opacity: 0
    }
    .v-enter-active, .v-leave-active{
        transition: opacity 1s;
    }
</style>
<transition mode="in-out/out-in">
	<div v-if="show" :key="A">
        hello world
    </div>
    <div v-else :key="B">
        bye world
    </div>
</transition>

Vue中的列表过渡

<style>
    .v-enter,v-leave-to{
        opacity: 0
    }
    .v-enter-active, .v-leave-active{
        transition: opacity 1s;
    }
</style>

<transition-group>
	<div v-for="(item, index) of arr">
        {{item.title}}
    </div>
</transition-group>

Vue中动画的封装

<div>
    <fade :show="show">
    	<div>
            hello world
        </div>
    </fade>
    <button @click="handleBtnClick">
        toggle
    </button>
</div>

Vue.component('fade', {
	props: ['show'],
	template: `
		<transition @before-enter="handleBeforeEnter"
         	@enter="handleEnter"    
         >
			<slot v-if="show"></slot>
		</transition>
	`,
    methods: {
        handleBeforeEnter: function(el){
            el.style.color="red"
        },
        handleEnter: function(el, done){
            setTimeout(() => {
				el.style.color = 'green'
				done()
            }, 2000)
        }
    }
})

Vue项目开发环境

  • 安装node.js
    • 检测npm -v和 node -v
  • 创建码云的仓库
    • 用账号登录码云
    • 然后选择项目>Private点击+号创建私有的项目
    • 依次填写项目名称>项目介绍>是否公开(私有)>选择语言(JavaScript)> 添加开源许可证(MIT License)> 使用Readme文件初始化这个项目>创建即可
  • 安装git并使用git将本地仓库和远程仓库进行关联
    • 点击码云头像>设置>SSH公钥>项目管理>公钥 管理>生成/添加SSH公钥
    • 在git-bash中三次回车执行ssh-keygen -t rsa -C "[email protected]",如果之前生成过公钥,这会提示已经生成,不需要再次生成了
    • 然后在 git-bash中执行 cat ~/.ssh/id_rsa.pub获取公钥
    • 然后将公钥添加到SSH公钥的里面,标题会自动生成。
    • 这样在本地会有一个私钥,然后私钥和公钥匹配之后就可以不用密码来上传和更新。
  • 配置SSH私钥并建立连接
  • 将线上的仓库通过SSH克隆到本地。在本地执行git clone SSH地址
  • 安装vue脚手架工具npm install --global -vue-cli
  • 在克隆下来的文件夹中使用vue-cli创建vue项目初始化项目:vue init webpack projectName(项目名)  **ps:**注:项目名不能大写,不能使用中文
  • 进入项目文件夹,执行cnpm install下载依赖
  • 运行 npm run dev
  • 在项目文件夹中执行git add .git commit -m ''提交到本地仓库
  • 然后执行git push将本地库提交到码云仓库

详细的环境配置:https://blog.csdn.net/yw00yw/article/details/81201670

单页应用VS多页应用

  • 多页应用网站
    • 当每次请求跳转的时候后台都会返回一个新的html文件,则为多页应用网站
      • 优点:首屏时间快,SEO效果好
      • 缺点:页面切换慢
  • 单页应用网站
    • 页面每次跳转并不加载html页面,而是通过js动态清除当前页面内容然后渲染新的html页面内容,只请求加载了一次。
      • 优点:页面切换快
      • 缺点:首屏时间稍慢,SEO差

项目初始化

  • 增加meta标签

样式问题——在main.js中引入

  • 引入reset.css使各个浏览器显示的效果一样
    • import './assets/styles/reset.css'
  • 引入border.css解决移动端1px问题
    • import './assets/styles/border.css'

js问题

  • fastclick 解决移动端click300ms延迟问题
    • import fastClick from 'fastclick'
    • fastClick.attach(document.body)

第三方字体库

  • iconfont

css预处理器

stylus——> npm install stylus stylus-loader --save

<style lang="stylus" scoped>
    .header
        height value
</style>

rem的使用

# 在rest.css中设置了html的根字体大小为 50px
# 因为设计稿一般是750px是iphone6的二倍图
# 那么可以简单在设计稿上量取的高度/宽度 = html * 2 = 50 * 2 = 1rem / 100
# 即 1px = 0.01rem

配置文件路径的别名,简化路径

build > webpack.base.conf.js中配置

resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
            '@': resolve('src'),
            'styles': resolve('src/assets/styles'),
        }
    }

引入

# 在css中引入必须加~
# 在main.js中引入不需要加前面的~
@import '~styles/stylus/varibles.styl'

分支的创建

# 在码云git仓库中创建一个分支,并起用分支名,然后将线上仓库使用`git pull`拉取到本地,然后使用`git checkout ...`切换到新分支上,然后进行开发,该功能模块开发完成之后依次提交到本地仓库`git commit`、线上仓库`git push`的当前分支上,然后切换到主分支,使用`git merge ...`合并到主分支,然后`git push`提交到远程仓库

轮播插件

使用Vue-Awesome-Swiper轮播插件

npm install vue-awesome-swiper --save

import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper'

// require styles
import 'swiper/dist/css/swiper.css'

Vue.use(VueAwesomeSwiper, /* { default global options } */)

解决图片的宽高比例自适应问题,即图片的自适应,用来占位,防止页面的抖动

.wrapper
	overflow: hidden
    width: 100%
    height: 0
    padding-bottom: 31.25% /*图片的高宽比例*/
	.swiper-img
		width 100%

样式的穿透,使子组件的样式不受scoped的限制

.wrapper >>> .swiper-pagination-bullet-active
        background  #fff !important

使用swiper解决多页小图标轮播

computed: {
    pages () {
        const pages = []
        this.iconList.forEach((item, index) => {
            const page = Math.floor(index / 9)
            if (!pages[page]) {
                pages[page] = []
            }
            pages[page].push(item)
        })
        return pages
    }
}

使用axios进行ajax数据的请求

  • fetch
  • vue-resource
  • axios
  • npm install axios --save

在项目目录static目录下模拟json数据,因为只有static才可以在地址栏中请求到。

  • http://localhost:8082/static/mock/index.json

在.gitignore中写入不需要提交到仓库的文件

  • static/mock
  • 则可以使用axios.get('/static/mock/index.json').then(this.getHomeInfoSucc)请求到数据

请求代理的替换,使用webpack提供的proxyTable解决跨域问题

打开项目根目录文件夹config下的index.js,然后在proxyTable属性中更改

proxyTable: {
    '/api': {
        target: 'http://localhost:8080', //目标接口域名
            changeOrigin: true, //是否跨域
            pathRewrite: {
                '^/api': '/static/mock' //重写接口
            }
    }
}

请求:

axios.get('/api/index.json').then(this.getHomeInfoSucc)

父子组件之间的数据传递

将父组件中请求到的数据传递给所有子组件

移动端文字垂直居中问题

关于移动端文字无法垂直居中(或line-height不起作用)的问题的解决方案

使用better-scroll实现列表滚动

cnpm install better-scroll --save

<div class="wrapper">
  <ul class="content">
    <li>...</li>
  </ul>
</div>
import BScroll from 'better-scroll'
const wrapper = document.querySelector('.wrapper')
const scroll = new BScroll(wrapper)

获取源事件的元素

 handleLetterClick (e) {
     console.log(e.target.innerText)
 }

使用scrollToElement实现滚动

# 同级组件1
handleLetterClick (e) {
    this.$emit('change', e.target.innerText)
}
# 同级组件2
watch: {
    letter () {
        if (this.letter) {
            const element = this.$refs[this.letter][0]
            this.scroll.scrollToElement(element)
        }
    }
}

触摸滑动

<div class="list">
    <ul>
        <li class="item" v-for="(city, key) of cities" :key="key" 
            @touchstart="handleTouchStart"
            @touchmove="handleTouchMove"
            @touchend="handleTouchEnd"
            @click="handleLetterClick"
            >{{key}}</li>
    </ul>
</div>

    data () {
        return {
        	touchStatus: false
        }
     },
    computed: {
        letters () {
            const letters = []
            for (let i in this.cities) {
                letters.push(i)
            }
            return letters
        }
    },
    methods: {
        handleLetterClick (e) {
            this.$emit('change', e.target.innerText)
        },
        handleTouchStart () {
            this.touchStatus = false
        },
        handleTouchMove (e) {
           // 1. 获取A元素距离顶部的距离
           // 2. 获取手指滑动距离顶部的当前距离
           // 3. 相减得到手指滑动到字母的距离
           // 4. 使用在字母上得到的距离/字母的高度=字母下标
            const startY = this.$refs['A'][0].offsetTop
            const touchY = e.touches[0].clientY - 79
            const index = Math.floor((touchY - startY) / 20 )
            if (index >= 0 && index < this.letters.length) {
                this.$emit('change', this.letters[index])
            }
        },
        handleTouchEnd () {
            this.touchStatus = true
        }
    }

列表性能优化

  • 函数节流
if (this.touchStatus) {
    if (this.timer) {
    	clearTimeout(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.letters.length) {
               this.$emit('change', this.letters[index])
           }
    }, 16)          
}

搜索功能 实现

watch: {
keyWord () {
    if (this.timer) {
    	clearTimeout(this.timer)
    }
    if (!this.keyWord) {
    	this.list = []
    	return
    }
    this.timer = setTimeout(()  => {
        const result = []
        for (let i in this.cities) {
            this.cities[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('.search-content')
}

使用vuex实现数据管理

export default new Vuex.Store({
    state: {
        city: '北京'
    },
    getters: {},
    actions: {
        changeCity(ctx, city) {
            ctx.commit('changeCity', city)
        }
    },
    mutations: {
        changeCity(state, city) {
            state.city = city
        }
    }
})

使用localStorage实现切换不同城市的数据存储,实现城市保存

let defaultCity = '北京'

try {
    if (localStorage.city) {
        defaultCity = localStorage.city
    }
} catch (e) {}

export default new Vuex.Store({
    state: {
        city: defaultCity
    },
    getters: {},
    actions: {
        changeCity(ctx, city) {
            ctx.commit('changeCity', city)
        }
    },
    mutations: {
        changeCity(state, city) {
            state.city = city
                // 保存城市
            try {
                localStorage.city = city
            } catch (e) {}
        }
    }
})

使用keep-alive性能优化

每一次切换路由的时候,对应的ajax就会被执行请求,原因是因为执行了mounted钩子函数,正常情况下只需要获取一次,可以减少性能

keep-alive 包含的组件第一次执行的时候被放到内存中,下一次不需要请求,直接从内存中调用

<div id="app">
    <keep-alive>
        <router-view/>
    </keep-alive>
</div>

activated

# 使用keep-alive会将请求的数据缓存到内存中,然后会调用activated钩子函数的执行,当页面改名的时候回执行该钩子函数。
activated () {
    if (this.lastCity !== this.city) {
        this.lastCity = this.city
        this.getHomeInfo()
    }
}

使用router-link或者动态路由实现页面详情

<router-link :to="'/detail/' + item.id" tag="li"></router-link>

{
    path: '/detail/:id',
    name: 'Detail',
    component: Detail
}

在build目录下的webpack.base.config.js中配置别名

resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
            '@': resolve('src'),
            'styles': resolve('src/assets/styles'),
            'common': resolve('src/common')
        }
    }

使用swiper配置图片的轮播

swiperOption: {
    pagination: {
        el: '.swiper-pagination',
            type: 'fraction'
    },
    observer:true,
    observeParents:true
}

采用监听事件scroll实现header显示隐藏及动画

handleScroll () {
    const top = document.documentElement.scrollTop
    if (top > 60) {
        let opacity = top / 140
        opacity = opacity > 1 ? 1 : opacity
        this.opacityStyle = {
            opacity
        }
        this.showAbs = false
    } else {
        this.showAbs = true
    }

}

使用activated 和deactivated 钩子函数对全局函数的添加和解绑

activated () {
	window.addEventListener('scroll', this.handleScroll)
},
deactivated () {
    // 对全局事件的解绑
    window.removeEventListener('scroll', this.handleScroll)
}

使用递归组件实现多级列表数据展示

<div class="item" v-for="(item, index) of list" :key="index">
    <div class="item-title border-bottom">
        <span class="item-title-icon"></span>
        {{item.title}}
    </div>
    <div v-if="item.children" class="item-children">
        <detail-list :list="item.children"></detail-list>
    </div>
</div>

使用activated 解决对keep-alive缓存问题的解决,让重新请求数据

或者使用以下属性解决

<keep-alive exclude="Detail">  # 组件名,除了detail组件之外的被缓存
    <router-view/>
</keep-alive>

每一个组件的name的作用

  • 在做递归组件的时候回用到
  • 在页面上取消缓存时候会用到
  • vue-devtools工具里面的组件名字

解决路由切换过程中滚动问题

# 在路由中添加
scrollBehavior(to, from, savedPosition) {
    return { x: 0, y: 0 }
}

动画的封装和使用

FadeAnimation.vue

<template>
    <transition>
        <slot></slot>
    </transition>
</template>

<script>
export default {
    name: 'FadeAnimation'
}
</script>

<style lang="stylus" scoped>
    .v-enter, .v-leave-to 
        opacity 0
    .v-enter-active, .v-leave-active
        transition opacity .5s
</style>

Banner.vue

<fade-animation>
            <common-gallary :imgs="gallaryImgs" v-show="showGallary" @close="handleBannerClose">			</common-gallary>
</fade-animation>

Vue项目的接口联调

# config/index.js
proxyTable: {
    '/api': {
        target: 'http://localhost:80' //api地址可以换成内网的IP或者外网的域名
    }
}

Vue项目的真机测试

# 获取当前电脑的内网IP
`ipconfig/all`

# 修改 package.json 文件(因为webpack的默认服务端口无法访问,只需要改成以下即可)
"dev": "webpack-dev-server --host 0.0.0.0 --inline --progress --config build/webpack.dev.conf.js"


# 解决低版本安卓机浏览器不支持promise,出现白屏问题
在项目目录下安装 
'npm install babel-polyfill --save'

# 并且在main.js中添加
import 'babel-polyfill'

然后重启之后使用同局域网的IP地址加端口号访问

解决手机上的全屏滑动出现的问题

@touchstart.prevent="handleTouchStart"

Vue项目的打包上线

# 运行
`npm run build`
打包成功后为dist的文件夹

# 一般直接将打包后的文件index.html和static文件夹放到后端项目的根目录下
# 如果想放到指定的目录,则需要在 config/index.js中修改
build: {
    assetsPublicPath: '/project'
}

猜你喜欢

转载自blog.csdn.net/yw00yw/article/details/84245625