# 组件定义

# 自定义组件

新建在/components/组件名.vue文件

组件文档结构

<template>
  <view>
    ......
  </view>
</template>
<script>
  export default {
    name: "组件名称",
    //属性自定义
    props: {
      属性名称: {
        type: String, //属性类型
        value: "值"
      },
      ......
    },
    //组件生命周期
    created: function(e) {

    },
    methods: {
      函数名称: function(obj) {

      },
    }
  }
</script>
<style>
  组件样式
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

使用组件

1、引用组件
import 组件名称 from "../../components/组件名.vue";
2、注册组件
export default{
  components:{
    组件名称
  },
}
3、在试图模板中使用组件
<组件名称 组件属性="对应的值"></组件名称>
1
2
3
4
5
6
7
8
9
10

# 全局注册

vue一样的方式去配置全局组件,需在main.js里进行全局注册,注册后就可在所有页面里使用该组件。

1、main.js里进行全局导入和注册

import Vue from 'vue'
import pageHead from './components/page-head.vue'
Vue.component('page-head',pageHead)
1
2
3

2、index.vue里可直接使用组件

<template>
  <view>
    <page-head></page-head>
  </view>
</template>
1
2
3
4
5

# 局部注册

1、传统vue规范:在index.vue页面中,通过import方式引入组件 ,在components选项中定义你想要使用的组件。

<!-- 在index.vue引入 uni-badge 组件-->
<template>
  <view>
	<uni-badge text="1"></uni-badge>
  </view>
</template>
<script>
  import uniBadge from '@/components/uni-badge/uni-badge.vue';
  export default {
	components: {
	  uniBadge
	}
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

对于components对象中的每个property来说,其property名就是自定义元素的名字,其property值就是这个组件的选项对象。

在对象中放一个类似uniBadge的变量名其实是缩写,即这个变量名同时是:

  • 用在模板中的自定义元素的名称
  • 包含了这个组件选项的变量名(仅支持驼峰法命名)

2、通过uni-appeasycom将组件引入精简为一步。只要组件安装在项目的components目录下,并符合components/组件名称/组件名称.vue目录结构。就可以不用引用、注册,直接在页面中使用。

<template>
  <view>
	<uni-badge text="1"></uni-badge>
  </view>
</template>
<script>
  // 这里不用import引入,也不需要在components内注册uni-badge组件。template里就可以直接用
  export default {
	data() {
	  return {}
	}
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
  • easycom是自动开启的,不需要手动开启,有需求时可以在pages.jsoneasycom节点进行个性化设置
  • 不管components目录下安装了多少组件,easycom打包后会自动剔除没有使用的组件,对组件库的使用尤为友好。

# props

props可以是数组或对象,用于接收来自父组件的数据。props可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。

选项 类型 说明
type String、Number、Boolean、Array、Object、Date、Function、Symbol,任何自定义构造函数、或上述内容组成的数组 会检查一个 prop 是否是给定的类型,否则抛出警告
default any 为该 prop 指定一个默认值。如果该 prop 没有被传入,则换做用这个值。对象或数组的默认值必须从一个工厂函数返回
required Boolean 定义该 prop 是否是必填项
validator Function 自定义验证函数会将该 prop 的值作为唯一的参数代入。在非生产环境下,如果该函数返回一个 false 的值 (也就是验证失败),一个控制台警告将会被抛出

示例:子组件定义

<template>
  <view>
	<view>{{age}}</view>
  </view>
</template>
<script>
  export default {
	props: {
	  // 检测类型 + 其他验证
	  age: {
		type: Number,
		default: 0,
		required: true,
		validator: function(value) {
		  return value >= 0
		}
	  }
	}
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

示例:父组件传递age属性

<template>
<view>
  <componentA :age="10"></componentA>
</view>
</template>
1
2
3
4
5

# 组件之间的数据传输

组件之间的数据传输,以及事件传递是比较常见的一个应用

# 事件注册/触发方式

客户端调用组件的时候,注册事件。组件触发注册的事件,达到向父组件传值的目的

子组件free-test.vue

<template>
  <!-- <button type="default" @tap="$emit('openExtend')">{{title}}</button> -->
  <button type="default" @tap="seeme">{{title}}</button>
</template>

<script>
  export default {
    name: "freeTs",
    props: {
      title: String,
      default: ''
    },
    methods: {
      seeme() {
        this.$emit('openExtend', { name: 'wk', 'sex': 'male' })
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

父组件调用时注册事件

<template>
  <view>
    <free-test :title="title" @openExtend="openExtend"></free-test>
  </view>
</template>
<script>
  import freeTest from '../../components/free-test.vue'
  export default {
    components: {
      freeTest
    },
    data() {
      return {
        title: 'haha'
      }
    },
    methods: {
      openExtend(obj) {
        console.log(obj)
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 客户端调用组建引用方式

客户端为调用的组件设置引用别名,就可以调用其方法进行传值

子组件free-test.vue

<template>
  <button type="default">{{title}}</button>
</template>

<script>
  export default {
    name: "freeTs",
    props: {
      title: String,
      default: ''
    },
    methods: {
      seeme(obj) {
        console.log(obj)
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

父组件为组建设置引用别名,就可以调用其方法进行传值

<template>
  <view>
    <free-test :title="title" ref="free"></free-test>
    <button type="default" @tap="seeData">test</button>
  </view>
</template>
<script>
  import freeTest from '../../components/free-test.vue'
  export default {
    components: {
      freeTest
    },
    data() {
      return {
        title: 'haha'
      }
    },
    methods: {
      seeData() {
        this.$refs.free.seeme({ title: '6666', created_at: '2020-09-19' });
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# ref

被用来给元素或子组件注册引用信息,引用信息将会注册在父组件的$refs对象上。

如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例:

<!-- 非H5端不支持通过this.$refs.content来获取view实例 -->
<view ref="content">hello</view>

<!-- 支持通过this.$refs.child来获取child-component实例 -->
<child-component ref="child"></child-component>
1
2
3
4
5

尽管存在prop和事件,有的时候你仍可能需要在JavaScript里直接访问一个子组件。访问子组件实例或子元素,通过ref为子组件赋予一个ID引用,在vue的js中可通过this.$refs.XXX来获取到组件对象。

<base-input ref="usernameInput"></base-input>
1

你已经定义了这个ref的组件里,你可以使用this.$refs.usernameInput来访问这个<base-input>实例

<!-- base-input子组件页面 -->
<template>
  <view>
    <input :focus="isFocus" type="text" placeholder="请输入内容" />
  </view>
</template>
<script>
  export default {
    name: "base-input",
    data() {
      return {
        "isFocus": false
      };
    },
    methods: {
      focus() {
        this.isFocus = true
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

允许父级组件通过下面的代码聚焦<base-input>里的输入框

<!-- index 父组件页面 -->
<template>
  <view>
    <base-input ref="usernameInput"></base-input>
    <button type="default" @click="getFocus">获取焦点</button>
  </view>
</template>
<script>
  export default {
    methods: {
      getFocus() {
        // 通过组件定义的ref调用focus方法
        this.$refs.usernameInput.focus()
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

注意

非H5端只能用于获取自定义组件,不能用于获取内置组件实例(如:view、text)

# 自定义事件

你可能有很多次想要在一个组件的根元素上直接监听一个原生事件。 这时,你可以使用 @ 事件的.native修饰符

  • 注意:在app、小程序端和h5端表现不一致,h5端获取到的是浏览器原生事件。
<template>
  <view>
    <!-- 我是父组件 -->
    <componentA @click.native="clickComponentA" style="height: 200px;"></componentA>
  </view>
</template>
<script>
  export default {
    methods: {
      clickComponentA() {
        console.log("clickComponentA");
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
  <view>
	<!-- 我是子组件 -->
	<view type="default" @click.stop="open" style="height: 30px;">点击</view>
  </view>
</template>
<script>
  export default {
	methods: {
	  open() {
		console.log("open");
	  }
	}
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# .sync 修饰符

当一个子组件改变了一个prop的值时,这个变化也会同步到父组件中所绑定。.sync它会被扩展为一个自动更新父组件属性的v-on监听器。

<!-- 父组件 -->
<template>
  <view>
    <syncA :title.sync="title"></syncA>
  </view>
</template>
<script>
  export default {
    data() {
      return {
        title: "hello vue.js"
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- 子组件 -->
<template>
  <view>
    <view @click="changeTitle">{{title}}</view>
  </view>
</template>
<script>
  export default {
    props: {
      title: {
        default: "hello"
      },
    },
    methods: {
      changeTitle() {
        // 触发一个更新事件
        this.$emit('update:title', "ruoyi-app")
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 命名限制

uni-app中以下这些作为保留关键字,不可作为组件名。

a、canvas、cell、content、countdown、datepicker、div、element、embed、header、image、img、indicator、input、link、list、loading-indicator、loading、marquee、meta、refresh、richtext、script、scrollable、scroller、select、slider-neighbor、slider、slot、span、spinner、style、svg、switch、tabbar、tabheader、template、text、textarea、timepicker、transition-group、transition、video、view、web

注意

  • 除以上列表中的名称外,标准的 HTML 及 SVG 标签名也不能作为组件名。
  • 在百度小程序中使用时,不要在 data 内使用 hidden ,可能会导致渲染错误。
  • methods中不可使用与生命周期同名的方法名。