配置 Vue 实例( 选项 )

  • Post author:
  • Post category:vue




一、总览

let vm = new Vue({
  /**
   * 各种选项(配置参数) 
   * Vue 提供的选项的值如果是函数时,不可用箭头函数,因为箭头函数的 this 与父级上下文绑定,并不指向 Vue 实例本身
   */

  // DOM
  // 要控制的 HTML 区域,源码会使用 document.querySelect('el的属性值'),所以 IE8 以下都不支持
  el,
  // 替换 el 选项挂载的元素为模板内容
  template,
  // 渲染函数,字符串模板的替代方案
  render,
  /**
   * 仅用于开发环境,在 render() 出现错误时,提供另外的渲染输出
   * 其错误将会作为第二个参数传递到 `renderError`。这个功能配合 hot-reload 非常实用
   */
  renderError,

  // 数据
  // 声明的数据都被挂载到了 Vue 实例上
  data,
  // 接收父组件传过来的值
  props,
  // 创建实例时手动传递 props,方便测试 props
  propsData,
  /**
   * 计算属性 
   * 依赖的数据(data 当中声明的响应式数据)缓存,一般用于管理表达式
   * 强调的是根据某个状态返回一个新状态
   */
  computed,
  /**
   * 监测属性
   * Vue 实例化时会调用 $watch() 方法遍历 watch 对象的每个属性
   * 强调的是观测某个状态,根据状态的改变而做事情
   */
  watch,
  // 定义可以通过vm对象访问的方法
  methods,

  // 生命周期钩子函数——全部组件一些特殊的时间点
  // 发生在 Vue 实例初始化之后,data observer 和 event/watcher 事件被配置之前
  beforeCreate,
  // 发生在 Vue 实例初始化以及 data observer 和 event/watcher 事件被配置之后
  created,
  // 挂载开始之前被调用,此时 render() 首次被调用
  beforeMount,
  // el 被新建的 vm.$el 替换,并挂载到实例上之后调用——等到页面加载完毕
  mounted,
  // 数据更新时调用,发生在 VDOM 重新渲染和打补丁之前
  beforeUpdate,
  // 数据更改导致 VDOM 重新渲染和打补丁之后被调用
  updated,
  // 实例销毁之前调用,Vue 实例依然可用
  beforeDestroy,
  // Vue 实例销毁后调用,事件监听和子实例全部被移除,释放系统资源
  destroyed,
  
  // 生命周期钩子函数——缓存组件(被 keep-alive 包裹的组件)
  // 组件激活时调用
  activated,
  // 组件停用时调用
  deactivated,
  
  // 资源
  // 包含 Vue 实例可用指令的哈希表,组件(局部)指令
  directives,
  // 包含 Vue 实例可用过滤器的哈希表,组件(局部)过滤器
  filters,
  // 包含 Vue 实例可用组件的哈希表,引入组件,组件可以写在别的文件中,也可以写在本文件中,需要赋值给变量
  components,
  
  // 组合
  //指定当前实例的父实例,子实例用 this.$parent 访问父实例,父实例通过 $children 数组访问子实例
  parent,
  // 将属性混入 Vue 实例对象,并在 Vue 自身实例对象的属性被调用之前得到执行
  mixins,
  // 用于声明继承另一个组件,从而无需使用 Vue.extend,便于扩展单文件组件
  extends,
  // 两个属性需要一起使用,用来向所有子组件注入依赖,类似于 React 的 Context
  provide && inject,
  
  // 其它
  // 允许组件递归调用自身,便于调试时显示更加友好的警告信息
  name,
  // 改变模板字符串的风格,默认为{{}}
  delimiters,
  // 让组件无状态(没有 data)和无实例(没有 this 上下文)
  functional,
  // 允许自定义组件使用 v-model 时定制 prop 和 event
  model,
  // 默认情况下,父作用域的非 props 属性绑定会应用在子组件的根元素上。当编写嵌套有其它组件或元素的组件时,可以将该属性设置为 false 关闭这些默认行为
  inheritAttrs,
  // 设为 true 时会保留并且渲染模板中的 HTML 注释
  comments
});



二、DOM



2.1 el && template 选项

<div id="app">hello</div>

<script>
  const vm = new Vue({
    el: '#app',
    template: `<div id="ceshi">xxx</div>`,
  })

	console.log(vm.$el); // <div id="ceshi">xxx</div>
</script>



2.2 render 选项

一种可以用


JS


来创建


HTML


的方案,如果该函数存在,则


Vue


构造函数不会从


template


选项或通过


el


选项指定的挂在元素中提取出的


HTML


模板编译渲染函数,组件中的


template


会被编译成


render


函数。

因为


Vue





VDOM


,所以在拿到


template


模板时也要转译成


VNode


的函数,而用


render


函数构建


DOM





Vue


就免去了转译的过程。当使用


render


函数描述


VDOM


时,


Vue


提供一个函数,这个函数是就构建


VDOM


所需要的工具。官方名字叫


createElement


,还有约定的简写叫


h


render: (h ,params) =>{
    let that = this;
  	// h => createElement("定义的元素 ",{ 元素的性质 }," 元素的内容"/[元素的内容])
    return h('div', that.getHTML(h,params.row));
}

getHTML ( h , row ) {
    let status = row.status;
    let that = this;
 
    let editButtonStyle = {
        props: {
            type: 'success',
            size: 'small',
            ghost: true
        },
        on: {
            click: () => {
                that.edit(row);
            }
        }
    };
    let editButton = h( 'Button' , editButtonStyle , '编辑' );
 
    let viewSourceButtonStyle = {
        props: {
            type: 'primary',
            size: 'small',
            ghost: true
        },
        style: {
            marginLeft: '20px'
        },
        on: {
            click: () => {
                that.viewSource(row);
            }
        }
    };
    let viewSourceButton = h( 'Button' , viewSourceButtonStyle , '查看' );
 
    let obsoleteButtonStyle = {
        props: {
            type: 'error',
            size: 'small',
            ghost: true
        },
        style: {
            marginLeft: '20px'
        },
        on: {
            click: () => {
                that.obsolete(row);
            }
        }
    };
    let obsoleteButtonButton = h( 'Button' , obsoleteButtonStyle , '作废' );
 
    let invalidButtonStyle = {
        props: {
            type: 'error',
            size: 'small',
            ghost: true,
            disabled: true
        },
        style: {
            marginLeft: '20px'
        },
    };
    let invalidButton = h( 'Button' , invalidButtonStyle , '已作废' );
 
    let data = [];
    if( status == 0 ){ // 正常
        data = [ editButton, viewSourceButton, obsoleteButtonButton ];
    }else { // 作废
        data = [ viewSourceButton,invalidButton ];
    }
    return data;
}

通过


render


函数实现


VDOM


比较麻烦,因此可以使用


babel-plugin-transform-vue-jsx





render


函数中应用


JSX


语法。

import Header from "./Header.vue"
new Vue({
  el: "#demo",
  render (h) {
    return (
      <Header level={1}>
        <span>AI-fisher</span>
      </Header>
    )
  }
})



2.3 renderError 选项

new Vue({
  render (h) {
    throw new Error('oops')
  },
  renderError (h, err) {
    // h => (createElement: () => VNode, error: Error) => VNode
    return h('pre', { style: { color: 'red' }}, err.stack)
  }
}).$mount('#app')



三、数据



3.1 data 选项

声明需要响应式绑定的数据对象,配合


{

{}}


渲染可以实现面向数据编程,即数据变化后,框架会自动渲染(实现


DOM


操作),这样就会提高性能

【注】项目当中需要用函数返回该对象,理由:

1、不使用


return


这种方式的数据会在项目的全局可见,会造成变量污染

2、把


data


包裹成函数以后,变量只在当前组件中生效,不会影响其他组件

<div id="app">
    <!-- 平台:CSDN -->
    平台:<span>{{ blog }}</span><br/>
    <!-- 用户:AI-fisher -->
    用户:<span>{{ username }}</span>
</div>
<script>
    let myVm = new Vue({
        el: '#app',
        data: {   
            blog: 'CSDN',
            username: 'AI-fisher'
        }  
    });  
</script>




data


选项中自定义了两个属性:


blog





username


,然后通过一种古老的模板语法:


mustach


,把他们的值绑定到了页面上,下面来打印一下这个实例:

console.log(myVm);

控制台打印结果(部分):

image.png

可以看到自定义属性被设置成了该实例的属性($开头表示是系统自带),所以说页面才能拿得到


blog





username


这两个属性的值,既然是实例属性,那么用


this


来访问也是可以的了:

<div id="app">
    <!-- 平台:CSDN -->
    平台:<span>{{ this.blog }}</span><br/>  
    <!-- 用户:AI-fisher -->
    用户:<span>{{ this.username }}</span>
</div>
<script>
    let myVm = new Vue({
        el:'#app',
        data:{   
            blog: 'CSDN',      
            username: 'AI-fisher'    
        }  
    });  
</script>

只不过,


this


可以省略,我们直接通过双大括号包裹该实例属性的属性名就可以在页面绑定数据了。当然,该数据绑定还是响应式的,是指当数据改变后,


Vue


会通知到使用该数据的代码。例如,视图渲染中使用了数据,数据改变后,视图也会自动更新(也可以理解为数据同步)。

浏览器刷新页面的时候,计算机内存中会产生一个


JS


的对象树,里面做了相应的映射来描述整个


HTML


的结构,我们只需操作这个虚拟的


JS


对象,不用操作真正的


DOM


,响应式系统在数据变化的时候,会去循环这个


JS


对象,在把要改变的内容上做标记。然后等整个循环完成之后,然后去逐个去操作


DOM


。一个标签有很多的属性,改其中一个属性并不会去替换整个元素,而是保留尽可能多的属性,只是替换器中某一部分,所以性能较高。



3.2 props 选项



props


选项用来接收父组件传过来的值(可读不可写),然后通过和访问


data


一样的方式:


mustach


语法{

{ 属性名 }}就可以访问到传递的数据

  • 数组——无类型校验
props: ['test', 'count', 'flag', 'tip']
  • 对象——有类型校验

为了检测数据的正确性,只能起到提示作用,并不会阻止程序的正常运行,因为类型的检测本就不是


JS


的强项

  • 写法一:验证传递数据的有效性 —- 如果数据类型不对,会报出警告,可以及时调整
props: {             
    test: String,             
    count: Number,             
    flag: Boolean,             
    tip: [String, Number, Object]
}
  • 写法二:既要验证数据的类型,又要设定属性的默认值,如果默认值是对象或者是数组,值为一个函数
props: {    
    test: {      
        type: String,           // 数据类型
        default: '测试数据了',       // 默认值
        required: true,              // 是否必传
        validator: function(value){
            return value == 0       // 是否符合某种自定义的规则
        }
    }  
}



3.3 propsData 选项



propsData


和属性无关,它用在全局扩展时进行传递数据

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>propsData属性</title>
		<script src="../assets/js/vue.js"></script>
	</head>
	<body>
		<header></header>
		<script type="text/javascript">
			var demo = Vue.extend({
				template:`<p style="color:red">这是利用propsData传递数据-----{{demo}}---{{a}}</p>`,
				data() {
					return{
						demo:'这里采用了插值的方式'
					}
				},
				props:['a']
			});
			new demo({ propsData: { a: 'propsData设置值' } }).$mount('header')
		</script>
	</body>
</html>



3.4 computed 选项




HTML


模板表达式中放置太多的业务逻辑,会让模板过重且难以维护。因此,可以考虑将模板中比较复杂的表达式拆分到


computed


属性当中进行计算。每个计算属性都是函数的形式,不过要求必须有返回值,所以就相当于用函数的返回值来模拟一个属性值。相对于


watch





filters


,它更适合当模板中的某个值需要通过一个或多个数据计算得到(依赖这些数据)的场景,有缓存性(页面重新渲染的时候依赖的数据不变化,会立即返回之前的计算结果,而不必再执行函数)

<div id="app">
    <!-- CSDN——AI-fisher -->
    {{ information }}
</div>
<script>    
    new Vue({        
        el: '#app',        
        data: {            
            blog: 'CSDN',            
            username: 'AI-fisher'
        },        
        computed: {            
            information () {    
                return `${this.blog}——${this.username}`;
            }
        }
    })
</script>

计算属性只在相关依赖发生改变时才会重新求值,这意味只要上面例子中的


message


没有发生改变,多次访问 计算属性总会返回之前的计算结果,而不必再次执行函数,这是


computed





method


的一个重要区别。

计算属性默认只拥有


getter


方法,但是可以自定义一个


setter


方法。

<script>
  ... ... ...
  computed: {
    fullName: {
      // getter
      get: function () {
        return this.firstName + " " + this.lastName
      },
      // setter
      set: function (newValue) {
        var names = newValue.split(" ")
        this.firstName = names[0]
        this.lastName = names[names.length - 1]
      }
    }
  }
  ... ... ...
  // 下面语句触发setter方法,firstName和lastName也会被相应更新
  vm.fullName = "John Doe"
</script>



3.5 watch 选项

通过


watch


属性可以手动观察


Vue


实例上的数据变动,当然也可以调用实例上的


vm.$watch


达到相同的目的。相对于


computed





filters


,它更适合监听某个值发生变化后,需要进行一些逻辑处理的场景,无缓存性(页面重新渲染时,就算值不变化也会执行)

  • 浅层描述

    • 基本操作
<div id="app"></div>
<script>    
let vm= new Vue({        
        el: '#app',        
        data: {            
            blog: 'CSDN'
        },        
        watch: {            
            blog () {    
               console.log('侦听的数据变化了!');
            }
        }
    })
</script>

在谷歌浏览器的控制台中作如下操作

>  vm.blog                        // 初始数据
<· "CSDN"       
>  vm.blog='博客园'            // 修改观测的数据
   侦听的数据变化了!
<· "博客园"
  • 获取变化前和变化后的值
<div id="app"></div>
<script>    
    new Vue({        
        el: '#app',        
        data: {            
            blog: 'CSDN',            
            username: 'AI-fisher'
        },        
        watch: {            
            blog (newValue, oldValue) {    
               console.log(`侦听的数据变化了!新的值为:${newValue},旧的值为:${oldValue}`);
            }
        }
    })
</script>
>  vm.blog                   // 初始数据
<· "CSDN"
>  vm.blog='博客园'       // 修改观测的数据
    侦听的数据变化了!新的值为:博客园,旧的值为:CSDN
<· "博客园"
  • 侦听的属性发生变化后执行某项功能,这个情况下,侦听属性就比计算属性有优势了
<div id="app"></div>
<script>    
    let vm = new Vue({
        el:'#app',        
        data:{
            ipt:'bmw'        
        },        
        methods:{            
            show(){
                console.log('ipt属性的值发生改变了我才会执行!')
            }        
        },        
        watch:{            
            ipt:'show'        
        }    
   });
</script>

在谷歌浏览器的控制台中作如下操作

>  vm.ipt                        
<· "bmw"       
>  vm.ipt='AI-fisher'            
    侦听的数据变化了!
<· "AI-fisher"
  • 深层描述

    之前的案例对侦听的属性进行的描述不够深,如果要进行深层次的描述的话,就要用到对象来进行描述,里面还要设置一些参数。

    • 设置数据从无到有时也要执行(首次运行)
<div id="app"></div>
<script>    
    let vm = new Vue({        
        el:'#app',        
        data:{
            ipt:'bmw'        
        },        
        watch:{            
            ipt: {                
                handler(newValue, oldValue){                    
                    console.log("ipt的值从无到有我就执行!",oldValue,newValue);                
                },                
                immediate: true            
            }        
        }    
    });
</script>

在谷歌浏览器运行,控制台出现的结果:

ipt的值从无到有我就执行! undefined bmw
  • 设置深度检测(监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器,性能开销大,任何修改


    obj


    里面任何一个属性都会触发这个监听器里的


    handler


<div id="app"></div>
<script>    
    let vm = new Vue({        
        el:'#app',        
        data:{            
            json:{a:1,b:2}        
        },       
        watch:{            
            json:{                
                handler(newValue,oldValue){
                    console.log('深度检测!',oldValue,newValue)                
                },                
                deep: true // 深度检测 复合数据类型            
            }        
        }    
    });
</script>

image.png

这里因为对象用到的是索引,这是打印本身的问题,不用去管它,我们只关心前后的值确实拿到了,而且是以对象的形式呈现的。


【注】:

  • 方法:每次都调用,强制渲染
  • 计算属性:必须在模板中调用才能执行,性能高:,适合做筛选,基于它们的响应式依赖进行缓存
  • 数据观测:不用在模板中渲染,默认状态下数据的从无到有不会调用,只有后期观测的数据发生变化时才会执行



3.6 methods 选项

<div id="app">
    <button v-on:click="showMsg">无括号调用</button>  
    <button v-on:click="showMsg()">加括号调用</button>
</div>
<script>
    new Vue({  
        el: '#app', 
        data: {    
            msg: 'AI-fisher'  
        },  
        methods: {
            showMsg () {
                alert(this.msg);   
            }  
        }
    })
</script>

点击页面上的两个按钮,控制台打印的都是


“AI-fisher”


,所以说这两种调用方式是相同的效果




四、生命周期钩子函数——全部组件



4.1 简介

生命周期钩子函数其实就是


Vue


实例的选项,这些选项的值全部都是函数,代表了该实例从出生到死亡这一生当中的各阶段,只要达到该阶段就会自动触发。生命周期的钩子函数都是同步执行的,不会有异步队列,也就是初始化实例的一瞬间全部执行完毕。



4.2 图示

image.jpeg

当初始化实例的一瞬间,它内部会构建一些响应式事件监听的机制,然后所有的钩子函数就会生成,之后接纳用户定义的那些数据,比如


data





methods


之类的。

通过


el


选项或者


vm.$mount(el)


来匹配要控制的


HTML


区域,然后拿


template


模板中的


HTML


代码去编译,如果没有的话,就直接找外面的


HTML


,之后通过


VDOM


去替换真实


DOM


,然后真实


DOM


就会被挂载,接下来就会处于一种停歇的状态。

当用户更新


model


层的数据,


VDOM


就会重新渲染,这种可更新状态一直持续到组件被


vm.$destory


卸载,卸载后数据观测以及里面的子实例身上绑定的相应式监听式事件会被全部取消,之后再来修改


model


层数据不会有任何效果。



4.3 辅助理解


初始化阶段

beforeCreate(){} // 准备怀孕

created(){} // 怀上了

beforeMount(){} // 准备生

mounted(){} // 生下来了


运行阶段

beforeUpdate(){} // 每天都在长大

updated(){} // 每次成长后


销毁阶段

beforeDestroy(){} // 即将舍弃肉身

destroyed(){} // 羽化登仙



4.4 使用



mounted


中能拿到所有的数据,是最安全的选择。当然,在***created*** 或者


mounted


中都可以请求数据,如果必须使用


DOM


操作,那么可以在


mounted





updated


中进行。以下对一些数据在各阶段进行了测试:


初始化阶段

beforeCreate

拿不到:data 数据、实例方法、ref 元素(真实的 DOM 元素)

能拿到:钩子函数、自定义选项

created

拿不到:ref 元素(真实的 DOM 元素)

能拿到:data 数据、实例方法、钩子函数、自定义选项

beforeMount

拿不到:ref 元素(真实的 DOM 元素)

能拿到:data 数据、实例方法、钩子函数、自定义选项

mounted

能拿到所有

当然,之后的钩子函数(除了销毁之后)肯定也能拿到所有,不用再做讨论


运行时阶段

beforeUpdate

能拿到所有

打印的是更新后的数据,但是当这个钩子打印的时候,数据并没有渲染到页面,也就是 VDOM 更新了,但真实 DOM 并没有更新

updated

能拿到所有

这个钩子是在真实 DOM 已经渲染完成后才执行函数中的业务逻辑


销毁阶段

beforeDestroy

能拿到所有

destroyed

拿不到:ref 元素(真实的 DOM元素)

能拿到:data 数据、实例方法、钩子函数、自定义选项



4.5 多组件生命周期关系


在这里插入图片描述




五、生命周期钩子函数——缓存组件

缓存组件包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。 是一个抽象组件,它自身不会渲染一个


DOM


元素,也不会出现在父组件链中。包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

当动态组件在缓存组件内被切换,它的


activated





deactivated


这两个生命周期钩子函数将会被对应执行。​




六、资源



6.1 directives 选项

该选项可以配置组件专属的指令

  • 使用:在自定义的指令名称前面加上


    v-前缀


    使用即可
  • 配置
directives: {
  "local-test": function(el, binding, vnode) {
    /** el 可以获取当前 DOM 节点,并且进行编译,也可以操作事件 **/
    /** binding 指的是一个对象,一般不用 **/
    /** VNode 是 Vue 编译生成的虚拟节点 **/
    el.style.border = "1px solid red"; //操作 style 所有样式
    console.log(el.value); //获取 v-model 的值
    console.log(el.dataset.name); // data-nam e绑定的值,需要 el.dataset 来获取
    console.log(vnode.context.$route); //获取当前路由信息
  }
},



6.2 filters 选项

该选项可以配置组件专属的过滤器,相对于


computed





filters


,它更适合对自身数据进行一些处理,比如日期格式化,无缓存性

  • 使用:现在只能在


    mustache


    插值和


    v-bind


    表达式中使用,用 | (过滤管道符)把需要过滤的值和过滤器连接起来
<!-- 在双花括号中 -->
{{ message | capitalize }}

<!--`v-bind`-->
<div v-bind:id="rawId | formatId"></div>
  • 配置
filters: {
  capitalize (value) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
  }
}



6.3 components 选项

<div id="app">
	<my-header></my-header>  
</div>

<script>
  import MyHeader from './components/MyHeader'
  const vm = new Vue({
    el: '#app',
    components: {
      'my-header': MyHeader
    } 
  })
</script>



七、组合



7.1 parent 选项

指定已创建的实例之父实例,在两者之间建立父子关系。子实例可以用


this.$parent


访问父实例,子实例被推入父实例的


$children


数组中

let parentVm = new Vue({
  el: "#app",
  data: {
    msg: "parent"
  }
});

let childVm = new Vue({
  data: {
    msg_: "child"
  },
  methods: {
    getChildVmFunc() {
      console.log("the root data is: " + this.$parent.msg);   // parent
    }
  },
  parent: parentVm
});



7.2 mixins 选项

用来将指定的


mixin


对象复用到


Vue


组件当中

// mixin对象
var mixin = {
  created: function () {
    console.log("mixin 钩子")
  },
  methods: {
    foo() {
      console.log("foo")
    },
    conflicting() {
      console.log("mixin conflicting")
    }
  }
}

// vue属性
var vm = new Vue({
  mixins: [mixin],
  created: function () {
    console.log("self 钩子")
  },
  methods: {
    bar() {
      console.log("bar")
    },
    conflicting() {
      console.log("self conflicting")
    }
  }
})

// mixin 钩子
// self 钩子
vm.foo() // foo
vm.bar() // bar
vm.conflicting() 	// self conflicting

同名组件


option


对象的属性会被合并为数组依次进行调用,其中


mixin


对象里的属性会被首先调用。如果组件


option


对象的属性值是一个对象,则


mixin


中的属性会被忽略掉。



7.3 extends 选项



  • Vue





    extends





    mixins


    类似,通过暴露一个


    extends


    对象到组件中使用。


  • extends


    会比


    mixins


    先执行。执行顺序:


    extends > mixins > 组件



  • extends


    只能暴露一个


    extends


    对象,暴露多个


    extends


    不会执行
// 暴露两个 mixins 对象
export const mixinsTest = {
    methods: {
        hello() {
            console.log("hello mixins");
        }
    },
    beforeCreate(){
        console.log("混入的beforeCreated");
        
    },
    created() {
        this.hello();
    },
}


export const mixinsTest2 = {
    methods:{
        hello2(){
            console.log("hello2");
        }
    },
    created() {
        this.hello2();
    },
}

// 只能使用一个 extends 对象,多个无效,extends 会先于 mixins 执行
export const extendsTest = {
    methods: {
        hello3() {
            console.log("hello extends");
        }
    },
    beforeCreate(){
        console.log("extends的beforeCreated");
        
    },
    created() {
        this.hello3();
    },
}

// vue组件
<template>
	<div>home</div>
</template>
<script>
import {mixinsTest,mixinsTest2,extendsTest} from '../util/test.js'
export default {
  name: "Home",
  data () {
    return {
    };
  },
    beforeCreate(){
        console.log("组件的beforeCreated");
        
    },
  created(){
      console.log("1212");
  },
  mixins:[mixinsTest2,mixinsTest], // 先调用哪个 mixins 对象,就先执行哪个
 	extends:extendsTest  // 使用extends
}
</script>
<style lang="css" scoped>
</style>



7.4 provide && inject 选项

实现跨组件传值,数据的流只能是向下传递,本身是非响应式的,但是可以通过传一个响应式数据来实现响应式



  • provide


    :根组件(指需要传递的数据所在的最外层组件,而非


    App.vue


    )进行使用,用来给后代组件注入依赖(属性或方法)


  • inject


    :子组件进行使用,用来获取根组件定义的跨组件传递的数据
<template>
  <div id="app">
    <h1>数据源的根组件</h1>
    <ChildN />
  </div>
</template>

<script>
import ChildN from './components/ChildN'
export default {
  components:{
    ChildN,
  },
  // 方法模式 ( 推荐使用 )。
  // provide(){
  //  return{
  //   'userName': 'AI-fisher'
  //  }
  // }
  // 对象模式
  provide : {  
    "userName": 'AI-fisher',
  }
}
</script>

ChildN.vue

<template>
  <div class="box">
    <h2>某一个后代组件</h2>
  	<h3>接受到根组件的传递的数据{{ userName1 }}</h3>
  </div>
</template>

<script>
export default {
	// 数组接收
  // inject: ['userName']   

	// 对象接收
  // inject : {                   
  //   userName1: 'userName'
  // }
  inject : {                   
    userName1: { // 指定别名,为了避免和 props 之类的重名冲突
      from: 'userName', // 原名
      default : '默认值'  // 指定默认值
    }
  }
}
</script>



八、其它



8.1 name 选项



name


选项就是给该组件起一个唯一的名字,有如下作用:

  • 项目中有缓存组件时,


    name


    可以用作


    include





    exclude


    的值
  • 递归组件,顾名思义,就是在自己的内部实现需要调用自身
  • 调试用,在


    vue-tools


    调试时,显示的就是


    name


    选项的值



8.2 delimiters 选项

作用是改变我们插值的符号,


Vue


默认的插值是双大括号


{

{ }}


,在一些特殊的情况下我们可能会用到其他的方式绑定插值,比如避免在一些使用


{

{ }}


绑定数据的开发模式中和


Vue


冲突

// 将插值形式变成${}
delimiters : [ '${' , '}' ]



8.3 functional 选项

把组件变成只接受


prop


的函数组件,无状态(没有响应式数据),没有实例(


this


上下文 ),只用来展示

// template 写法
// props 父组件传递的数据
<template functional>
  <div>{{props.name}}</div>
</template>

// jsx 写法
Vue.component('my-component', {
  functional: true,
  // 可选
  props: {},
  render (createElement, context) {
  }
})



8.4 model 选项

该选项允许一个自定义组件在使用


v-model


时定制


prop





event





v-model


只是语法糖,默认情况下,一个组件上的


v-model


会把


value


用作


prop


属性值且把


input


用作


event


属性值,现在拆分一个例子

// 分解后 <my-input :value="foo" @input="val => { foo = val }"></my-input>
<my-input v-model="foo"></my-input>
Vue.component('my-input', {
	model: {
	 prop: 'value',
	 event: 'input',
	},
	props: {
		value: String,
	},
	template: '<input type="text" :value="value" @input="$emit($event.target.value)"/>',
})

通过上面的分析,默认情况下,一个组件上的


v-model


会把


value


用作


prop


且把


input


用作


event


。所以当我们在一个自定义组件上使用


v-model


并不能实现双向绑定,因为自定的组件并没有默认的


value





input


事件,在使用时,我们需要按照上面那样显式的去声明定义这些东西。这时,


model


选项就派上用场了,在定义组件的时候,指定


prop


的值和监听的事件。

所以要想自定义


v-model


,比如改为

<my-input :foo="foo" @change="val => { foo = val }"></my-input>

那么,可以这样实现

<my-input v-model="foo"></my-input>
Vue.component('my-input', {
	 model: {
	  prop: 'foo',   // 绑定值修改为 foo
	  event: 'change',  // 事件修改为 change
	},
	props: {
		foo: String,  // 此时父组件传递过来的变量就是 foo
	},
	template: '<input type="text" :value="value" @input="$emit($event.target.value)"/>',
})



8.5 inheritAttrs 选项

官方:如果你不希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false

父组件

<template>
 <div class="parent">
    <child-component user="AI-fisher"></child-component>
  </div>
</template>
<script>
import ChildComponent from './child-component'
export default {
  components: {
    ChildComponent
  }
}
</script>

子组件(


inheritAttrs: true


<template>
  <div class="child">子组件</div>
</template>
<script>
export default {
  inheritAttrs: true,
  mounted() {
    console.log(this.$attrs) // {user: 'AI-fisher'}
  }
}
</script>

渲染结果

<div ...... class="parent">
  <div ...... class="child" user="AI-fisher">子组件</div>
</div>

子组件(


inheritAttrs: false


<template>
  <div class="child">子组件</div>
</template>
<script>
export default {
  inheritAttrs: false,
  mounted() {
    console.log(this.$attrs) // {user: 'AI-fisher'}
  }
}
</script>

渲染结果

<div ...... class="parent">
  <div ...... class="child"">子组件</div>
</div>

总结:

由上述例子可以看出,前提:子组件的


props


中未注册父组件传递过来的属性。

  1. 当设置


    inheritAttrs: true


    (默认)时,子组件的顶层标签元素中(本例子的


    div


    元素)会渲染出父组件传递过来的属性
  2. 当设置


    inheritAttrs: false


    时,子组件的顶层标签元素中(本例子的


    div


    元素)不会渲染出父组件传递过来的属性
  3. 不管


    inheritAttrs





    true


    或者


    false


    ,子组件中都能通过


    $attrs


    属性获取到父组件中传递过来的属性



8.6 comments 选项

这个选项只在完整构建版本中的浏览器内编译时可用。当设为


true


时,将会保留且渲染模板中的


HTML


注释。默认行为是舍弃它们。

new Vue({
  el: '#app',
  comments: true,
  ...App
})



版权声明:本文为weixin_37844113原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。