基本示例(官网找去)
因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
组件的复用
就跟用标签一样,可以随便用但是
如果你想要复用组件,就要注意一个事情。如果你在组件中使用了data,一定要把它写成函数,而不是单纯的一个变量。所以,如下规定就出来了
data 必须是一个函数
当我们定义这个 组件时,你可能会发现它的 data 并不是像这样直接提供一个对象:
data: {
count: 0
}
取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
data: function () {
return {
count: 0
}
}
如果 Vue 没有这条规则,那么当你改变其中一个组件的值(比如用click方法改变),那么所有组件的值都会被改变。
组件的组织
嵌套树的形式
为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。
现在已知的全局注册是在一个页面中,以这样的形式注册:
Vue.component('my-component-name', {
// ... options ...
})
局部注册是指在一个页面中,把一个组件作为一个变量的样子,如:
// 局部组件
var componentA = {
name:'componentA',
data: function () {
return {
count: 0,
}
},
template: '<button @click="handleClick" style="color: #fab;"> {{sonText}} {{ count }} 次.</button>',
}
我现在想知道的就是,在vue项目中使用组件是用import导入的,这种情况算是局部还是全局,感觉是全局,因为只能在引用的页面使用。
通过 Prop 向子组件传递数据
我们想要一个组件能够通用,就需要他能够只有一个架子然后所有的数据都是我们后来传过去的,这正是 prop 的由来。
Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。如:
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data 中的值一样。
你当然也可以传数组、传对象。
所以你就会发现一个问题,我们在组件中,怎么判断传回来的是什么值?毕竟我们需要看看她传回来的值,如果是数组,还要遍历,如果是对象,还要提取里面我们所需要的数据。
留个小疑问,以后解决
我猜是设置props的时候给绑定一个类型属性,只能传回来对应类型的数据。
ps:我想尝试一下传入一个对象,然后使用,失败了。
成功了,原来我是这样写的:
<body>
<div id="app">
<button-counter itle="sds"></button-counter>
</div>
<script>
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
props:['itle'],
template: '<button>{{itle}}</button>'
})
</script>
<script>
new Vue({
el:'#app',
})
</script>
能穿进去参数
后来我是这样写的,想传进去一个对象,但是失败了
<body>
<div id="app">
<button-counter itle="{name:'sds'}"></button-counter>
</div>
<script>
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
props:['itle'],
template: '<button>{{itle.name}}</button>'
})
</script>
<script>
new Vue({
el:'#app',
})
</script>
最后总结出来,要这个样子用组件
<button-counter :itle="{name:'sds'}"></button-counter>
也就是加一个冒号,什么鬼,为什么一个单纯的字符串不用v-bind(也就是冒号)绑定,而一个对象就要用v-bind绑定呢?
单个根元素
当你写一个自己的组件的时候,你肯定不会只有一个标签,肯定会有很多个,但当你写了一个包含很多标签的组件的时候,你就会发现,报错了。
Vue 会显示一个错误,并解释道 every component must have a single root element (每个组件必须只有一个根元素)。你可以将模板的内容包裹在一个父元素内,来修复这个问题,例如:
<div class="blog-post">
<h3>{{ title }}</h3>
<div v-html="content"></div>
</div>
上述的这个和一些接下来的示例使用了 JavaScript 的模板字符串来让多行的模板更易读。它们在 IE 下并没有被支持,所以如果你需要在不 (经过 Babel 或 TypeScript 之类的工具) 编译的情况下支持 IE,请使用折行转义字符取而代之。(这段话啥意思我也不太懂)
监听子组件事件
最重要,最难的一部分,就是监听子组件的事件。
现在是基础,我们就对最简单的点击事件来看。
当我们在子组件中写一个button,想要这个按钮一摁,然后进行一些操作,而这个操作,是由我们父组件来确定的,这就很骚气,我们就可以用下面的方法。
我们在子组件中的按钮上添加这样一个点击事件
<div class="blog-post">
<h3>我是传奇,康佳手机</h3>
<button v-on:click="$emit('enlarge-text')">Enlarge text</button>
</div>
然后我们在父组件上使用这个组件的时候,这样写
<blog-post
v-on:enlarge-text="一个点击方法,随便写什么都行"
></blog-post>
我们可以看到,enlarge-text是联系父子组件的一个事件名,子组件可以通过调用内建的 $emit 方法 并传入事件名(也就是enlarge-text)称来触发一个事件。
而有了这个 v-on:enlarge-text=“一个点击事件” 监听器,父级组件就会接收该事件。
使用事件抛出一个值
有的时候用一个事件来抛出一个特定的值是非常有用的。
抛出的值可以是任何的东西,现在我只是尝试了传一个定值,我们也可以尝试一下用{{}}来传一个vue里面的数据,还没有测试过。
方法如下,使用 $emit 的第二个参数来提供这个值:
<button v-on:click="$emit('enlarge-text',1)">Enlarge text</button>
对,你没看错,我回传了一个数字1。
然后当在父级组件监听这个事件的时候,我们可以通过 $event
访问到被抛出的这个值:
。。。。。。
这个$event
会自动传入你的方法里,ps:这里最好是设置一个参数,然后就自动传到你的参数里面了,直接用$event和event都不管用,也不知道咋回事,这有带测试,看我这个方法:
这个值将会作为第一个参数传入这个方法:
methods:{
toBig :function(sizes){
alert(sizes)
}
}
这是使用
<blog-post
v-on:enlarge-text="toBig"
></blog-post>
在组件上使用 v-model
自定义事件也可以用于创建支持 v-model 的自定义输入组件。记住:
<input v-model="searchText">
等价于:
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
ps:$event.target.value的意思是获取当前input输入的值
不要误会,上面只是说v-modl可以被v-bind和v-on组合给替换掉
重点
当用在组件上时,v-model 则会这样:
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
也就是下面终极版的第三种
为了让它正常工作,这个组件内的 <input>
必须:
将其 value 特性绑定到一个名叫 value 的 prop 上
在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
写成代码之后是这样的:
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
现在 v-model 就应该可以在这个组件上完美地工作起来了:
<custom-input v-model="searchText"></custom-input>
v-model终极版:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"> <!--使用utf-8编码-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>组件注册</title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<style>
</style>
<body>
<div id="app">
//不使用组件
<input v-bind:value="aierlan" v-on:input="aierlan=$event.target.value"/>
//使用组件,使用v-model
<blog-post v-model="aierlan"></blog-post>
//使用组件,使用v-bind和v-on代替
<blog-post v-bind:value="aierlan" v-on:input="aierlan=$event"></blog-post>
<p>{{aierlan}}</p>
</div>
</body>
<script>
Vue.component('blog-post', {
props: ['value'],
template: `<div> <input v-bind:value="value" v-on:input="$emit('input', $event.target.value)"/></div>`
})
new Vue({
el: '#app',
data:{
aierlan:'sdsdsd'
}
})
</script>
</html>
通过插槽分发内容
这个很简单,可以通过官方文档就能看明白
动态组件
就是vue自己有一个<component>
组件,这个组件可以有一个is属性,这个属性的取值是其他组件的名字,只要是is=“组件名1”,那么这个<component>
组件就会变成组件1。
用法就是,我们可以做一个切换的列表页,如下面代码,通过点击就可以切换组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"> <!--使用utf-8编码-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script type="text/javascript" src="js/jquery.js" ></script>
<title>组件注册</title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<style>
.tab-button {
padding: 6px 10px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border: 1px solid #ccc;
cursor: pointer;
background: #f0f0f0;
margin-bottom: -1px;
margin-right: -1px;
}
.tab-button:hover {
background: #e0e0e0;
}
.active {
background: #e0e0e0;
}
.tab {
border: 1px solid #ccc;
padding: 10px;
}
</style>
<body>
<div id="app">
<button v-for="name in names"
v-bind:class="['tab-button',{ active: username === name }]"
v-on:click="username = name">{{name}}</button>
<component
v-bind:is="currentTabComponent"
class="tab"
></component>
</div>
</body>
<script>
Vue.component('button-sd', {
template: '<div>Home component</div>'
})
Vue.component('button-wxd',{
template:'<button>这是第二个组件</button>'
})
Vue.component('button-sw',{
template:'<button>这是第三个组件</button>'
})
new Vue({
el:'#app',
data:{
names:['sd','wxd','sw'],
username:'wxd'
},
computed:{
currentTabComponent:function(){
return 'button-'+this.username
}
}
})
</script>
</html>
解析 DOM 模板时的注意事项
有些 HTML 元素,诸如 <ul>、<ol>、<table>
和 <select>
,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li>、<tr>
和 <option>
,只能出现在其它某些特定的元素内部。
这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:
<table>
<blog-post-row></blog-post-row>
</table>
这个自定义组件 <blog-post-row>
会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is 特性给了我们一个变通的办法:
<table>
<tr is="blog-post-row"></tr>
</table>
(ps:也就是说,现在is就有了两个功能了,应该就这两个)
需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在的:
字符串 (例如:template: '...')
单文件组件 (.vue)
<script type="text/x-template">
到这里,你需要了解的解析 DOM 模板时的注意事项——实际上也是 Vue 的全部必要内容,大概就是这些了。恭喜你!接下来还有很多东西要去学习,不过首先,我们推荐你先休息一下,试用一下 Vue,自己随意做些好玩的东西。