vue 中的 ref , this.$refs
在JavaScript中需要通过document.querySelector("#demo")来获取dom节点,然后再获取这个节点的值。在Vue中,我们不用获取dom节点,元素绑定ref之后,直接通过this.$refs即可调用,这样可以减少获取dom节点的消耗。
ref被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs对象上。
如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;
如果用在子组件上,引用就指向该子组件实例
通俗的讲,ref特性就是为元素或子组件赋予一个ID引用,通过this.$refs.refName来访问元素或子组件的实例
<template lang="">
<p ref="p">Hello</p>
<children ref="children" @click = "handleEvent"></children>
</template>
<script>
methods: {
handleEvent() {
const Element_node = this.$refs.p
const package = this.$refs.children
}
}
</script>
tips:
1、 $refs只有在组件渲染完成后才填充,在初始渲染的时候不能访问它们,并且它是非响应式的,因此不能用它在模板中做数据绑定。
2、当ref和v-for一起使用时,获取到的引用将会是一个数组,包含循环数组源。
3、可以在父组件的方法中通过 子组件身上绑定了 ref ,来调用子组件身上的方法( this.$refs.children.handleEvent() )
vuex 中的 mapstate
state(vuex) / data (vue)
state在使用的时候一般被挂载到子组件的computed计算属性上,这样有利于state的值发生改变的时候及时响应给子组件。如果你用data去接收$store.state,当然可以接收到值,但由于这只是一个简单的赋值操作,因此state中的状态改变的时候不能被vue中的data监听到,当然你也可以通过watch $store去解决这个问题。
//state.js
let state = {
count: 1,
name: 'dkr',
sex: '男',
from: 'china'
}
export default state
import { mapState } from 'vuex'
<template>
<div id="example">
<button @click="decrement">-</button>
{{count}}
{{dataCount}}
<button @click="increment">+</button>
<div>{{sex}}</div>
<div>{{from}}</div>
<div>{{myCmpted}}</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
data () {
return {
str: '国籍',
dataCount: this.$store.state.count // 在 data 中接收 this.$store.state
}
},
computed: mapState({
count: 'count', // 第一种写法
from: function (state) { // 用普通函数this指向vue实例,要注意
return this.str + ':' + state.from
},
// 注意下面的写法看起来和上面相同,事实上箭头函数的this指针并没有指向vue实例,因此不要滥用箭头函数
// from: (state) => this.str + ':' + state.from
myCmpted: function () {
// 这里不需要state,测试一下computed的原有用法
return '测试' + this.str
}
}),
methods: {
increment () {
this.$store.commit('increment')
},
decrement () {
this.$store.commit('decrement')
}
},
created () {
// 写个定时器,发现computed依旧保持了只要内部有相关属性发生改变不管是当前实例data中的改变,还是vuex中的值改变都会触发dom和值更新
setTimeout(() => {
this.str = '国家'
}, 1000)
}
}
</script>
vue 音乐播放器 / vue-aplayer插件
vue的一些问题
响应式数据原理
默认 vue 在初始化数据时,会遍历 data 中的属性使用 objiect.defineproperty 重新定义所有属性(这是为了利用 objiect.defineproperty中的 set 和 get 方法进行数据劫持)
和 进行依赖收集(收集当前组件中的 watcher,即:订阅者),如果数据发生变化就会通知相关依赖进行更新操作(参考数据的发布与订阅)。
vue 中没有对 data 中的数组进行遍历,而是进行了原型链重写,指向了自己定义的数组原型方法,这样当
调用数组 的方法 时,就会转向vue 自己重新的原型方法(用数组的本来方法更改数据然后手动通知依赖更新(dep.notify()))。只有数组里的对象才会进行响应式观测遍历它
如果是数组,就让目标的原型链指向自己重写的原型链(重写的数组上的方法:比如push,pop,shift,unshift,splice等)
当用户调用这些方法的时候,会采用函数劫持的方式,还会调用原数组的方法但是会去更新数组。
vue 为何采用异步渲染
vue 组件级更新 ,如果多个数据被更改了,假设它们对应渲染的同一个watcher ,那么就可以等改完了之后再去更新,
如果是不相同的watcher(每次 new 一个 watcher 都有一个 id),可以把相同的过滤掉,就不用改一个数据更新一下试图了
nextTick dom 渲染完毕之后才会执行
nextTick 中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
主要思路就是采用微任务优先的方式调用异步方法去执行 nextTick 包装的方法。
computed 有缓存,只要数据没有变化就使用计算属性 (会有一个dirty 值,为 true 继续使用上次的计算结果值,为false 重新计算新的值)
只用在组件中,深层核心原理:递归,开销大哦
methods 每次都会执行这个方法,开销较大
watch 原理与 computed 相同,但是watch 没有缓存
computed 计算属性对应创建的函数默认是不会执行的,只有当在页面取值的时候才会执行
js 原型
每一个类都是一个显示原型prototype
每一个类都有一个隐式原型__proto__
实例的_proto__等于类的显示原型prototype
当去查找一个实例的属性或方法,先在自身查找,找不到则沿着__proto__向上查找
我们把原型__proto__与原型__proto__形成的链条关系叫做原型链
作用是:实现了JS的继承,让实列拥有了类的公用方法
箭头函数没有原型,原型是undefined
箭头函数this指向全局对象,而函数指向引用对象
JS中的实例是通过构造函数来创建的,每个构造函数可以new出很多个实例,那么每个实例都会继承原型上的方法或属性。
Vue的data数据其实是Vue原型上的属性,数据存在于内存当中。Vue为了保证每个实例上的data数据的独立性,规定了必须使用函数,而不是对象。
使用函数后,使用的是data()函数,data()函数中的this指向的是当前实例本身,就不会相互影响了。
在路由添加元信息,meta 字段,控制显示与隐藏 (利用 v-show="$route.meta.xxx")
路由跳转的方式:
声明式导航 router-link
编程式导航:利用的是组件实例的$router.push|replace方法,可以实现路由的跳转。(可以书写一些自己业务)
路由传参,参数有哪几种写法?
params参数:属于路径当中的一部分,需要注意,在配置路由的时候,需要占位
query参数:不属于路径当中的一部分,类似于ajax中的querystring /home?k=v&kv=,不需要占位
如何指定params参数可传可不传?
如果路由要求传递params参数,但是你就不传递params参数,发现一件事情,URL会有问题的
如何指定params参数可以传递、或者不传递,在配置路由index.js的时候,在占位的后面加上一个问号
使用 undefined 解决 params 可传可不传的情况下传递了一个空值; params:{keywords:'' || undefined}
路由组件能不能传递 props 数据?
布尔值写法只能传递 params
对象写法:不常用
函数写法;常用
{
path: '/search/:keywords?', // 加了一个问号,表示 params 可传可不传
name: 'Search',
component: Search,
meta:{show:true},
// 路由组件能传递 props 数据
// props:true, // 第一种方式布尔值写法:params
// props:{a:1,b:2} // 第二种方式对象写法,不常用的方法
// 常用函数写法
props:($route)=>{
return {
keywords:$route.params.keywords,username:$route.query.username
}
}
}
vuex 模块式开发
如果存储的数据非常多,为了方便管理,可以针对每一个模块建立一个小仓库,然后一次性将所有的小仓库导出,(例如本例中大仓库 store 中:Home 模块小仓库,Search 模块小仓库)
页面优化1:
快速滑动或者点击,浏览器来不及响应导致出现卡顿现象,可以利用函数防抖或节流:用户操作行为过快,前面所有的触发都会取消,只会执行最后一次。
性能优化1:
当一个组件在多个地方被引用,建议把它注册为全局组件 main.js 中 vue.component 注册 ,如果这个组件中有网络请求,且请求的内容没有变化,为了避免多次请求,建议把请求放在根组件 mounted,这样只需要请求一次。
性能优化2:
当用 v-for 遍历创建一个导航列表时,且每个导航 item 都能点击跳转到另一个页面。建议使用事件冒泡+编程式导航的方式,原因如下:
1)声明式导航 router-link 是组件,不宜使用它,加载组件需要时间,可能会出现卡顿现象。
2)直接使用编程式导航,每一个导航都有一个回调函数,造成回调函数过多。
3)事件冒泡:可以在导航列表的父元素身上添加一个事件,利用冒泡的原理,点击子元素,就会触发父元素身上的事件。
备注:可以通过在子元素身上添加自定义属性来区分其他没有点击的子元素
新创建一个模块顺序:
1.先静态页面 + 静态组件拆分
2.发请求(api)
3.vuex(三连环: state mutations actions)
4.组件获取仓库数据,动态展示