vue之other
Vuex
Vuex是vue官方的一款状态管理工具,什么是状态呢?我们在前端开发中有一个概念:数据驱动,页面中任意的显示不同,都应该有一条数据来控制,而这条数据又叫做state,状态。
在vue中。组件间进行数据传递、通信很频繁,而父子组件和非父子组件的通信功能也比较完善,但是,唯一困难的就是多组件间的数据共享,这个问题由vuex来处理
vue提供的一个全局的状态管理工具,主要处理项目中多组件间状态共享
Vuex的使用:
- 创建store:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
- 设置state
state就是一个纯对象,上面有一些状态挂载
import state from './state'
//可以设置store管理的state/getter,mutations,actions
const store = new Vuex.Store({
state
})
- 在根实例里配置store
这样,我们就可以在任意的组件中通过this.$store来使用关于store的api
import store from './store'
new Vue({
el: '#app',
router,
store,
template: '<App/>',
components: { App }
})
- 在组件中使用state
因为在组件中可以通过this.store.state来使用state中管理的数据
data(){
return {
num:this.$store.state.num
}
},
但是我们发现,这样使用的话,当state的数据更改的时候,vue组件并不会重新渲染
也就是说,如果想要在组件中响应式的使用的时候,我们需要通过计算属性(computed)来使用
computed:{
num(){
return this.$store.state.num
}
}
这样的写法很无趣,而且如果使用的状态较多会产生冗余的感觉,所以vuex提供了mapState辅助函数,帮助我们在组件中获取并使用vuex的store中保存的状态
所以我们可以这样写:
computed:mapState(['num']),
但是如果组件中已经有了num这个数据了,而state中的数据名字也叫num就会照成冲突,这个时候我们可以在组件使用state的时候,给状态起个别名:
computed:mapState({
// _num:'num',//键名为别名,值字符串代表的是真正的状态
_num(state){//方法名为别名,函数体里还可以对真正的状态做出一些处理
return state.num
} //简写为 _num:state=>state.num
}),
但是,有的时候我们在组件中还有自己的业务逻辑需要用到计算属性:
computed:{
a(){
return num+1
},
...mapState({
// _num:'num',//键名为别名,值字符串代表的是真正的状态
_num(state){//方法名为别名,函数体里还可以对真正的状态做出一些处理
return state.num
}
}),
},
- getters
有的时候,我们需要根据state中的某一个状态派生出一个新的状态,例如,我们state中有一个num,在某些组件中需要用到是num的二倍的一个状态,我们就可以通过getters来创建
const getters = {
doubleNum(state){
return state.num*2
}
}
computed:{
...mapGetters(["doubleNum"])
}
创建了之后,在组件中通过this.$store.getters.doubleNum来获取里面的数据
当然vuex也提供了mapGetters辅助函数来帮助我们在组件中使用getters里的状态,且,使用的方法和mapState一模一样
- 使用mutations更改state
我们不能直接在组件中更改state:this.$store.state.num=2,而是需要使用mutations来更改,mutations也是一个纯对象,里面包含很多更改state 的方法,这些方法的形参接收到state,在函数体里更改,这时,组件用到的数据也会更改,实现响应式。
但是我们也不能直接调用mutations 的方法,需要使用this.$store.commit来调用,第一个参数为调用的方法名,第二げ参数为传递参数
const mutations = {
increment(state){
state.num++
}
}
vuex提供了mapMutations方法来帮助我们在组件中调用mutations 的方法,使用方法和mapState、mapGetters一样
- 使用actions来处理异步操作
Action 类似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。
也就是说,如果有这样的需求:在一个异步处理之后,更改状态,我们在组件中应该先调用actions,来进行异步动作,然后由actions调用mutation来更改数据
const actions = {
getNumFromBackEnd({commit}){
setTimeout(() => {
let num = Math.floor(Math.random()*10)
//调用mutations的方法
commit(CHANGE_NUM,num)
}, 1000);
}
}
如上,actions的方法中可以进行异步的动作,且形参会接收store,从中取出commit方法用以调用mutations的方法
在组件中通过this.$store.dispatch方法调用actions的方法
当然也可以使用mapMutations来辅助使用
组件使用数据且通过异步动作更改数据的一系列事情:
1.生成store,设置state
2.在根实例中注入store
3.组件通过计算属性或者mapState来使用状态
4.用户产生操作,调用actions的方法,然后进行异步动作
5.异步动作之后,通过commit调用mutations的方法
6.mutations方法被调用后,更改state
7.state中的数据更新之后,计算属性重新执行来更改在页面中使用的状态
8.组件状态被更改...创建新的虚拟dom......
9.组件的模板更新之后重新渲染在dom中
vuex的使用:
目前市场上有两种使用vuex的情况,
第一种:将需要共享、需要管理的状态放入vuex中管理,也就是说在必要时使用
第二种:将所有的数据都交由vuex管理,由vuex来承担更多的责任,组件变得更轻量级,视图层更轻
自定义指令
在实现回到顶部功能的时候,我们写了一个backTop组件,接下来需要通过监听window.scroll事件来控制这个组件显示隐藏
写了一个v-back-top指令,就是将回到顶部功能做成一个指令,哪个组件或者dom需要使用到回到顶部,就加上这个指令就可以,设置不同的参数来控制在不同的情况下触发
Vue的组件库
组件库就是通用组件的集合
pc:element-ui iview
mobile: mint-ui
nextTick
当我们在使用一些插件的时候,经常需要在dom更新完成后进行必要操作,但是在vue中提供的api只有updated钩子函数,而在这个函数里,任意数据的变化导致的dom更新完成都会触发,所以很可能会造成无关数据的影响,而使用监听的话只能监听到数据的变化,此时dom还没有更新,我们只能强行使用setTimeout来处理
这里推荐大家使用nextTick全局方法:
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
eq:
getBillBoards(){
axios.get(this.$root.config.host+'mz/v4/api/billboard/home',{
params:{__t:Date.now()}
}).then(res => {
console.log(res.data.data.billboards)
this.billboards = res.data.data.billboards
//当数据更新,dom循环完成后,执行回调
Vue.nextTick(function () {
new Swiper('.app-home-banner',{
loop:true
})
})
})
}
Vue试题分析
- v-for可以实现数据遍历显示,不仅可以遍历数组,也可以遍历对象,还可以从数值中取值:
v-for='n in 10' n会打印1-10
- vue的生命周期钩子:
通用:beforeCreate/created/beforeMount/mounted/beforeUpdate/updated/beforeDestroy/destroyed
路由守卫:beforeRouteEnter/beforeRouteUpdate (2.2 新增)/beforeRouteLeave
- v-if v-show
v-if是真正的条件渲染,会确保在切换中条件块内的事件监听、子组件都会适当的被销毁和重建
v-show总是将节点渲染在dom中,只是基于css:display来控制节点的显示和隐藏
v-if有更高的切换开始,v-show有更高的初始渲染开销
v-if是惰性的,初始条件为假,就不会渲染
- axios相关
axios请求的时候不会带上cookie,不会影响带宽,可以通过withCredentials:true来设置
对axios 的请求头进行设置:
axios.defaults.headers = {'Content-Type':'...'}
vue2.0不在更新维护vue-resource,官方推荐使用axios
- 组件实例的作用域是孤立的,意味着不能(不应该)在子组件模板里直接引用父组件的数据,要让子组件使用父组件数据的话,需要通过props来将父组件的数据传递给子组件,子组件不能也不应该修改父组件传入的数据,但是可以通过传入引用类型的数据来实现数据共享
6.为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为内容分发 (即 Angular 用户熟知的“transclusion”)。Vue.js 实现了一个内容分发 API,参照了当前 Web Components 规范草案,使用特殊的 <slot> 元素作为原始内容的插槽。
a-template:
<p>hello world</p>
<b>
<h1>hello world</h1>
</b>
b-template:
<slot></slot>
- 注册方式:
全局:Vue.component(name,Vue.extend({}))
局部:{ components:{name:Vue.extend({})} }
- 事件总线实现非父子组件通信
//创建bus
let bus = new Vue()
//a
new Vue({
template:'...',
mounted(){
bus.$on('emit-a',function(){
alert(1)
})
}
})
//b
new Vue({
template:'...',
methods:{
emitA(){
bus.$emit('emit-a')
}
}
})
//当b组件的emitA方法被调用的时候,A组件就会执行alert(1)
- methods和计算属性的区别
假设我们有一个数据为num,还希望拥有一个数据为doublenum,而且希望doublenum的值永远都是num的二倍
方法:
* 因为是直接显示在模板中,也就是说,我们可以来一个doublenum的方法,这个方法返回num的二倍,将这个方法放到模板中的某个地方执行 {{doublenum()}}
但是,当无关的例如一个str的数据更改的时候,组件会重新创建虚拟dom树,与上一次的虚拟dom树对比之后重新渲染,这个时候在重新渲染模板的时候doublenum函数会被再次的调用,造成不必要的性能浪费
* 创建一个doublenum数据,使其初始值为num的二倍,然后利用watch来监听这两个数据,在改变的时候更改对应的数据,但是需要初始的为doublenum赋值为num的二倍,如果num是动态获取到的,doublenun赋值会更繁琐
* computed计算数据,我们可以利用computed来创建一条新的doublenum数据。并且设置它的getter和setter,并与num建立关系,且computed会缓存,在重新渲染的时候,不会重新执行getter和setter
computed:{
doublenum:{
get(){
return this.num*2
},
set(val){
this.num = val/2
}
}
}
- 绑定class的对象语法和数组语法
<a :class="{a:true,b:false,c:1}"> => </a> => <a class='a c'></a>
data(){
return {
c:'c'
}
}
<a :class = '["a","b",c]'></a> => </a> => <a class='a b c'></a>
- 单向数据流
prop是单向绑定的,父组件属性变化,传递给子组件,但是,子组件数据变化,不能直接传递给父组件,也就是数据的流行是从父组件流向子组件的,为了防止子组件修改父组件的数据(会让应用的数据流变的更难开发、更新、维护)
使用了vuex工具的时候,store中数据在组件中使用的过程也是单向数据流,state->vue component->actions->mutations->state->vue component
-
this.$router.push/replace({name:'user',params:{userId:1})
this.$router.push/replace({path:'/register',query:{plan:private})
key相关
当数据改变之后,vue会创建新的虚拟dom来和原来的虚拟dom做对比,在创建新的虚拟的dom的时候,会根据key来查找在原来的虚拟dom中有没有某个部分,如果原来的有,这次的也需要,就会实现复用,而且在做diff对比的时候,如果有key会加快对比的查找速度,提高性能
尽量循环的时候不要将key设置为数组的索引,因为当删除某一个元素的时候,就会导致删除位置下面的所有元素的key值都与上一次虚拟dom的key值不同,导致复用失败,这个时候我们最好使用关键的唯一的,例如id这样的数据作为key
如果数据变化只是值的变化而不是条数和位置的变化,可以使用索引作为key
Vue.use()
Vue.use会查找插件对象里的install方法去执行,并且给install方法里传入Vue对象
var a = {
install(Vue){
Vue.component("my-a",{...})
}
}
Vue.use(a)
进入域后根据不同的情况显示不同的页面(PC/MOBILE)
很多情况下,一个应用会有PC和移动端两个版本,而这两个版本因为差别大,内容多,所以不能用响应式开发但是单独开发,而域名只有一个,用户进入域后直接返回对应设备的应用,做法主要有两种:
-
前端判断并跳转
进入一个应用或者一个空白页面后,通过navigator.userAgent来判断用户访问的设备类型,进行跳转
-
后端判断并响应对应的应用
用户地址栏进入域的时候,服务器能接收到请求头上包含的userAgent信息,判断之后返回对应应用