几乎任意类型的应用界面都可以抽象为一个组件树:
复习:DOM树
但关键的关键,是有了组件,我们就可以重用(reuse)在各个页面反复出现的部分。
@悟@:如果没有组件(以及后面的route、脚手架等),vue就只能算是个类库,不能算是框架。
官方文档定义:组件
本质上是一个拥有预定义选项的一个 Vue 实例
可以通过Vue.component()创建:
Vue.component('todo-item', {//指定组件名称 template: '<li>这是个待办项</li>'//指定template,模板 })
component()接收两个参数:
然后,我们就可以使用todo-item实例了:(注意它放置的位置,演示移到#yz-hello以外)
<form id="yz-hello"> <input type="file" name="icon" id="" v-on:change="upload" ref="icon"> <todo-item></todo-item> </form>注意:Vue.component()一定要放在new Vue() 前面?,否则就会报错:
@想一想@:为什么呢?
通过Vue.component()生成的组件,注册(使用)之后,可以会被所有的模板使用:这种组件被称为全局组件。
演示:
<div id="fg-welcome"> <yz-table></yz-table> </div>
const welcome = new Vue({ el: "#fg-welcome" //模板,渲染 })更多的时候我们会使用局部组件(因为冲突和性能):
const password = { template: '<a>忘记密码</a>' }
components: { "forget-password": password },演示:不设置components
在组件的template中还可以再嵌入组件:这样才能形成组件树。
@想一想@:new Vue()生成的根实例是不是也是一个组件?
template中使用:
const password = { //直接在template中使用全局组件 template: `<a><todo-item></todo-item>忘记密码</a>' }
const icon = { template: '<span>图标</span>' } const password = { template: '<a><yz-icon></yz-icon>忘记密码</a>', components: { //使用局部组件一样要显式注册 "yz-icon": icon } }
必须要有一个且仅有一个根元素,不能几个HTML元素并列,比如像这样:
template: `<h3>{{ title }}</h3> <div v-html="content"></div>`要把它们套到同一个HTML元素中,比如:(复习:v-html vs {{}})
<div class="blog-post"> <h3>{{ title }}</h3> <div v-html="content"></div> </div>
因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。但是:
el 是根实例特有的选项。
本质上是用一个页面已存在的DOM元素作为Vue实例的template。
使用函数(的返回值),而不是直接赋值。
Vue.component('todo-item', { template: '<li>这是个待办项:{{pwd}}</li>', // data: function () { 两种写法都OK data() { return { pwd: '忘记密码' } } })
否则,新版会直接报警告,老版会让该data被多个实例共享,造成很多不必要的问题……
再看Vue实例生命周期:有无template/el……
我们可能:希望组件在不同的地方使用时,有不同的呈现内容。
可以像根实例一样,在组件的模板中绑定文本和属性,但是需要使用props(而不是data)
props: ["todo", "url"], //注意这是数组
template: '<a :href="url">{{todo}}</a>',
<todo-item todo="忘记密码" url="https://17bang.ren"></todo-item>
注意对比:
|
用于 |
数据来源 |
存储 |
组织形式 |
props |
组件 |
HTML |
键名 |
数组 |
data |
根实例 |
JavaScript代码 |
键值对 |
对象 |
data() |
组件 |
JavaScript代码 |
键值对 |
函数(返回值) |
el: "#yz-hello", data:{ dUrl: "https://17bang.ren/Code" },这就需要我们使用之前的v-bind:
<forget-password :url="dUrl"></forget-password>
注意层层对应关系……
vue会把父组件template中声明的属性当做一个普通属性,传递给子组件template的根节点:
<todo-item style="color: red;"></todo-item>
todo-item的template是:
Vue.component('todo-item', { template: '<a>忘记密码 <span>(~ ̄(OO) ̄)ブ</span> </a>',生成的HTML:
<a style="color: red;"> <span>(~ ̄(OO) ̄)ブ</span></a>这个特性尝尝被用于父组件控制子组件的样式,还可以添加class、title啥的……,且子组件template中根元素上已经存在的style/class之类的值不会被覆盖。
但是,子组件不能像上文有props声明一样使用父组件中的prop值。(演示:去掉props中的url后报错)
多快好省!前端后端,线上线下,名师精讲
更多了解 加: