vue基础(2)
十.Prop传值
父组件向子组件传deptId参数:
<dynamic-report ref="DynamicReport" :deptId="deptId" />
子组件在props中接收deptId参数后,就可用this.deptId访问:
props: {
deptId: {
type: String,
default: ''
}
}
传递动态和静态prop
- 静态赋予一个变量的值
<blog-post title="hellow Vue"></blog-post> - 动态赋予一个变量的值
<blog-post v-bind:title="post.title"></blog-post>
单向数据流
所有的prop参数都是自上而下传递,所以在子组件中不能够改变prop的值,否则控制台将报错。如果需要,可在子组件data中初始化
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
Prop验证
- 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return {
message: 'hello'
}
}
},
- 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
$attrs和$listeners
-
$listeners包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器,它可以通过 v-on=”$listeners” 传入内部组件。
-
$attrs包含了父作用域中非props 特性绑定的属性 (class 和 style 除外)。当一个组件没有声明任何 props 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件。
-
$props:当前组件从父组件那里接收的参数,通俗的讲和$attr差不多,但是只包括在当前组件中定义了的props属性。
阅读此篇文章更易理解$attrs和$listeners的作用
https://blog.csdn.net/songxiugongwang/article/details/84001967
.sync修饰符
.sync是vue中用于实现简单的“双向绑定”的语法糖,在平时的开发中是非常实用的。
vue的prop是单向下行绑定:父级的prop的更新会向下流动到子组件中,但是反过来不行。
可是有些情况,我们需要对prop进行“双向绑定”。这个时候,就可以用.sync来解决
<text-document :title.sync="doc.title"></text-document>
当子组件需要更新 title 的值时,它需要显式地触发this.$emit('update:title', newValue)
十一.插槽(v-slot)
https://blog.csdn.net/qq_42205731/article/details/103796900
跟 v-on 和 v-bind 一样,v-slot 也有缩写,例如 v-slot:header 可以被重写为 #header
使用缩写的话,必须明确插槽名称,否则无效。
十二.动态组件和异步组件
1. 动态组件
// 动态组件中,根据业务需求给currentComponent赋予不同的组件,就能显示不同的组件,常用于tab的切换。
<keep-alive>
<component :is="currentComponent"></component>
</keep-alive>
实用keep-alive,将组件缓存起来,在tab切换的时候就不会每次都刷新。将保持该组件上一次的状态。
2. 异步组件
在路由参数列表中,配置如下代码
{
path: '/',
name: 'Home',
component: () => import('@/pages/home/Home.vue')
}, {
path: '/city',
name: 'City',
component: () => import('@/pages/city/City.vue')
},
使用了异步组件,首页完全加载的时间反而更长。这是因为ajax 请求也挺耗时的。
当我们 app.*.js 没有很大的时候,不建议使用异步组件。因为使用异步组件,会发送更过的ajax 请求,这也会耗费时间!
十三.处理边界情况
-
访问根实例($root)
在每个子组件中,可以通过this.$root.xxx来访问根组件的数据属性,调用根组件的方法,但是不推荐这么使用,推荐使用vuex管理应用的状态。 -
访问父级组件实例($parent)
和$root类似,$parent可以访问父组件的实例。但是当变更了父组件的数据,如果父组件变了,就难以查找这个变更从哪里发起的。 -
访问子组件实例或子元素($ref)
<base-input ref="usernameInput"></base-input>
现在在你已经定义了这个 ref 的组件里,你可以使用:
this.$refs.usernameInput -
依赖注入(provice, inject)
如果在某个组建中 ,有一个数据或者方法是所有后代组件都需要用到的,使用provide和inject可以很好的解决此类问题。
父组件中:
provide: function () {
return {
getMap: this.getMap
}
}
子组件中:
inject: ['getMap']
十四.混入(mixins)
在多个组件中如果存在相同的一些方法和处理逻辑,为了不重复写代码,可以使用mixins。
十五.自定义指令
<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
Vue.directive('demo', {
bind: function (el, binding, vnode) {
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ')
}
})
new Vue({
el: '#hook-arguments-example',
data: {
message: 'hello!'
}
})
指令钩子函数
- bind
只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。 - inserted
被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。 - update
所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。 - componentUpdated
指令所在组件的 VNode 及其子 VNode 全部更新后调用。 - unbind
只调用一次,指令与元素解绑时调用。
指令钩子函数参数
- el
指令所绑定的元素,可以用来直接操作 DOM。 - binding
一个对象,包含以下 property: - name
指令名,不包括 v- 前缀。 - value
指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。 - oldValue
指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。 - expression
字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。 - arg
传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。 - modifiers
一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。 - vnode
Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。 - oldVnode
上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
除了 el 之外,其它参数都应该是只读的,切勿进行修改。
如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。
十六.渲染函数
使用render动态渲染界面。
createElement(A,B,C); A:可以是标签名,组件名 B:就是标签/vue组件里面需要的数据 C :子节点
十七.路由
路由参数
| 模式 | 匹配路径 | $route.params |
|---|---|---|
| /user/:username | /user/evan | |
| /user/:username/post/:post_id | /user/evan/post/123 |
匹配所有路由:
{path:’*’}或
{path:’/demo-*’}
路由钩子函数
- 全局钩子函数。
router.beforeEach((to, from, next) => {
console.log('beforeEach')
//next() //如果要跳转的话,一定要写上next()
//next(false) //取消了导航
next() //正常跳转,不写的话,不会跳转
})
router.afterEach((to, from) => { // 举例: 通过跳转后改变document.title
if( to.meta.title ){
window.document.title = to.meta.title //每个路由下title
}else{
window.document.title = '默认的title'
}
})
- 针对单个路由钩子函数
beforeEnter(to, from, next){
console.log('beforeEnter')
next() //正常跳转,不写的话,不会跳转
}
- 组件级钩子函数
beforeRouteEnter(to, from, next){
// 这个路由钩子函数比生命周期beforeCreate函数先执行,所以this实例还没有创建出来
console.log("beforeRouteEnter")
console.log(this) //这时this还是undefinde,因为这个时候this实例还没有创建出来
next((vm) => { //vm,可以这个vm这个参数来获取this实例,接着就可以做修改了
vm.text = '改变了'
})
},
beforeRouteUpdate(to, from, next){
//可以解决二级导航时,页面只渲染一次的问题,也就是导航是否更新了,是否需要更新
console.log('beforeRouteUpdate')
next();
},
beforeRouteLeave(to, from, next){// 当离开组件时,是否允许离开
next()
}
编程式导航
-
声明式
<router-link :to="..."> -
编程式
router.push(...)
例如:
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
注意:如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。
取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path:
const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: '/user/${userId}' }) // -> /user/123
// 这里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user
hash和history的区别?
| Hash | History | |
|---|---|---|
| Url显示 | 有# | 无# |
| 回车刷新 | 可以加载到hash值对应页面 | 一般404 |
| 支持版本 | 支持低版本和IE浏览器 | HTML5新API |
**路由懒加载和按组分块**
const Foo = () => import('./Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
十八.页面缓存(keep-alive)
https://blog.csdn.net/fu983531588/article/details/90321827
- 配合路由缓存
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
//不缓存的页面
<router-view v-if="!$route.meta.keepAlive"></router-view>
============================
router中配置:
{
path:"/home",
component:home,
meta:{keepAlive: true} //home页面会被缓存
}
{
path:"/hello",
component:hello,
meta:{keepAlive: false} //hello页面不会被缓存
}
- 配合组件缓存
// 将缓存name为test-keep-alive的组件
<keep-alive include="test-keep-alive">
<component></component>
</keep-alive>
// 将不缓存name为test-keep-alive的组件
<keep-alive exclude="test-keep-alive">
<component></component>
</keep-alive>
十九.状态管理(Vuex)
https://www.cnblogs.com/cathy1024/p/11357454.html
- State
状态字段声明,获取使用this.$store.state.xxx - Mutation
改变store状态的唯一方法是提交(commit),在mutation中接受state,然后改变state状态。
<button @click="LoginHandle">登录</button>
LoginHandle () {
// 修改isLogin状态
this.$store.commit('changeLogin', true)
// 修改username状态
this.$store.commit('changeUsername', this.username)
// 修改password状态
this.$store.commit('changePassword', this.password)
}
=======================================================
const store = new Vuex.Store({
state: {
isLogin: false, //登录状态
username: '', //用户名 },
mutations: {
// 修改登录状态
changeLogin(state, data) {
state.isLogin = data
},
// 修改用户名状态
changeUsername(state, data) {
state.username = data
},
}
})
-
dispatch
dispatch:含有异步操作,数据提交至 actions ,可用于向后台提交数据。 -
commit
同步操作,数据提交至 mutations ,可用于登录成功后读取用户信息写到缓存里。 -
mapState
当一个组件需要获取多个状态时,将这些状态都声明为计算属性会重复冗余。
computed: ...mapState({
isLogin: state => state.isLogin,
username: state => state.username,
password: state => state.password
})
<template>
<div class="home">
登录状态:{{isLogin}} <br>
用户名:{{username}}<br>
密码:{{password}} <br>
</div>
</template>
在计算属性computed中使用mapState时,需要用展开运算符[...],不然computed中的其他方法将无效
6. Getter
主要作用是对state属性进行计算,可以理解类似于Vue中computed。
- mapGetters
和mapStates用法相同。
二十.extend和$mount
Vue.extend( options )
用法:使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。
data 选项是特例,需要注意 - 在 Vue.extend() 中它必须是函数
<div id="mount-point"></div>
// 创建构造器
var Profile = Vue.extend({
template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
data: function () {
return {
firstName: 'Walter',
lastName: 'White',
alias: 'Heisenberg'
}
}
})
// 创建 Profile 实例,并挂载到一个元素上。
new Profile().$mount('#mount-point')
结果如下:
<p>Walter White aka Heisenberg</p>
可以看到,extend 创建的是 Vue 构造器,而不是我们平时常写的组件实例,所以不可以通过 new Vue({ components: testExtend }) 来直接使用,需要通过 new Profile().$mount('#mount-point') 来挂载到指定的元素上。
为什么使用 extend
在 vue 项目中,我们有了初始化的根实例后,所有页面基本上都是通过 router 来管理,组件也是通过 import 来进行局部注册,所以组件的创建我们不需要去关注,相比 extend 要更省心一点点。但是这样做会有几个缺点:
组件模板都是事先定义好的,如果我要从接口动态渲染组件怎么办?
所有内容都是在 #app 下渲染,注册组件都是在当前位置渲染。如果我要实现一个类似于 window.alert() 提示组件要求像调用 JS 函数一样调用它,该怎么办?
这时候,Vue.extend + vm.$mount 组合就派上用场了。

浙公网安备 33010602011771号