vue基础(2)

十.Prop传值

父组件向子组件传deptId参数:

<dynamic-report ref="DynamicReport" :deptId="deptId" />

子组件在props中接收deptId参数后,就可用this.deptId访问:

props: {
   deptId: {
      type: String,
      default: ''
   }
}

传递动态和静态prop

  1. 静态赋予一个变量的值
    <blog-post title="hellow Vue"></blog-post>
  2. 动态赋予一个变量的值
    <blog-post v-bind:title="post.title"></blog-post>

单向数据流
所有的prop参数都是自上而下传递,所以在子组件中不能够改变prop的值,否则控制台将报错。如果需要,可在子组件data中初始化

props: ['initialCounter'],
data: function () {
	return {
		counter: this.initialCounter
	}
}

Prop验证

  1. 带有默认值的对象
propE: {
	type: Object,
	// 对象或数组默认值必须从一个工厂函数获取 
	default: function () {
		return {
			message: 'hello'
		}
	}
},
  1. 自定义验证函数
propF: {
	validator: function (value) {
		// 这个值必须匹配下列字符串中的一个
		return ['success', 'warning', 'danger'].indexOf(value) !== -1
	}
}

$attrs和$listeners

  1. $listeners包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器,它可以通过 v-on=”$listeners” 传入内部组件。

  2. $attrs包含了父作用域中非props 特性绑定的属性 (class 和 style 除外)。当一个组件没有声明任何 props 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件。

  3. $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 请求,这也会耗费时间!

十三.处理边界情况

  1. 访问根实例($root)
    在每个子组件中,可以通过this.$root.xxx来访问根组件的数据属性,调用根组件的方法,但是不推荐这么使用,推荐使用vuex管理应用的状态。

  2. 访问父级组件实例($parent)
    和$root类似,$parent可以访问父组件的实例。但是当变更了父组件的数据,如果父组件变了,就难以查找这个变更从哪里发起的。

  3. 访问子组件实例或子元素($ref)
    <base-input ref="usernameInput"></base-input>
    现在在你已经定义了这个 ref 的组件里,你可以使用:
    this.$refs.usernameInput

  4. 依赖注入(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!'
  }
})

指令钩子函数

  1. bind
    只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  2. inserted
    被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
  3. update
    所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
  4. componentUpdated
    指令所在组件的 VNode 及其子 VNode 全部更新后调用。
  5. unbind
    只调用一次,指令与元素解绑时调用。

指令钩子函数参数

  1. el
    指令所绑定的元素,可以用来直接操作 DOM。
  2. binding
    一个对象,包含以下 property:
  3. name
    指令名,不包括 v- 前缀。
  4. value
    指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
  5. oldValue
    指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
  6. expression
    字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
  7. arg
    传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
  8. modifiers
    一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
  9. vnode
    Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
  10. 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-*’}

路由钩子函数

  1. 全局钩子函数。
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'
		}
})
  1. 针对单个路由钩子函数
beforeEnter(to, from, next){
		console.log('beforeEnter')
		next() //正常跳转,不写的话,不会跳转
}
  1. 组件级钩子函数
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()
}

编程式导航

  1. 声明式
    <router-link :to="...">

  2. 编程式
    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

  1. 配合路由缓存
<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页面不会被缓存
}
  1. 配合组件缓存
// 将缓存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

  1. State
    状态字段声明,获取使用this.$store.state.xxx
  2. 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
		},
	  }
})
  1. dispatch
    dispatch:含有异步操作,数据提交至 actions ,可用于向后台提交数据。

  2. commit
    同步操作,数据提交至 mutations ,可用于登录成功后读取用户信息写到缓存里。

  3. 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。

  1. 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 组合就派上用场了。

posted @ 2021-01-26 10:07  小韓烟柳  阅读(77)  评论(0)    收藏  举报