v-bind:属性名=变量值
传递props: [属性名]
接收this.$emit(事件名,数据)
发送事件和数据v-on:事件名="父组件事件"
监听并接收传递过来的数据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
对象绑定
:class={类名:变量}
数组绑定
:class=[变量]
style
对象绑定
:style={变量}
数组绑定
:style=[变量]
v-if: 每一次都会删除和添加dom,性能不好
v-show: 经常操作的可以使用v-show,性能好
问题:
# 解决vue的复用问题,在不添加key的时候,当切换显示和隐藏时候,vue会复用文本框,里面内容也不会改变,解决办法就是给元素加一个key就可以使之唯一,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’))
用来占位,包裹一些元素,但是不显示
# 作用:是为了让每个可复用的组件拥有自己的独立数据
# 在html元素上的ref可以获取dom
hello world
# 使用发布订阅的方式,在组件上的ref可以获取该组件的引用
{{total}}
vue中的单项数据流,只允许父组件向子组件传递数据,不允许子组件改变父组件传递过来的数据。如果需要修改父组件传递过来的数据,则可以将传递过来的数据保存为自己的变量,然后做更改。
props: {
content: String,
age: Number,
id: [Number, String],
address: {
type: String,
required: true,
default: 'default value',
validator: function(value){
return value.length > 5
}
}
}
在组件上绑定事件的时候,这个事件是属于监听事件,而不是原生事件。因此当点击时候不会触发。如果需要触发,有以下两种操作:
@click.native="chandleClick"
通过(Bus/总线/发布订阅模式/观察者模式)
在vue中,父组件向子组件传递数据的时候,通过绑定属性向子组件传递,子组件通过props来接收
通过插槽的方式可以批量的在子组件内部传递数据,然后通过slot来接收,并且可以接收具名slot内容。
header
footer
{{props.item}} - hello
hello world
hello world
中文文档:http://www.mrfront.com/docs/velocity.js/index.html
vue中的dom的复用,导致动画不会出现,需要添加不同的key值
hello world
bye world
{{item.title}}
hello world
Vue.component('fade', {
props: ['show'],
template: `
`,
methods: {
handleBeforeEnter: function(el){
el.style.color="red"
},
handleEnter: function(el, done){
setTimeout(() => {
el.style.color = 'green'
done()
}, 2000)
}
}
})
ssh-keygen -t rsa -C "[email protected]"
,如果之前生成过公钥,这会提示已经生成,不需要再次生成了cat ~/.ssh/id_rsa.pub
获取公钥git clone SSH地址
npm install --global -vue-cli
vue init webpack projectName(项目名)
**ps:**注:项目名不能大写,不能使用中文cnpm install
下载依赖git add .
和git commit -m ''
提交到本地仓库git push
将本地库提交到码云仓库详细的环境配置:https://blog.csdn.net/yw00yw/article/details/81201670
import './assets/styles/reset.css'
import './assets/styles/border.css'
import fastClick from 'fastclick'
fastClick.attach(document.body)
stylus——> npm install stylus stylus-loader --save
# 在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%
.wrapper >>> .swiper-pagination-bullet-active
background #fff !important
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
}
}
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)
请求到数据打开项目根目录文件夹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不起作用)的问题的解决方案
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)
}
# 同级组件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')
}
export default new Vuex.Store({
state: {
city: '北京'
},
getters: {},
actions: {
changeCity(ctx, city) {
ctx.commit('changeCity', city)
}
},
mutations: {
changeCity(state, city) {
state.city = city
}
}
})
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) {}
}
}
})
每一次切换路由的时候,对应的ajax就会被执行请求,原因是因为执行了mounted钩子函数,正常情况下只需要获取一次,可以减少性能
keep-alive 包含的组件第一次执行的时候被放到内存中,下一次不需要请求,直接从内存中调用
# 使用keep-alive会将请求的数据缓存到内存中,然后会调用activated钩子函数的执行,当页面改名的时候回执行该钩子函数。
activated () {
if (this.lastCity !== this.city) {
this.lastCity = this.city
this.getHomeInfo()
}
}
{
path: '/detail/:id',
name: 'Detail',
component: Detail
}
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src'),
'styles': resolve('src/assets/styles'),
'common': resolve('src/common')
}
}
swiperOption: {
pagination: {
el: '.swiper-pagination',
type: 'fraction'
},
observer:true,
observeParents:true
}
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 () {
window.addEventListener('scroll', this.handleScroll)
},
deactivated () {
// 对全局事件的解绑
window.removeEventListener('scroll', this.handleScroll)
}
{{item.title}}
或者使用以下属性解决
# 组件名,除了detail组件之外的被缓存
# 在路由中添加
scrollBehavior(to, from, savedPosition) {
return { x: 0, y: 0 }
}
FadeAnimation.vue
Banner.vue
# config/index.js
proxyTable: {
'/api': {
target: 'http://localhost:80' //api地址可以换成内网的IP或者外网的域名
}
}
# 获取当前电脑的内网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"
# 运行
`npm run build`
打包成功后为dist的文件夹
# 一般直接将打包后的文件index.html和static文件夹放到后端项目的根目录下
# 如果想放到指定的目录,则需要在 config/index.js中修改
build: {
assetsPublicPath: '/project'
}