(1) export 和 export default 的区别
- export ( import ) 可以有多个,export default ( 默认导出 ) 只能有一个
- export导出后引用需要加 { } ,export default则不需要
(2) vuex
state.js
功能:状态数据
const state={
singer:{}
}
export default state
mutation-types.js
功能:放置方法名,或者对mutations做封装
export const SET_SINGER = 'SET_SINGER'
mutations.js
功能:操作state数据
import * as types from './mutation-types'
const matutaions = {
[types.SET_SINGER] (state,singer){ // singer是传入的参数
state.singer=singer
}
}
export default matutaions
getters.js
功能:获取state里的数据,对state数据做映射
export const singer = state => state.singer
actions.js
功能:放异步操作
function findIndex(list, song) {
return list.findIndex((item) => {
return item.id === song.id
})
}
index.js
功能: 入口文件
import Vue from 'vue'
import Vuex from 'vuex'
import * as actions from './actions'
import * as getters from './getters'
import state from './state'
import mutations from './mutations'
import createLogger from 'vuex/dist/logger' // 打印motation的修改纪录
Vue.use(Vuex)
const debug = process.env.NODE_ENV !== 'production'
// 调试工具,在dev环境开启,在production环境关闭
export default new Vuex.Store({
actions,
getters,
state,
mutations,
strict: debug,
plugins: debug ? [createLogger()] : []
})
存数据 ( 到 vuex 的 state 中 )
singer.vue
import {mapMutations} from 'vuex' // 语法糖
methods: {
selectSinger(singer) { // 子组件派发的this.$emit('select',item),这个item就是singer
this.$router.push({
path: `/singer/${singer.id}`
})
this.setSinger(singer)
// 在...mapMutations中取得setSinger方法,singer数据作为参数传给该方法,该方法改变state中的singer
},
_getSingerList() {
getSingerList().then((res) => {
if (res.code === ERR_OK) {
this.singers = this._normalizeSinger(res.data.list)
}
})
},
...mapMutations({
setSinger: 'SET_SINGER' // 映射成一个setSinger方法,对应的是mutation-types.js中的常量
})
},
取数据 ( 在 vuex 的 state 中 )
singer-detail.js
import {mapGetters} from 'vuex'
computed: {
...mapGetters([ // 扩展到computed中,是一个数组
'singer'
])
}
(3) router.beforeEach((to, from, next) => { })
导航钩子:作用是拦截导航
http://blog.csdn.net/wenyun_kang/article/details/70987840
https://segmentfault.com/a/1190000011140870
(详细)//www.greatytc.com/p/2578cc444b70
(详细)//www.greatytc.com/p/9798e3e63998
(1) 全局的钩子router.beforeEach((to, from, next) => { } )
(2) 路由元信息 meta 字段,标记是否需要检测导航
- 在router文件夹的index.js中
router/index.js
export default new Router({
routes: [
{
path: '/',
name: 'home',
redirect: '/recommend',
meta: { // 路由元信息字段,表示是否需要检测导航,true表示需要检测
needLogin: true
}
},
{
path: '/login',
component: Login
},
{
path: '/recommend',
name: 'recommend',
component: Recommend
},
{
path: '/singer',
name: 'singer',
component: Singer,
meta: {
needLogin: true
},
children: [{
path: ':id',
component: SingerDetail,
meta: {
needLogin: true
}
}]
}
]
})
- 在main.js中
main.js
router.beforeEach((to, from, next) => {
if (to.meta.needLogin) { // 如果目标页面需要登陆
if (window.sessionStorage.data) { // 但是同时已经登陆过了,有session
next() // 直接跳转到目标页面
} else {
alert('请先登录')
next('/login') // 否则跳转到登陆页面
}
} else {
next() // 如果不需要登陆,直接跳转到目标页面
}
})
- 在login.js中
login.js
methods: {
login() {
this.$http.post('https://www.easy-mock.com/mock/59d2fed09cabc90bb5e5c287/music/login', {
phone: `${this.userName}`,
password: `${this.passName}`
}).then((response) => {
console.log(response, 'response')
console.log(response.data, 'response.data')
if (response.data.data) { // 如果提交成功,返回数据存在
let ses = window.sessionStorage
let data = JSON.stringify(response.data.data)
ses.setItem('data', data) // 设置session,需要以字符串方式存储
this.$router.push('/') // 跳转路由
} else {
console.log('有错误')
}
})
}
}
(4) v-bind:style='' '' 绑定样式属性
- v-bind:style 它是一个 JavaScript 对象
http://blog.csdn.net/qiphon3650/article/details/73716220
(1)
<div class="bg-image" v-bind:style="bgStyle"> // 一般绑定到样式属性上,计算属性
computed: {
bgStyle() {
return {
'background-image': `url(${this.bgImage})`,
border: '1px solid red'
}
// return `background-image:url(${this.bgImage})`
}
}
-----------------------------------------------------------------------
(2)
// 这种方式不提倡,不直观
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
activeColor: 'red',
fontSize: 30
}
(5) 在不同宽度的设备上,让图片宽度为设备宽度,且高度和宽度相等
- 注意:这种布局不要在class="bg-image"的div中直接写内容(比如文字,这样不会在div中),需要在里面再加子div,在子div中写内容,子div用绝对定位
<div class="bg-image" v-bind:style="bgStyle" ref="bgImage">
<!--<div class="bg-image" v-bind:style="{color:red}">1-->
<!--filter是一个加暗的浮层-->
<div class="filter"></div>
</div>
.bg-image
position: relative
width: 100%
height: 0
padding-top: 100%
transform-origin: top
background-size: cover
.filter
position: absolute
top: 0
left: 0
width: 100%
height: 100%
background: rgba(7, 17, 27, 0.4)
(6) promise 封装axios请求
test2.js
import axios from 'axios'
// import Vue from 'vue'
// Vue.prototype.$http = axios
export function getSongs() {
return axios.get('/api/artist/album?id=6452&limit=30').then((response) => {
return Promise.resolve(response)
})
}
-----------------------------------------------------------------------
search.vue
import {getSongs} from 'api/test2.js'
export default {
created() {
this.getData()
},
methods: {
getData() {
getSongs().then((data) => {
console.log(data)
})
}
}
}
----------------------------------------------------------------
上面的/api是使用了代理,如下配置:
config/index.js
proxyTable:{
'/api': {
target: 'http://localhost:3000/',
changeOrigin: true,
pathRewrite: {
'^/api':''
}
}
}
访问 ('/api/artist/album?id=6452&limit=30')
其实是:http://localhost:3000/api/artist/album?id=6452&limit=30
(7)
this.$router.push() 跳转
this.$router.back() 返回
(1) this.$router.push
selectSinger(singer) { // 子组件派发的this.$emit('select',item),这个item就是singer
this.$router.push({
path: `/singer/${singer.id}`
})
this.setSinger(singer)
// 在...mapMutation中取得setSinger方法,singer数据作为参数传给state
},
--------------------------------------------
(2) this.$router.back()
<div class="back" v-on:click="back">
<i class="icon-back"></i>
</div>
methods: {
back() {
this.$router.back()
}
},
(8) watch 观察者
- watch方法响应数据的变化,当你想要在数据变化响应时,执行异步操作或开销较大的操作,这是很有用的。
- Vue.js 提供了一个方法 watch,它用于观察Vue实例上的数据变动。对应一个对象,键是观察表达式,值是对应回调。值也可以是方法名,或者是对象,包含选项。
https://q.cnblogs.com/q/91448/
http://blog.csdn.net/itkingone/article/details/69568498
http://blog.csdn.net/lemon_zhao/article/details/52191527
(官网)https://cn.vuejs.org/v2/api/#vm-watch
(知乎)https://www.zhihu.com/question/39155535?sort=created
例一:
<script>
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 question 发生改变,这个函数就会运行
question: function (newQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.getAnswer()
}
},
methods: {
getAnswer() {........}
}
})
</script>
例二:
<span style="color:#006600;"><div id="app">
<input type="text" v-model:value="childrens.name" />
<input type="text" v-model:value="lastName" />
</div>
<script type="text/javascript">
var vm = new Vue( {
el: '#app',
data: {
childrens: {
name: '小强',
age: 20,
sex: '男'
},
tdArray:["1","2"],
lastName:"张三"
},
watch:{
childrens:{
handler:function(val,oldval){
console.log(val.name)
},
deep:true//对象内部的属性监听,也叫深度监听
},
'childrens.name':function(val,oldval){
console.log(val+"aaa")
},//键路径必须加上引号
lastName:function(val,oldval){
console.log(this.lastName)
}
},//以V-model绑定数据时使用的数据变化监测
} );
vm.$watch("lastName",function(val,oldval){
console.log(val)
})//主动调用$watch方法来进行数据监测</span>
</script>
</body>
例三:
var v_assetManage_controller = new Vue({
el: '.LSee-index',
data: {
trendQueryTimeCtr: {
startTime: '',
endTime: ''
}
},
ready: function() {
//
},
methods: {
queryTrendData: function(){
//do some here
}
},
watch: {
'trendQueryTimeCtr.startTime': 'queryTrendData',
'trendQueryTimeCtr.endTime': 'queryTrendData'
}
});
(8) vm.$watch( expOrFn, callback, [options] )
- 参数:
{string | Function} expOrFn
{Function | Object} callback
{Object} [options]
{boolean} deep // 深度监听,一般用于对象
{boolean} immediate
返回值:{Function} unwatch - 用法:
观察 Vue 实例变化的一个表达式或计算属性函数。回调函数得到的参数为新值和旧值。表达式只接受监督的键路径。对于更复杂的表达式,用一个函数取代。 - 选项:deep
为了发现对象内部值的变化,可以在选项参数中指定 deep: true 。注意监听数组的变动不需要这么做。
// 键路径
vm.$watch('a.b.c', function (newVal, oldVal) {
// 做点什么
})
// 函数
vm.$watch(
function () {
return this.a + this.b
},
function (newVal, oldVal) {
// 做点什么
}
)
(9) better-scroll的封装
probeType
类型:Number
默认值:0
可选值:1、2、3
作用:有时候我们需要知道滚动的位置。
当 probeType 为 1 的时候,会非实时(屏幕滑动超过一定时间后)派发scroll 事件;
当 probeType 为 2 的时候,会在屏幕滑动的过程中实时的派发 scroll 事件;
当 probeType 为 3 的时候,不仅在屏幕滑动的过程中,而且在 momentum 滚动动画运行过程中实时派发 scroll 事件。momentum
类型:Boolean
默认值:true
作用:当快速在屏幕上滑动一段距离的时候,会根据滑动的距离和时间计算出动量,并生成滚动动画。设置为 true 则开启动画。
翻译:momentum是动量的意思refresh
参数:无
返回值:无
作用:重新计算 better-scroll,当 DOM 结构发生变化的时候务必要调用确保滚动的效果正常。
<template>
<div ref="wrapper">
<slot></slot>
</div>
</template>
<script type="text/ecmascript-6">
import BScroll from 'better-scroll'
export default {
props: {
/**
* probeType
* 1 滚动的时候会派发scroll事件,会截流。
* 2 滚动的时候实时派发scroll事件,不会截流。
* 3 除了实时派发scroll事件,在swipe的情况下仍然能实时派发scroll事件
*/
probeType: { // 类型
type: Number,
default: 1
},
click: { // 是否能点击
type: Boolean,
default: true
},
listenScroll: { // 是否派发滚动事件
type: Boolean,
default: false
},
data: { // 列表数据
type: Array,
default: null
},
pullup: { // 是否派发滚动到底部的事件,用于上拉加载
type: Boolean,
default: false
},
pulldown: { // 是否派发顶部下拉的事件,用于下拉刷新
type: Boolean,
default: false
},
beforeScroll: { // 是否派发列表滚动开始的事件
type: Boolean,
default: false
},
refreshDelay: { // 当数据更新后,刷新scroll的延时。
type: Number,
default: 20
},
scrollX: { // 横向滚动
type: Boolean,
default: false
}
},
mounted() {
setTimeout(() => {
this._initScroll()
}, 20)
},
methods: {
_initScroll() {
if (!this.$refs.wrapper) {
return
}
this.scroll = new BScroll(this.$refs.wrapper, {
probeType: this.probeType,
click: this.click,
scrollX: this.scrollX
})
// 是否派发滚动事件
if (this.listenScroll) {
let me = this
this.scroll.on('scroll', (pos) => {
me.$emit('scroll', pos)
})
}
// 是否派发滚动到底部事件,用于上拉加载
if (this.pullup) {
this.scroll.on('scrollEnd', () => {
if (this.scroll.y <= (this.scroll.maxScrollY + 50)) {
this.$emit('scrollToEnd')
}
})
}
// 是否派发顶部下拉事件,用于下拉刷新
if (this.pulldown) {
this.scroll.on('touchend', (pos) => {
// 下拉动作
if (pos.y > 50) {
this.$emit('pulldown')
}
})
}
// 是否派发列表滚动开始的事件
if (this.beforeScroll) {
this.scroll.on('beforeScrollStart', () => {
this.$emit('beforeScroll')
})
}
},
// 方法代理
disable() { // 作用:禁用 better-scroll,DOM 事件(如 touchstart、touchmove、touchend)的回调函数不再响应。
this.scroll && this.scroll.disable()
},
enable() { // 作用:启用 better-scroll
this.scroll && this.scroll.enable()
},
refresh() { // 作用:重新计算 better-scroll,当 DOM 结构发生变化的时候务必要调用确保滚动的效果正常。
this.scroll && this.scroll.refresh()
},
scrollTo() { // 作用:滚动到指定的位置
this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
},
scrollToElement() { // 作用:滚动到指定的目标元素
this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
}
// _watchData() {
// setTimeout(() => {
// this.refresh()
// }, this.refreshDelay)
// }
},
watch: {
data() {
setTimeout(() => {
this.refresh()
}, this.refreshDelay)
}
// 'data': '_watchData' //观察data的变化,当data变化是执行_watchData函数,上面的是直接执行
}
}
</script>
<style scoped lang="stylus" rel="stylesheet/stylus">
</style>
(10) 事件修饰符
.stop : 阻止冒泡
.prevent : 阻止默认事件
.capture
.self : 指定元素触发(不包括子元素)
.once : 事件只执行一次,特别之处:还能用在组件事件上
ps: 给组件添加原生事件,需要添加.naive
<!-- 阻止单击事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件侦听器时使用事件捕获模式 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当事件在该元素本身 (比如不是子元素) 触发时触发回调 -->
<div v-on:click.self="doThat">...</div>
(10) v-on:click.once="" 事件只触发一次
- 不像其它只能对原生的 DOM 事件起作用的修饰符,.once 修饰符还能被用到自定义的组件事件上。
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
(11) .snyc修饰符
- sync : 同步
- async: 异步
- .sync实际上是语法糖
- <comp :foo.sync="bar"></comp>
https://www.cnblogs.com/penghuwan/p/7473375.html
<comp :foo.sync="bar"></comp>
会被扩展为:
<comp :foo="bar" @update:foo="val => bar = val"></comp>
当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:
this.$emit('update:foo', newValue)
// (1) 父组件给子组件comp 传递一个foo同步属性,值是bar
// (2) 当子组件想要改变foo属性时,由于子组件不能修改父组件传过来的任何数据,所以用.sync修饰符
// (3) 当子组件想要改变foo属性时,向父组件派发一个'update:foo'事件,newValue为传递的数据
// (4) 'update:foo'事件将foo的值改为从子组件传过来的newValue值
rank-detail.vue
<sync class="sync" v-bind:bg.sync="bb" v-if="bb"></sync>
data() {
return {
bb: true
}
}
-----------------------------------------------------------------------------
sync.vue
<div class="sync" v-on:click="goto" v-if="bb">
这里是sync组件显示内容
</div>
<script type="text/ecmascript-6">
export default {
props: {
bb: {
type: Boolean,
default: true
}
},
methods: {
goto() {
this.$emit('update:bg', false)
}
}
}
</script>