组件的特点

  • 可复用
  • 方便维护
  • 每一个vue组件都是一个独立的个体(独立的vm实例);DATA是独立的(不同组件的data互不干扰)、有完整的生命周期、方法都是独立的
  • 能够实现组件的嵌套;需要掌握组件之间的信息通信

    全局组件

    无需单独引用或者配置,直接在大组件中调取全局组件即可 ```javascript Vue.component(组件名,options)

options可以使用的有vm实例具备的大部分(data,methods,生命周期函数…)

每调用一个组件都是创建一个单独的vue实例(VueComponent->Vue)

  1. <a name="7lS22"></a>
  2. ## 组件的命名规则
  3. - kebab-case:短横线作为分隔符,只能基于kebab方法调取
  4. - PasalCase:单词首字母大写,也是基于kebab方式调取(如果在template模板中可以使用Pasal方式调取)
  5. - 调取组件的时候,会把所有组件的单词渲染为小写字母(命名除了PaselCase模式外,都要把组件名设置为小写,调取组件的时候可以是大写也可以是小写,最后都是按小写渲染的)
  6. - 命名的时候尽量不要出现其余的特殊字符
  7. ```html
  8. <!DOCTYPE html>
  9. <html>
  10. <head>
  11. <meta charset="UTF-8">
  12. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  13. <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0">
  14. <title></title>
  15. </head>
  16. <body>
  17. <div id="app">
  18. <h3 v-text='title'></h3>
  19. <!--
  20. 调取组件
  21. + 单闭合:不符合w3c规范,调取完成后,后面的视图不识别(避免使用)
  22. + 双闭合:可以设置除组件规定内容外的其余内容(slot插槽)
  23. -->
  24. <my-button/>
  25. <my-button>
  26. 我加的其它内容(slot 插槽)
  27. </my-button>
  28. </div>
  29. <!-- IMPORT JS -->
  30. <script src="./node_modules/vue/dist/vue.js"></script>
  31. <script>
  32. //全局组件
  33. Vue.component('MyButton', {
  34. template: `<button>组件中的按钮</button>`
  35. });
  36. let vm = new Vue({
  37. el: '#app',
  38. data: {
  39. title: '我很开心'
  40. }
  41. });
  42. </script>
  43. </body>
  44. </html>

局部组件

父子通信

子组件通过props接受父组件的数据,子组件通过$emit触发父组件的自定义事件

父组件传递数据给子组件

父组件传递数据给子组件实质: 是通过行内属性的方式传递给子组件
父传子: 让子组件使用父组件的数据
1、$parent 通过获取组件的方式
2、自定义属性 + props (type default required validator)
3、$attrs 可以获取没有被props接收的剩余的属性
4、provide/inject
5、$children + 索引
6、$refs
—— $root

1. props

prop的大小写

在dom中的模块,驼峰命名的prop名要使用短横线分割命名替换,但是如果是字符串模板,则没有此限制

prop的类型

  1. /* props: {
  2. title: String,
  3. likes: Number,
  4. isPublished: Boolean,
  5. commentIds: Array,
  6. author: Object,
  7. callback: Function,
  8. contactsPromise: Promise // or any other constructor
  9. }
  10. */
  11. function a(id){
  12. this.id=id
  13. }
  14. Vue.component('blog-post', {
  15. props: {
  16. author: a
  17. }
  18. })

prop的验证

  1. //type类型可以是string,number,boolean,array,object,data,function,symbol
  2. //type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认
  3. Vue.component('my-component', {
  4. props: {
  5. // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
  6. propA: Number,
  7. // 多个可能的类型
  8. propB: [String, Number],
  9. // 必填的字符串
  10. propC: {
  11. type: String,
  12. required: true
  13. },
  14. // 带有默认值的数字
  15. propD: {
  16. type: Number,
  17. default: 100
  18. },
  19. // 带有默认值的对象
  20. propE: {
  21. type: Object,
  22. // 对象或数组默认值必须从一个工厂函数获取
  23. default: function () {
  24. return { message: 'hello' }
  25. }
  26. },
  27. // 自定义验证函数
  28. propF: {
  29. validator: function (value) {
  30. // validator 是自定义的校验函数
  31. // val 就是这个 prop 收到的值
  32. // 自定义校验规则,如果校验通过return true,否则抛出异常或者return false
  33. // 这个值必须匹配下列字符串中的一个
  34. return ['success', 'warning', 'danger'].indexOf(value) !== -1
  35. }
  36. }
  37. }
  38. })

注意点:prop 会在一个组件实例创建之前进行验证,实例的属性 (如 data、computed 等) 在 default 或 validator 函数中是不可用的。

prop静态传值或者动态传值

prop是父组件传递数据的自定义属性。

  1. prop 传递静态的,直接传一个值
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. </head>
  6. <body>
  7. <!-- 父组件 -->
  8. <div id="app">
  9. <son sonvalue3="'abcd'" sonvalue="f" sonvalue2="33"></son>
  10. </div>
  11. <!-- 子组件,此处静态传数据时,必须是确定值 -->
  12. <template id="son">
  13. <div>
  14. <h2>我是子组件</h2>
  15. 引用父组件中的数据项:{{sonvalue}}- {{sonvalue2}}- {{sonvalue3}}
  16. </div>
  17. </template>
  18. <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  19. <script type="text/javascript">
  20. //1.定义组件对象
  21. let Son = {
  22. template: "#son",
  23. props: {
  24. sonvalue: {
  25. type: Number
  26. },
  27. sonvalue2: {
  28. type: Number,
  29. default: 23
  30. },
  31. sonvalue3: {
  32. type: String,
  33. required: true
  34. }
  35. }
  36. }
  37. let vm = new Vue({
  38. el: "#app",
  39. components: { //2.注册组件对象
  40. Son
  41. }
  42. });
  43. </script>
  44. </body>
  45. </html>
  1. prop使用v-bind,在传入数字,布尔值,数组,对象时,即使是静态的,也必须使用v-bind绑定,因为此时他是表达式不是字符串;当将一个对象所有的属性作为prop传入时,可以使用不带参数的,用一个对象包含所有属性,然后把对象名绑定在元素上即可。
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. </head>
  6. <body>
  7. <!--
  8. 父组件把信息传递给子组件:props属性传递
  9. - 默认传递给子组件的属性值都是字符串格式的,如果需要传递数据的格式是数据本身应该具备的格式,我们需要基于v-bind实现传递(哪怕传递的属性值还是固定)
  10. - 可以把子组件当做一个标签,我们可以设置ID/CLASS/STYLE等内置属性值,这些属性也会传递给子组件,VUE帮我们处理好的,该合并的合并,该覆盖的覆盖,无需我们在PROPS中注册处理
  11. -->
  12. <!-- 父组件 -->
  13. <div id="app">
  14. <!-- 子组件 -->
  15. <son :sonvalue3="Parentvalue3" :sonvalue="Parentvalue" :sonvalue2="Parentvalue2"></son>
  16. </div>
  17. <template id="son">
  18. <div>
  19. <h2>我是子组件</h2>
  20. 引用父组件中的数据项:{{sonvalue}}- {{sonvalue2}}- {{sonvalue3}}
  21. </div>
  22. </template>
  23. <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  24. <script type="text/javascript">
  25. //1.定义组件对象
  26. let Son = {
  27. template: "#son",
  28. props: {
  29. sonvalue: {
  30. type: Number
  31. },
  32. sonvalue2: {
  33. type: Number
  34. },
  35. sonvalue3: {
  36. type: String
  37. }
  38. }
  39. }
  40. let vm = new Vue({
  41. el: "#app",
  42. data:{
  43. Parentvalue:'12',
  44. Parentvalue2:'90',
  45. Parentvalue3:"'asss'"
  46. },
  47. components: { //2.注册组件对象
  48. Son
  49. }
  50. });
  51. </script>
  52. </body>
  53. </html>

单项数据流prop注意点

  1. prop是父子之间形成的单行向下传递数据,禁止逆向传递。
  2. 当父组件发生更新时,子组件所有的prop会变成新的值。因此不应该在子组件内部改变prop,会造成错误。

重点

  1. - 情景一:prop传递初始值时,子组件要把他作为一个本地的prop数据使用。
  1. // 解决办法:定义一个本地的data属性并将这个prop用作初始值。
  2. props: ['initialCounter'],
  3. data: function () {
  4. return {
  5. counter: this.initialCounter
  6. }
  7. }
  1. - 情景二:prop以一种原始的值传入并需要进行转换。
  1. //解决办法:使用这个prop的值定义一个计算属性
  2. props: ['size'],
  3. computed: {
  4. normalizedSize: function () {
  5. return this.size.trim().toLowerCase()
  6. }
  7. }
  8. //在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态。

2. $parent

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. </head>
  6. <body>
  7. <div id="app">
  8. <h1>{{name}}</h1>
  9. <father></father>
  10. </div>
  11. </body>
  12. <template id="father">
  13. <div>
  14. <div @click="facount++">父组件:{{facount}}</div>
  15. <son :q='facount'></son>
  16. </div>
  17. </template>
  18. <template id='son'>
  19. <div @click.stop='fn'>
  20. 子组件:{{$parent.facount}}
  21. <h2>接受父组件的数据:{{q}}</h2>
  22. </div>
  23. </template>
  24. <script src="https://cdn.jsdelivr.net/npm/vue">
  25. </script>
  26. <script type="text/javascript">
  27. // 父传子 就是在子组件使用的标签上 添加行内属性
  28. // 自组件中 通过props属性接收传进来的值;
  29. // 这个props对应的属性的属性值只能看 不能改;
  30. Vue.component('father',{
  31. template:'#father',
  32. data() {
  33. return {
  34. facount:100
  35. }
  36. },
  37. })
  38. Vue.component('son',{
  39. template:'#son',
  40. props:['q'],
  41. data() {
  42. return {
  43. }
  44. },
  45. methods: {
  46. fn(){
  47. //this.$parent 可以获取整个父组件,
  48. //那么整个父组件中的属性或者方法 我们可以随意调用
  49. //this.$parent.facount+=10;
  50. console.log(this.q)
  51. // 从父组件接手过来的数据 我们不能直接修改
  52. // 因为这么修改 有被重写的风险
  53. // 每当父组件更新一下, 传进来的数据就会被重写
  54. this.q= 1000;
  55. }
  56. },
  57. })
  58. let vm = new Vue({
  59. el:'#app',
  60. data:{
  61. name:"珠峰"
  62. },
  63. });

子组件向父组件传递

子传父: 通过让子组件告诉父组件要执行什么代码
1、$parent
2、自定义事件 + $emit : 所有再组件上边的事件都是自定义事件
3、$listeners 获取传给子组件的所有的自定义事件
4、provide/inject provide(){return {name:this.name}}

1. 利用emit

在子组件向父组件传递时借助了emit

事件名

在向父组件传递时,触发的事件名必须匹配监听事件所用的名称,事件名没有自动化的大小写转换,v-on事件监听器在dom模块中会被自动转换为全小写,会造成事件名不相同造成问题,因此建议使用短横线分割。

思路

在子组件里$emit绑定一个事件($emit(“事件名”,”参数”)),执行emit时,会把参数传递给父组件,父组件通过v-on监听并接收参数

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title></title>
  6. </head>
  7. <body>
  8. <div id="app">
  9. <h2>下面的数据项是从根组件中取到的</h2>
  10. <ol>
  11. <li v-for="item in todo">{{item}}</li>
  12. </ol>
  13. <hr />
  14. 这是一个子组件,我们希望把子组件中的数据传递给父组件
  15. <!-- 第三步:父组件接受子组件的方法 -->
  16. <!--<子组件 @子组件发回事件名="父组件要执行的方法"></子组件>-->
  17. <son @submitmsg="addmsg"></son>
  18. </div>
  19. <template id="son">
  20. <div>
  21. <input type="text" v-model="txt" />
  22. <!-- 第一步:子组件绑定事件 -->
  23. <button @click="add">添加</button>
  24. <p> 在子组件中的数据如下:</p>
  25. <p>{{txt}}</p>
  26. </div>
  27. </template>
  28. <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  29. <script type="text/javascript">
  30. //1.定义组件对象,子组件
  31. let Son = {
  32. template: "#son",
  33. data: function () {
  34. return {
  35. txt: ""
  36. }
  37. },
  38. methods: {
  39. add: function () {
  40. console.info(this.txt);
  41. //第二步:子组件向父组件发送一个方submitmsg
  42. //emit内容少的时候,可以直接放到@click后面,用值直接写就可以
  43. this.$emit("submitmsg", {
  44. msg: this.txt,
  45. t: new Date()
  46. })
  47. }
  48. }
  49. }
  50. let vm = new Vue({
  51. el: "#app",
  52. data: {
  53. todo: [
  54. "天气变冷了",
  55. "注意不要感冒了"
  56. ]
  57. },
  58. components: { //2.注册组件对象
  59. Son
  60. },
  61. methods: {
  62. // 第四步:接受子组件方法之后,执行父组件方法
  63. addmsg: function (info) {
  64. console.info("父组件收到了子组件发布的事件", info);
  65. this.todo.push(info.msg);
  66. }
  67. }
  68. });
  69. </script>
  70. </body>
  71. </html>

2. v-model

一个组件上的v-model默认会利用名为value的prop和名为input的事件。使用父组件v-model传值,子组件props[‘value’]接收而子组件也可以通过$emit(‘input’,false),去改变父组件中v-model 和 子组件中 value 的值 。
**
使用v-model来进行双向数据绑定的时:

  1. <input v-model="something">

仅仅是一个语法糖:

  1. <input v-bind:value="something" v-on:input="something = $event.target.value">

所以在组件中使用的时候,相当于下面的简写:

  1. <custom v-bind:value="something" v-on:input="something = $event.target.value"></custom>

所以要组件的v-model生效,它必须:

  • 将value绑定到名为value的prop上
  • 在其input事件被触发时,将新的值通过自定义的input事件触发

    父组件

  1. <template>
  2. <div class="toggleClassWrap">
  3. <!-- 自定义v-model="isShow"应用 此处将isShow 传递给子组件中的props -->
  4. <modelVue v-if="ifShow" v-model="ifShow"></modelVue>
  5. </div>
  6. </template>
  7. <script type="text/javascript">
  8. import modelVue from '../../components/model.vue'
  9. export default{
  10. data () {
  11. return {
  12. ifShow:true,
  13. }
  14. },
  15. components : {
  16. modelVue
  17. }
  18. }
  19. </script>

子组件

  1. <template>
  2. <div id="showAlert">
  3. <div>showAlert 内容</div>
  4. <button class="close" @click="close">关闭</button>
  5. </div>
  6. </template>
  7. <script>
  8. export default{
  9. //1.将value绑定到名为value的prop上
  10. props:{
  11. value:{
  12. type:Boolean,
  13. default:false,
  14. }
  15. },
  16. data(){
  17. return{}
  18. },
  19. methods:{
  20. close(){
  21. //2.将value绑定到名为value的prop上
  22. this.$emit('input',false);//传值给父组件, 让父组件监听到这个变化
  23. }
  24. },
  25. }
  26. </script>
  27. <style scoped>
  28. .close{
  29. background:red;
  30. color:white;
  31. }
  32. </style>

3. .sync

可以通过prop进行双向绑定,同时配合this.$emit(update:myPropName,newValue)触发事件。.sync相当一个语法糖,会被扩展为自动更新父组件属性的v-on监听器,(即让自己手动更新父组件的值,进而使数据来源更改更明显)

  1. //作为语法糖的原本写法
  2. <text-document
  3. v-bind:title="doc.title"
  4. v-on:update:title="doc.title = $event">
  5. </text-document>
  6. //利用.sync语法糖简写的形式
  7. <text-document v-bind:title.sync="doc.title"></text-document>

父组件

  1. <template>
  2. <div class="vuexWrap common">
  3. <!--使用sync修饰符可以简化子组件向父组件传递数据的过程;-->
  4. <!--1. 在父组件使用子组件时,prop后面跟一个.sync ,然后取消显式声明的事件监听-->
  5. <!--2. 子组件触发事件:this.$emit('update:prop名字', 新数据)-->
  6. <childrenOne :title.sync="doc.title"></childrenOne>
  7. </div>
  8. </div>
  9. </template>
  10. <script type="text/javascript">
  11. import childrenOne from '../../components/childrenOne.vue'
  12. export default{
  13. data () {
  14. return {
  15. doc:{
  16. title:'index'
  17. },
  18. }
  19. },
  20. mounted (){
  21. //childrenOne
  22. alert(this.doc.title);
  23. },
  24. components : {
  25. childrenOne
  26. }
  27. }
  28. </script>

子组件

  1. <template>
  2. <div class="OneWrap common">
  3. {{title}}
  4. </div>
  5. </template>
  6. <script type="text/javascript">
  7. export default{
  8. props:{
  9. title:""
  10. },
  11. data () {
  12. return {
  13. newTitle:"childrenOne"
  14. }
  15. },
  16. mounted (){
  17. this.$emit('update:title', this.newTitle);
  18. },
  19. }
  20. </script>

4. ref

  • ref加在原生的DOM元素上,通过ref获取的是原生的DOM对象(基于ref把当前元素放置到this.$refs对象,实现对dom直接操作);如果加在组件上,获取的是这个组件实例的一个引用;拿到这个实例后可以访问上面的数据、调用组件的方法
  • 只有在mounted及之后才能获取到
  • $parent和$children是获取组件和子组件的实例,只不过$children是一个数组集合,需要记住组件顺序才可以
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <div id="app" :style="{color: xColor}">
  9. <p ref="p1">{{msg}}</p>
  10. <ul>
  11. <!-- <li v-for="(item, index) in ary"
  12. v-if="index % 2 != 0"
  13. ref="listItem"
  14. :key="index">{{item}}</li>-->
  15. <li v-for="(item, index) in oddIndex"
  16. ref="listItem"
  17. :key="index">{{item}}</li>
  18. </ul>
  19. </div>
  20. <script src="vue.js"></script>
  21. <script>
  22. // Vue是数据驱动的,不提倡操作DOM;但是必要的时候还是需要操作DOM的;Vue提供了专门的方式获取DOM;
  23. // ref属性 和 vm.$refs
  24. // 如果这个列表不需要全部渲染,可以写一个计算属性,v-for 这个计算属性
  25. // 或者,v-if 条件渲染
  26. let vm = new Vue({
  27. el: '#app',
  28. data: {
  29. msg: 'hello',
  30. ary: [1, 2, 3, 4],
  31. xColor: ''
  32. },
  33. computed: {
  34. oddIndex() {
  35. return this.ary.filter((item, index) => index % 2 !== 0);
  36. }
  37. },
  38. mounted() {
  39. // console.log(this.$refs);
  40. console.log(this.$refs.p1);
  41. console.log(this.$refs.listItem);
  42. // 我们通过this.$refs获取DOM元素;
  43. this.$refs.p1.style.color = 'red'; // 可以实现,但是不推荐操作DOM;
  44. // 首先要在获取的元素添加 ref="标识符" 的行内属性
  45. // 获取的时候this.$refs.标识符 获取元素;
  46. // 如果相同的ref有一个,获取到的就是带这个ref的原生元素对象
  47. // 如果相同的ref有多个,获取到的是所有带有这个ref的元素组成的数组
  48. //基于REF可以把当前元素放置到this.$refs对象中,从而实现对DOM的直接操作(只有在mounted及之后才可以获取到)
  49. }
  50. })
  51. </html>

获取子组件的实例

  • this.$children[0].flag ->需要知道是数组的哪一个
  • 给子组件加ref,this.$refs.实例,

  • ref用于获取组件

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <div id="app">
  11. <h1>{{name}}</h1>
  12. <ul>
  13. <li ref='www'></li>
  14. <li ref='www'></li>
  15. <li ref='www'></li>
  16. </ul>
  17. <ul>
  18. <li v-for='item in ary' ref='qqq'></li>
  19. </ul>
  20. <my-btn v-for='item in ary' :key='item' ref='qqq'></my-btn>
  21. </div>
  22. </body>
  23. </html>
  24. <template id='btn'>
  25. <button @click='clickFn' class='aaa' >按钮</button>
  26. </template>
  27. <script src="../node_modules/vue/dist/vue.js"></script>
  28. <script>
  29. // ref除了获取元素 还可以获取 组件;
  30. // 获取到组件之后 我们就可以根据自己的需求进行编写
  31. // 父组件怎么调用到 子组件的 methods中的函数
  32. // 子组件怎么调用到 父组件的 methods中的函数
  33. let obj = {
  34. template:'#btn',
  35. methods: {
  36. clickFn(e){
  37. this.$emit('click',e);
  38. console.log(this)
  39. }
  40. },
  41. }
  42. let vm = new Vue({
  43. el:'#app',
  44. data:{
  45. name:"珠峰",
  46. ary:[1,2,3,4]
  47. },
  48. mounted() {
  49. // ref获取元素 在多个元素的时候 只能获取一个
  50. // 若是通过 v-for循环出来的 就都可以获取到
  51. // DOM的更新是一个异步操作
  52. console.log(this.$refs.qqq)// v-for出来的可以获取一组
  53. console.log(this.$refs.www)// 静态写死的只获取一个
  54. this.ary.pop();
  55. this.$nextTick(()=>{
  56. // DOM更新完成之后才会触发; DOM的更新是异步的
  57. console.log(this.$refs.qqq)
  58. })
  59. },
  60. components:{
  61. 'my-btn':obj
  62. },
  63. });
  64. </script>

5. $parent和$child

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. </head>
  6. <body>
  7. <div id="app">
  8. <h1>{{name}}</h1>
  9. <father></father>
  10. </div>
  11. </body>
  12. <template id="father">
  13. <div>
  14. <!-- 只要组件上的事件 不管长成什么样 都是自定义事件 -->
  15. <div @click="facount++">父组件:{{facount}}</div>
  16. <son :q='facount'></son>
  17. </div>
  18. </template>
  19. <template id='son'>
  20. <div @click.stop='fn'>
  21. 子组件:{{$parent.facount}}
  22. <h2>接受父组件的数据:{{q}}</h2>
  23. </div>
  24. </template>
  25. <script src="https://cdn.jsdelivr.net/npm/vue">
  26. </script>
  27. <script type="text/javascript">
  28. // 父传子 就是在子组件使用的标签上 添加行内属性
  29. // 自组件中 通过props属性接收传进来的值;
  30. // 这个props对应的属性的属性值只能看 不能改;
  31. Vue.component('father',{
  32. template:'#father',
  33. data() {
  34. return {
  35. facount:100
  36. }
  37. },
  38. })
  39. Vue.component('son',{
  40. template:'#son',
  41. props:['q'],
  42. data() {
  43. return {
  44. }
  45. },
  46. methods: {
  47. fn(){
  48. //this.$parent 可以获取整个父组件,
  49. //那么整个父组件中的属性或者方法 我们可以随意调用
  50. //this.$parent.facount+=10;
  51. console.log(this.q)
  52. // 从父组件接手过来的数据 我们不能直接修改
  53. // 因为这么修改 有被重写的风险
  54. // 每当父组件更新一下, 传进来的数据就会被重写
  55. this.q= 1000;
  56. }
  57. },
  58. })
  59. let vm = new Vue({
  60. el:'#app',
  61. data:{
  62. name:"珠峰"
  63. },
  64. });

6. $attr

可以获取没有被props接收的那些参数

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. <link rel="stylesheet" href="../node_modules/element-ui/lib/theme-chalk/index.css">
  9. </head>
  10. <body>
  11. <div id="app">
  12. <!-- 只要组件上的事件 不管长成什么样 都是自定义事件 -->
  13. <h1>{{name}}</h1>
  14. <mycount :count='count' @add123='fn' @minus123='fn'></mycount>
  15. <el-button type="primary" icon="el-icon-edit" @click='fn2' class='qqq'></el-button>
  16. <my-button @click='fn2' class='qwer'></my-button>
  17. </div>
  18. </body>
  19. </html>
  20. <template id='mycount'>
  21. <div>
  22. <h2>数字是{{count}}</h2>
  23. <button @click='add'>增加</button>
  24. <button @click='minus'>减少</button>
  25. </div>
  26. </template>
  27. <script src="../node_modules/vue/dist/vue.js"></script>
  28. <script src="../node_modules/element-ui/lib/index.js"></script>
  29. <script>
  30. // 子传父 让父组件使用子组件的数据;也就是子组件可以修改父组件的数据
  31. /*
  32. 1、$parent
  33. 2、自定义事件 + $emit(官推)
  34. 3、$listeners 可以接收所有自定义事件 this.$listeners.事件名(参数)
  35. 4、provide/inject
  36. // 2 3 4这三种方法 都是一个套路: 把父组件的函数 传给子组件,
  37. 然后再子组件中执行对应的函数,并通过参数的方式 把子组件的数据给父组件
  38. */
  39. let mycount = {
  40. template:'#mycount',
  41. props:['count'],// props 优先于 data
  42. created() {
  43. console.log(this)
  44. },
  45. methods: {
  46. add() {
  47. // this.$parent.count++
  48. // this.$emit('add123',1,2,3,4,5,6,7)
  49. this.$listeners.add123(1,2,3)
  50. },
  51. minus(){
  52. // this.$parent.count--
  53. // this.$emit('minus123',100,200,300,400)
  54. this.qqq(100,200)
  55. }
  56. },
  57. inject:['qqq']
  58. }
  59. let vm = new Vue({
  60. el:'#app',
  61. data:{
  62. name:"珠峰",
  63. count:0
  64. },
  65. components:{
  66. mycount
  67. },
  68. methods: {
  69. fn(n){
  70. console.log(arguments)
  71. this.count += n
  72. },
  73. fn2(){
  74. console.log(arguments)
  75. }
  76. },
  77. provide(){
  78. return {
  79. qqq:this.fn
  80. }
  81. }
  82. });
  83. </script>

隔代通信

  1. provide和inject
  1. {
  2. provide:{
  3. //对象或者返回对象的函数都可以(属性如果是data中的数据,则必须使用函数的方法进行处理)
  4. name:"aaa";
  5. }
  6. }
  7. //后代组件基于inject声明需要使用的数据并调取使用
  8. {
  9. inject:['name'],
  10. methods:{
  11. function(){
  12. let name=this.name;
  13. }
  14. }
  15. }

prop用法参考文章
v-model实例理解
prop,$emit用法推荐