vue学习第八天——组件基础

基本示例(官网找去)

因为组件是可复用的 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,自己随意做些好玩的东西。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值