您的位置:首页 > Web前端 > Vue.js

Vue.js 2.x笔记:组件(5)

2018-06-12 09:31 501 查看

1. 组件简介

  组件(Component)是 Vue.js 最强大的功能之一,组件可以扩展 HTML 元素,封装可重用的代码。

  组件:为了拆分Vue实例的代码量,以不同的组件来划分不同的功能模块,需要什么样的功能,可以去调用对应的组件。

  模块化和组件化的区别:

  ◊ 模块化:是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一。

  ◊ 组件化:是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用。  

2. 注册组件

2.1 全局组件

  注册全局组件语法格式:

Vue.component(tagName, options)

  其中,tagName 为组件名,options 为配置选项。

  注册组件后调用方式:

<tagName></tagName>

  所有实例都能用全局组件。

  组件名定义方式:PascalCase和kebab-case。在组件命名时可以采用PascalCase或kebab-case,但在DOM中只能使用kebab-case。

  PascalCase示例:

<div id="app">
<my-component></my-component>
</div>
<script>
Vue.component('MyComponent', {
template: '<div>标题</div>'
});

var vm = new Vue({
el: "#app"
});
</script>

  kebab-case示例:

<div id="app">
<my-component></my-component>
</div>
<script>
Vue.component('my-component', {
template: '<div>标题</div>'
});

var vm = new Vue({
el: "#app"
});
</script>
<div id="app">
<home></home>
</div>
<script>
Vue.component("home", {
template: "<div>{{text}}</div>",
data: function () {
return {
text: "主页"
};
}
});

new Vue({
el: "#app"
});
</script>
<div id="app">
<home></home>
</div>
<script>
var homeTpl = Vue.extend({ 
template: "<div>{{text}}</div>",
data: function () {
return {
text: "主页"
};
}
});

Vue.component('home', homeTpl);

new Vue({
el: "#app"
});
</script>

  使用template标签:

<div id="app">
<home></home>
</div>
<template id="tpl">
<div>{{text}}</div>
</template>
<script>
Vue.component("home", {
template: "#tpl",
data: function () {
return {
text: "主页"
};
}
});

new Vue({
el: "#app"
});
</script>

2.2 局部组件

  局部组件只能在当前Vue示例中使用。

<div id="app">
<home></home>
</div>
<script>
new Vue({
el: "#app",
components: {
"home": {
template: "<div>{{text}}</div>",
data: function () {
return {
text: "主页"
};
}
}
}
});
</script>

2.3 Vue.extend

2.3.1 基本使用

<div id="app">
<home></home>
</div>
<script>
var home = Vue.extend({
template: "<div>标题</div>"
});

Vue.component("home", home);

new Vue({
el: "#app"
});
</script>

2.3.2 参数data

  data:在 Vue.extend() 中必须是函数。

<body>
<task></task>

<script>
var task = Vue.extend({
template:"<div>{{ taskName }}</div>",
data:function(){
return {
taskName:"任务名称"
}
}
});

new task().$mount("task");
</script>
</body>

2.3.3 使用$mount

  mount:挂载,将vue实例挂靠在某个dom元素上的一个过程。

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>libing.vue</title>
<script src="node_modules/vue/dist/vue.min.js"></script>
</head>

<body>
<div id="app"></div>
<script>
var home = Vue.extend({
template: "<div>标题</div>"
});

new home().$mount("#app");
</script>
</body>

</html>

3. 组件通信

3.1 props:父组件向子组件传递数据

  prop 是组件用来传递数据的自定义特性,在组件上注册自定义属性。

  prop特性注册成为组件实例的属性。

   

props
:父组件向子组件传递数据。

  一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。

3.1.1 静态props

  示例:

<div id="app">
<home text="主页"></home>
</div>
<script>
var homeTpl = Vue.extend({
props:["text"],
template: "<div>{{text}}</div>"
});

Vue.component('home', homeTpl);

new Vue({
el: "#app"
});
</script>

3.1.2 动态props

  使用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件。

<div id="app">
<home v-bind:text="text"></home>
</div>
<script>
var homeTpl = Vue.extend({
props: ["text"],
template: "<div>{{text}}</div>"
});

Vue.component('home', homeTpl);

new Vue({
el: "#app",
data: {
text: "主页"
}
});
</script>

  由于HTML Attribute不区分大小写,当使用DOM模板时,camelCase的props名称要转为kebab-case。

<div id="app">
<home warning-text="提示信息"></home>
</div>
<script>
Vue.component('home', {
props: ['warningText'],
template: '<div>{{ warningText }}</div>'
});

var vm = new Vue({
el: "#app"
});
</script>

  传递的数据可以是来自父级的动态数据,使用指令v-bind来动态绑定props的值,当父组件的数据变化时,也会传递给子组件。

<div id="app">
<home v-bind:warning-text="warningText"></home>
</div>
<script>
Vue.component('home', {
props: ['warningText'],
template: '<div>{{ warningText }}</div>'
});

var vm = new Vue({
el: "#app",
data: {
warningText: '提示信息'
}
});
</script>

注:prop 是单向传递,当父组件的属性变化时,将传递给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态。

3.1.3 props验证

  为组件的 prop 指定验证要求,如果有一个需求没有被满足,则 Vue 会在控制台中警告。

Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 匹配任何类型)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组且一定会从一个工厂函数返回默认值
default: function () {
return {
message: 'hello'
}
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
});

  类型检查:type可以是下列原生构造函数中的一个:String、Number、Boolean、Array、Object、Date、Function、Symbol,也可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认。

  示例:

<div id="app">
<parent-component></parent-component>
</div>

<template id="child-component1">
<h2>{{ message }}</h2>
</template>
<template id="child-component2">
<h2>{{ message }}</h2>
</template>
<template id="parent-component">
<div>
<child-component1></child-component1>
<child-component2></child-component2>
</div>
</template>

<script>
Vue.component('parent-component', {
template: '#parent-component',
components: {
'child-component1': {
template: '#child-component1',
data() {
return {
message: '子组件1'
};
}
},
'child-component2': {
template: '#child-component2',
data() {
return {
message: '子组件2'
};
}
}
}
});

var vm = new Vue({
el: "#app"
});
</script>

  示例:

<div id="app">
<todo :todo-data="taskList"></todo>
</div>

<template id="tpl-todo-item">
<li>{{ id }} - {{ text }}</li>
</template>

<template id="tpl-todo-list">
<ul>
<todo-item v-for="item in todoData" :id="item.id" :text="item.text"></todo-item>
</ul>
</template>

<script>
// 构建一个子组件
var todoItem = Vue.extend({
template: "#tpl-todo-item",
props: {
id: {
type: Number,
required: true
},
text: {
type: String,
default: ''
}
}
})

// 构建一个父组件
var todoList = Vue.extend({
template: "#tpl-todo-list",
props: {
todoData: {
type: Array,
default: []
}
},
// 局部注册子组件
components: {
todoItem: todoItem
}
})

// 注册到全局
Vue.component('todo', todoList)

new Vue({
el: "#app",
data: {
taskList: [{
id: 1,
text: 'New'
},
{
id: 2,
text: 'InProcedure'
},
{
id: 3,
text: 'Done'
}
]
}
});
</script>

3.2 自定义事件:子组件向父组件传递数据

  每一个Vue实例都实现事件接口:

  

$on(eventName)
:监听事件

  

$emit(eventName)
:触发事件

  子组件需要向父组件传递数据时,子组件用

$emit(eventName)
来触发事件,父组件用
$on(eventName)
来监听子组件的事件。

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

<template id="tpl-search-form">
<div class="input-group form-group" style="width: 500px;">
<input type="text" class="form-control" placeholder="请输入查询关键字" v-model="keyword" />
<span class="input-group-btn">
<input type="button" class="btn btn-primary" value="查询" @click="search">
</span>
</div>
</template>
<template id="tpl-search-bar">
<searchform @onsearch="search"></searchform>
</template>

<script>
// 构建一个子组件
var searchform = Vue.extend({
template: "#tpl-search-form",
data: function () {
return {
keyword: 'libing'
};
},
methods: {
search: function () {
this.$emit('onsearch', this.keyword);
}
}
});

// 构建一个父组件
var searchbar = Vue.extend({
template: "#tpl-search-bar",
components: {
searchform: searchform
},
methods: {
search(keyword) {
console.log(keyword);
}
}
})

// 注册到全局
Vue.component('searchbar', searchbar);

new Vue({
el: "#app"
});
</script>

  购物车示例:

<div id="app">
<shoppingcart :shopppingcarts="products" @calc="getTotal"></shoppingcart>
<div>总计:{{ totalPrice }}</div>
</div>
<template id="shoppingcart">
<table>
<tr>
<th>商品ID</th>
<th>商品名称</th>
<th>单价</th>
<th>数量</th>
</tr>
<tr v-for="item in shopppingcarts">
<td>{{ item.ID }}</td>
<td>{{ item.ProductName }}</td>
<td>{{ item.UnitPrice }}</td>
<td><input type="text" v-model="item.Quantity" @change="calcTotal" /></td>
</tr>
</table>
</template>
<script>
var shoppingcart = Vue.extend({
template: "#shoppingcart",
props: ["shopppingcarts"],
methods: {
calcTotal: function () {
this.$emit("calc");
}
}
});

new Vue({
el: "#app",
components: {
shoppingcart: shoppingcart
},
data: {
totalPrice: 100,
products: [{
ID: 1,
ProductName: "手机",
UnitPrice: 1000,
Quantity: 2
}, {
ID: 2,
ProductName: "电脑",
UnitPrice: 5000,
Quantity: 5
}]
},
methods: {
getTotal() {
console.log(new Date());
this.totalPrice = 0;
this.products.forEach(product => {
this.totalPrice += product.UnitPrice * product.Quantity;
});
}
},
mounted() {
//当vue执行完毕之后,去执行函数
this.getTotal();
}
});
</script>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: