vue.js methods是什么中的方法互相调用时变量的vue 作用域是怎样的

Vuejs第九篇之组件作用域及props数据传递实例详解 - 简书
Vuejs第九篇之组件作用域及props数据传递实例详解
本篇资料来于官方文档:本教程是小编结合官方文档整理的一套更加细致,代码更多更全的教程,特别适合新手阅读。props数据传递①组件实例的作用域:是孤立的,简单的来说,组件和组件之间,即使有同名属性,值也不共享。1234567891011121314151617181920212223varvm =newVue({el:'#app',components: {"add": {template:"btn:{{btn}}",data:function() {return{btn:"123"};}},del: {template:"btn:{{btn}}",data:function() {return{btn:"456"};}}}});渲染结果是:2个按钮,第一个的值是123,第二个的值是456(虽然他们都是btn)②使用props绑定静态数据:【1】这种方法用于传递字符串,且值是写在父组件自定义元素上的。【2】下面示例中的写法,不能传递父组件data属性中的值【3】会覆盖模板的data属性中,同名的值。示例代码:1234567891011121314151617181920varvm =newVue({el:'#app',data: {h:"hello"},components: {"add": {props: ['btn'],template:"btn:{{btn}}",data:function() {return{btn:"123"};}}}});这种写法下,btn的值是h,而不是123,或者是hello。【4】驼峰写法假如插值是驼峰式的,而在html标签中,由于html的特性是不区分大小写(比如LI和li是一样的),因此,html标签中要传递的值要写成短横线式的(如btn-test),以区分大小写。而在props的数组中,应该和插值保持一致,写成驼峰式的(如btnTest)。例如:12props: ['btnTest'],template:"btn:{{btnTest}}",正确的写法:1假如插值写短横线式,或者是html标签写成驼峰式,都不能正常生效。(除非插值不写成驼峰式——跳过大小写的限制,才可以)③利用props绑定动态数据:简单来说,就是让子组件的某个插值,和父组件的数据保持一致。标准写法是(利用v-bind):1如代码1234567891011121314151617181920varvm =newVue({el:'#app',data: {h:"hello"},components: {"add": {props: ['btn'],template:"btn:{{btn}}",data:function() {return{'btn':"123"};//子组件同名的值被覆盖了}}}});说明:【1】btn使用的父组件data中 h的值;【2】子组件的data的函数中返回值被覆盖了。【3】也就是说,使用v-bind的是使用父组件的值(根据属性名),没有使用v-bind的是将标签里的数值当做字符串来使用。【4】依然需要使用props,否则他会取用自己data里的btn的值④字面量和动态语法:【1】简单来说,不加v-bind的,传递的是字面量,即当做字符串(例如1也是字符串,而不是number类型);【2】加上v-bind的,传递的是JS表达式(因此才能传递父组件的值);【3】加上v-bind后,如果能找到父组件的值,那么使用父组件的值;如果没有对应的,则将其看做一个js表达式(例如1+2看做3,{a:1}看做是一个对象);如代码:1234567891011121314151617varvm =newVue({el:'#app',data: {h:"hello"},components: {"add": {props: ['btn'],template:"btn:{{btn}}"}}});这里的btn的值是3(而不是没有加v-bind时,作为字符串的1+2)⑤props的绑定类型:【1】简单来说,分为两种类型,即单向绑定(父组件能影响子组件,但相反不行)和双向绑定(子组件也能影响父组件);【2】单向绑定示例:(默认,或使用.once)1234567891011121314151617181920父组件:子组件:varvm =newVue({el:'#app',data: {val: 1},components: {"test": {props: ['testVal'],template:""}}});说明:当父组件的值被更改后,子组件的值也随之更改;当子组件的值被更改后,父组件的值不会变化,而假如再次修改父组件的值,子组件会再次同步。另外需要注意的是,子组件如果要同步绑定,那么子组件的input需要是v-model,而不能是value属性(那样只能单项绑定,且修改子组件的值后会失去绑定)【3】双向绑定:需要使用“.sync”作为修饰词如示例:1234567891011121314151617181920父组件:子组件:varvm =newVue({el:'#app',data: {val: 1},components: {"test": {props: ['test'],template:""}}});效果是无论你改哪一个的值,另外一个都会随之变动。【4】props验证:简单来说,当组件获取数据时,进行验证,只有符合条件的时候,才会使用之。写法是将props变为一个对象,被验证是值是对象的key,验证条件是和key对应的value。例如:12345props: {test: {twoWay:true}},验证test这个变量是不是双向绑定,如果不是,则报错。(注意,这个不能用于验证单向绑定)。示例代码如下:123456789101112131415161718192021222324父组件:子组件:varvm =newVue({el:'#app',data: {val: 1},components:{test:{props: {test: {twoWay:true}},template:""}}});更多验证类型请查看官方教程:问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
&div id="example"&
&component :is="component_name" @click="ccl()"&&/component&
var mycomponent = Vue.extend({
template: '&div&{{title}}hello component.&/div&',
props: ['message'],
data: function () {
return {title: this.$root.message}
methods: {
ccl: function () {
alert('right');
不是这么写的么?为什么我点击了以后没有反应呢?报错为VM9342:3 Uncaught TypeError: scope.ccl is not a function
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
这个ccl不是组件的,而是他爹的方法。你要在他爹的methods里面定义:
ponent('child',{
template: '&div&{{title}}hello component.&/div&',
props: ['message'],
var father=new Vue({
el:"#example",
"component_name":'child'
ccl:function(){
理解好vue模板里面的作用域,就能够知道为什么了。。。
========日16:01:39 补充===========
怎么将父组件的数据传递给子组件
这个文档有说啊,用props:
&component :is="xxx" :fatherMassage="msg"&&/component&
然后父组件在data里面弄个msg的字段
ponent('child',{
template: '&div v-for="item in fatherMassage.data" &{{title}}hello component.&/div&',
props: ['fatherMassage'],
ready:function(){
console.log(this.fatherMassage.list)
var father=new Vue({
el:"#example",
"component_name":'child',
list:[xxx,xxx,xx,xx,x],
ccl:function(){
vue的作者尤大的文档写的很详细啦~~~~认真看下都会明白的
同步到新浪微博
分享到微博?
你好!看起来你挺喜欢这个内容,但是你还没有注册帐号。 当你创建了帐号,我们能准确地追踪你关注的问题,在有新答案或内容的时候收到网页和邮件通知。还能直接向作者咨询更多细节。如果上面的内容有帮助,记得点赞 (????)? 表示感谢。
明天提醒我
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
扫扫下载 App深入理解Vue.js组件! - 博客频道 - CSDN.NET
无笙的博客
Vue.js引入的组件,让分解单一HTML到独立组件成为可能。组件可以自定义元素形式使用,或者使用原生元素但是以is特性做扩展。
注册和引用
使用组件之前,首先需要注册。可以注册为全局的或者是局部的。全局注册可以使用:
Vue.component(tag, options)
注册一个组件。tag为自定义元素的名字,options同为创建组件的选项。注册完成后,即可以&tag&形式引用此组件。如下是一个完整可运行的案例:
src=&/vue/dist/vue.js&
Vue.component('tag', {
template: `&div&one component rule all other&div&`
el: &#app&
你也可以局部注册,这样注册的组件,仅仅限于执行注册的Vue实例内:
src=&/vue/dist/vue.js&
var tag = {
template: `&div&one component rule all other&div&`
el: &#app&,
components: {tag}
我们注意到,&tag&是HTML本身并不具备的标签,现在由Vue的组件技术引入,因此被称为是自定义标签。这些自定义标签的背后实现常常是标签、脚本、css的集合体。它的内部可以非常复杂,但是对外则以大家习惯的简单的标签呈现。通过本节这个小小案例,组件技术带来的抽象价值已经展现出来一角了。
多个组件可以使用同一个挂载点,然后动态地在它们之间切换。元素&component&可以用于此场景,修改属性is即可达成动态切换的效果:
v-bind:is=&current&
假设我们有三个组件home、posts、archives,我们可以设置一个定时器,每隔2秒修改一次current,把三个组件的逐个切入到当前挂接点:
src=&/vue/dist/vue.js&
v-bind:is=&current&
var app = new Vue({
el: '#app',
current: 'archive',
b : ['home','posts','archive']
components: {
home: { template:'&h1&home&/h1&'},
posts: { template:'&h1&posts&/h1&' },
archive: {template:'&h1&archive&/h1&'}
this.i = this.i % 3
this.current = this.b[this.i]
this.i++
setTimeout(this.a,2000)
mounted(){
setTimeout(this.a,2000)
一个父组件内常常有多个子组件,有时候为了个别处理,需要在父组件代码内引用子组件实例。Vue.js可以通过指令v-ref设置组件的标识符,并在代码内通过$refs+标识符来引用特定组件。接下来举例说明。
假设一个案例有三个按钮。其中前两个按钮被点击时,每次对自己的计数器累加1;另外一个按钮可以取得前两个按钮的计数器值,并加总后设置{{total}}的值。此时在第三个按钮的事件代码中,就需要引用前两个按钮的实例。代码如下:
src=&/vue/dist/vue.js&
{{ total }}
v-on:click=&value&value
Vue.component('count', {
template: '&button v-on:click=&inc&&{{ count }}&/button&',
data: function () {
return {count: 0}
methods: {
inc: function () {
this.count+= 1
el: '#app',
data: {total:0},
methods: {
value: function () {
this.total = this.$refs.b1.count+this.$refs.b2.count
标签button使用ref设置两个按钮分为为b1、b2,随后在父组件代码内通过$refs引用它们。
按照组件分解的愿景,一个大型的HTML会按照语义划分为多个组件,那么组件之间必然存在协作的问题。Vue.js提供的协作方式有属性传递、事件传递和内容分发。
此方法用于父组件传递数据给子组件。每个组件的作用域都是和其他组件隔离的,因此,子组件不应该直接访问父组件的数据,而是通过属性传递数据过来。如下案例传递一个字符串到子组件:
src=&/vue/dist/vue.js&
message=&hello&
Vue.component('child', {
props: ['message'],
template: '&span&{{ message }}&/span&'
new Vue({el:'#app'})
本案例会显示
在页面上。这里,父组件为挂接在#app上的Vue实例,子组件为child。child使用props声明一个名为message的属性,此属性把父组件内的字符串hello传递数据到组件内。
如果不是传递一个静态的字符串,而是传递JavaScript表达式,那么可以使用指令v-bind:
src=&/vue/dist/vue.js&
v-bind:message=&hello+',world'&
Vue.component('child', {
props: ['message'],
template: '&span&{{ message }}&/span&'
el:'#app',
data:{hello:'hi'}
运行结果为:
本案例把父组件内的hello成员传递给子组件。出现在属性内的hello不再指示字面上的字符串,而是指向一个表达式,因此传递进来的是表达式的求值结果。
当通过属性传递表达式时,有些时候类型是特定的,Vue提供了属性的验证,包括类型验证,范围验证等。比如传递年龄进来的话,要求应该是整数。案例如下:
src=&/vue/dist/vue.js&
v-bind:age=&age&
Vue.component('child', {
props: {'age':Number},
template: '&span&you are {{ age }}&/span&'
el:'#app',
data:{age:'30'}
如果你使用的是开发版本的vue.js,那么会在控制台得到一个警告,Vue 将拒绝在子组件上设置此值:
[Vue warn]: Invalid prop: type check failed for prop &age&. Expected Number, got String.
(found in component &child&)
当把age的那一行修改为数字,即:
data:{age:30}
警告就会消失。属性名称后可以加入类型,类型检查除了使用Number,还可以有更多,完整类型列表如下:
你还可以在属性名后跟一个对象,在此对象内指定范围检查,提供默认值,或者要求它是必选属性:
src=&/vue/dist/vue.js&
v-bind:age=&age&
Vue.component('child', {
props: {'age':{
type:Number,
validator: function (value) {
return value & 0 && value&150
required:true,
default:50
template: '&span&you are {{ age }}&/span&'
el:'#app',
data:{age:'149'}
官方手册提供了一个相对全面的验证样例:
Vue.component('example', {
// 基础类型检测 (`null` 意思是任何类型都可以)
propA: Number,
// 多种类型
propB: [String, Number],
// 必传且是字符串
type: String,
required: true
// 数字,有默认值
type: Number,
default: 100
// 数组/对象的默认值应当由一个工厂函数返回
type: Object,
default: function () {
return { message: 'hello' }
// 自定义验证函数
validator: function (value) {
return value & 10
每个Vue实例都有事件接口,组件是一个具体的Vue实例,因此也有事件接口,用来发射和接收事件,具体事件如下:
发射事件:$on(event)
接收事件:$emit(event)
我们假设一个案例来说明事件通讯。此案例中,有一个父组件绑定在#app上,还有两个按钮组件,点击任何一个按钮让自己的计数器加1,并且让父组件内的一个计数器加1。图例:
使用一个案例,来演示事件的使用:
src=&/vue/dist/vue.js&
{{ total }}
Vue.component('count', {
template: '&button v-on:click=&inc&&{{ count }}&/button&',
data: function () {
return {count: 0}
methods: {
inc: function () {
this.count+= 1
this.$emit('inc')
el: '#app',
data: {total: 0},
mounted(){
this.$refs.b1.$on('inc',this.inc)
this.$refs.b2.$on('inc',this.inc)
methods: {
inc: function () {
this.total += 1
在父组件的绑定完成钩子函数(函数mounted)内,通过$on方法监听inc事件到this.inc。在子组件count内,完成对自己的计数器count加1后随即使用$emit发射事件给父组件。另外,我们使用了v-ref指令为每一个子组件一个引用标识符,从而在代码内可以使用形如:
this.$refs.childRefName
来引用子组件实例。除了在js代码内通过$on方法设置监听代码外,也可以使用指令v-on在HTML内达成类似效果:
src=&/vue/dist/vue.js&
{{ total }}
v-on:inc='inc'
v-on:inc='inc'
Vue.component('count', {
template: '&button v-on:click=&inc&&{{ count }}&/button&',
data: function () {
return {count: 0}
methods: {
inc: function () {
this.count+= 1
this.$emit('inc')
el: '#app',
data: {total: 0},
methods: {
inc: function () {
this.total += 1
这种方法的好处是:
省下了ref属性的声明,因为不必在代码中引用组件。
在HTML就可以一目了然地看到监听的是哪个子组件。
可以利用组件,把较大的HTML分解为一个个自洽的组件。比如常见的论坛首页的HTML的架构可能是这样的:
class='wrapper'
class='navigator'navigator...
class='content'
class='topics'topics...
class='userinfo'userinfo...
所有的内容全部呈现在一个HTML内。可以想见此文件巨大,并且还会随着需求的变化而继续增长。如果使用组件来做分解,那么首页可以变为:
注意:使用标签content1,而不是content,是因为后者是html内置的标签,我们的自定义标签不应该和内置标签冲突。
本来嵌入在div内的内容,现在可以分解到一个个的组件内。比如topics,形如:
var topics = {
template: `&div class='topics'&topics...&/div&`
如下是一个可运行的案例:
src=&/vue/dist/vue.js&
Vue.component('topics',{
template: `&div class=&topics&&topics ...&div&`
Vue.component('userinfo',{
template: `&div class=&userinfo&&userinfo ...&div&`
Vue.component('content1',{
template: `&div class=&content&&&slot&&/slot&&div&`,
var navi = Vue.component('navi',{
template: `&div class=&navigator&&navigator ...&div&`
var wrapper = Vue.component('wrapper',{
template: `&div class=&wrapper&&&slot&&/slot&&div&`,
el: &#app&,
components:{
请留意到wrapper组件模板内使用了&slot&标签,content1组件内也使用了&slot&。标签&slot&的语义是——请把使用此组件自定义标签内的全部内容抓取过来,放置到&slot&所在的位置上。以content1为例,它在自定义标签内的全部内容为:
这里内容会直接被抓取过来,放置到&slot&处,从而混合得到content最终的模板:
class=&content&
这个过程奇妙而难解,但是非常有用。这意味着,可以通过&slot&,把父组件内的HTML片段传递到组件内,从而完成一种另类的父子数据传递。
随即发生的,是&topics&和&userinfo&代表的组件的内容也混入到content1内,变成
class=&content&
class=&topics&topics ...
class=&userinfo&userinfo ...
就这样,我们通过&slot&技术,一步步从组件还原出最初的HTML。这个技术被称为内容分发。slot,也就是插槽,是内容分发的重要标签。
如果子组件模板包含&slot&,父组件的内容就会被插入到&slot&位置上并替换掉&slot&标签本身,否则父组件内的内容将会被丢弃。
如果&slot&标签中本身是有内容的,那么这些内容如何和插入的内容合并呢?这些本有的内容被视为备用内容。也就是说,如果父组件内元素为空,备用内容会保留,否则就会被丢弃。
假定子组件foo有下面模板:
父组件内容如下:
parent content
渲染结果:
parent content
如果父组件为:
那么渲染结果为:
如下是一个整合后的案例:
src=&/vue/dist/vue.js&
parent content
Vue.component('foo', {
template: `
el: '#app'
你可以试试删除&p&parent content&/p&,对比父组件有无内容带来的差别。
嵌入到子组件标签的内容,可以通过给予属性slot不同的值,来区别不同的插槽。在子组件内使用&slot name=''&方式来引用它们。有了命名插槽,内容分发可以变得更加灵活。在多个插槽的场景下,如果找不到匹配的插槽,可以使用一个备用的插槽来承载内容。如果内容既找不到命名插槽,也没有备用插槽的话,就会被丢弃。
假设一个子组件&app-layout&模板为:
class=&container&
name=&header&
父组件模板为:
slot=&header&title
那么渲染结果:
class=&container&
综合案例:插槽
现在我们看一个高级的案例,我来做一个即时贴(sticky)组件,用来显示一个有标题和主体的即时贴。组件会定义好即时贴的结构和外观,而具体的标题和内容值则使用内容分发技术来传入组件:
src=&/vue/dist/vue.js&
class=&& id=&app&
slot=&title&
slot=&body&
Body foo bar baz
Vue.component('sticky', {
template: `
&div class=&wrapper&&
&div class=&title&&
&slot name=&title&&&/slot&
&div class=&body&&
&slot name=&body&&&/slot&
el: &#app&
.wrapper {
display: flex;
width: 180px;
height: 150px;
background: yellow;
border-radius: 10px;
border-bottom:1px solid red
border-bottom:1px solid blue
本案例内,使用上下文通过属性slot创建了两个插槽,分别为title和body,在组件的模板内通过&slot&标签引用对应名称的插槽(title和body),并把它注入到插槽标签占据的位置上。
使用事件总线
如果两个组件之间没有父子关系,但是也需要通讯,可以使用事件总线。具体做法就是创建一个空的Vue实例作为中介,事件发起方调用此实例的$emit方法来发射事件,而事件监听方使用此实例的$on方法来挂接事件。
举例说明。此案例代码中有两个按钮,点击一个按钮会让另一个按钮的组件的count加1。代码如下:
src=&/vue/dist/vue.js&
var bus = new Vue({})
Vue.component('foo', {
template: '&button v-on:click=&inc&&{{ count }}&/button&',
data: function () {
return {count: 0}
mounted(){
bus.$on('foo-inc',this.doinc)
methods: {
inc: function () {
bus.$emit('bar-inc',this)
doinc: function () {
this.count++
Vue.component('bar', {
template: '&button v-on:click=&inc&&{{ count }}&/button&',
data: function () {
return {count: 0}
mounted(){
bus.$on('bar-inc',this.doinc)
methods: {
inc: function () {
bus.$emit('foo-inc',this)
doinc: function () {
this.count++
el: '#app'
这里列出的案例,是同属一个父组件的两个兄弟组件的通讯方法。实际上作为总线方式的Vue实例,可以用于任何组件之间的通讯。
为了演示说明vue的组件通讯,我们从一个假设的todo应用开始(再次:)。UI当然还是类似这样的:
但是这次的新意在于,我们会把整个app分为三个组件,层次关系如下:
--todoList
app作为父应用组件,newTodo作为一个子组件负责用户输入,并且获取新的todo;而todoList作为另外一个子组件,它需要负责显示全部todo项目到列表中。
这样的分工在稍微大的app中非常常见,由此达成分而治之的目的。但是组件之间势必需要通讯,比如newTodo组件必须把新的todo字符串通知到todoList组件,以便后者更新todo列表并由此更新用户界面。
基于组件结构的通讯
在Vue.js 1.0版本内,从子组件到父组件的通讯,Vue.js提供了$dispatch方法,而从父组件到子组件则是通过 $broadcast方法。我们在如下的代码中使用了此技术:
src=&https://cdn.jsdelivr.net/vue/1.0.28/vue.min.js&
id=&todo-app&
var newTodo = {
template:'&div&&input type=&text& autofocus v-model=&newtodo&/&&button @click=&add&&add&/button&&/div&',
newtodo:''
add:function(){
this.$dispatch('newtodo',this.newtodo)
this.newtodo = ''
var todoList = {
template:'&ul& \
&li v-for=&(index,item) in items&&{{item}} \
&button @click=&rm(index)&&X&/button&&/li& \
items:['item 1','item 2','item 3'],
rm:function(i){
this.items.splice(i,1)
'newtodo': function (newtodo) {
this.items.push(newtodo)
var app= new Vue({
el:'#todo-app',
components:{
newTodo:newTodo,
todoList:todoList
'newtodo': function (newtodo) {
this.$broadcast('newtodo',newtodo)
整个通讯过程是这样的:
组件newTodo在用户点击按钮后,会把新的todo字符串通过$dispatch发出。
而父组件app在event内截获此事件,随即通过$broadcast方法发送到子组件。
子组件todoList在event内截获此事件取出payload,加入它到数据items内。
这就是组件通讯的方法。Vue.js并没有为兄弟组件提供直接的通讯方法,如果兄弟组件之间需要通讯,只能先发给父组件,父组件向子组件广播,侦听此事件的子组件随后获取此事件。
通过$broadcast+$dispatch完成组件通讯是可行的,但是问题不少:
依赖于树形组件结构,你得知道组件的结构是怎么样的。
组件结构复杂的话,必然降低通讯效率。
兄弟组件直接不能直接通讯,必须通过父组件间接完成。
在Vue2.0版本内,此方法已经被废弃。
集中化的eventBus
实际上,我们只是为了让两个组件交换数据,这个过程并不应该和组件的结构(父子关系的组件,兄弟关系的组件)捆绑在一起。因此,一个变通的方式是引入一个新的组件,用它作为组件之间的通讯中介,此技术被称为Event Bus。如下代码正式利用了此技术:
src=&https://cdn.jsdelivr.net/vue/1.0.28/vue.min.js&
id=&todo-app&
var eventHub =new Vue( {
todos:['A','B','C']
created: function () {
this.$on('add', this.addTodo)
this.$on('delete', this.deleteTodo)
beforeDestroy: function () {
this.$off('add', this.addTodo)
this.$off('delete', this.deleteTodo)
methods: {
addTodo: function (newTodo) {
this.todos.push(newTodo)
deleteTodo: function (i) {
this.todos.splice(i,1)
var newTodo = {
template:'&div&&input type=&text& autofocus v-model=&newtodo&/&&button @click=&add&&add&/button&&/div&',
newtodo:''
add:function(){
eventHub.$emit('add', this.newtodo)
this.newtodo = ''
var todoList = {
template:'&ul& \
&li v-for=&(index,item) in items&&{{item}} \
&button @click=&rm(index)&&X&/button&&/li& \
items:eventHub.todos
rm:function(i){
eventHub.$emit('delete', i)
var app= new Vue({
el:'#todo-app',
components:{
newTodo:newTodo,
todoList:todoList
由此代码我们可以看到:
app组件不再承担通讯中介功能,而只是简单的作为两个子组件的容器。
eventBus组件承载了全部的数据(todos),以及对数据的修改,它监听事件add和delete,在监听函数内操作数据。
子组件todoList的data成员的数据来源改为从eventBus获取,删除todo的方法内不再操作数据,而是转发给eventBus来完成删除。
子组件newTodo的按钮不再添加数据,而是转发事件给eventBus,由后者完成添加。
这样做,就把本来捆绑到组件结构上的通讯还原为单纯的通讯,并且集中数据和操作到一个对象(eventBus),也就有利于组件的数据共享。当我们谈到eventBus的时候,我们离vuex——一个更加专业的状态管理库就比较近了。后文会谈及vuex。
组件编码风格
Vue组件是很好的复用代码的方法。接下来,我们使用一个微小的案例来讲解组件。我们可以看到HTML代码:
@click=&inc&+
标签&span&和&button&其实一起合作,完成一个完整的功能,它们是内聚的;因此可以利用组件的概念,用一个语义化的自定义标签,把两个标签包装到一个组件内。以此观念,做完后应该得到这样的代码:
为此,我们需要创建一个组件,它可以容纳两个标签以及和它们有关的方法和数据。我们会采用多种方案来完成此组件,从而了解组件的多种编码风格。首先,我们从使用集中template的组件编码风格开始。
集中模板式
以下代码是可以直接保存为html文件,并使用浏览器来打开运行的:
src=&/vue/dist/vue.js&
var counter = {
'template':'&div&&span&{{count}}&/span&&button v-on:click=&inc&&+&/button&&/div&',
return {count: 0}
methods: {
inc () {this.count++}
var app = new Vue({
components:{
counter : counter
app.$mount('#app')
我们对代码稍作解释:
Vue的实例属性template。它的值用来承载模板代码,本来放置在主HTML内的两个标签现在搬移到此处。需要注意的是,两个标签外套上了一个div标签,因为Vue2.0版本要求作为模板的html必须是单根的。
Vue的实例属性components。它可以被用来注册一个局部组件。正是在此处,组件counter被注册,从而在html标签内可以直接使用标签&counter&来引用组件counter。
引入组件技术后,强相关性的html标签和对应的数据、代码内聚到了一起,这是符合软件工程分治原则的行为。
另外,使用template在代码内混合html字符串还是比较烦人的:
你得小心的在外层使用单引号,在内部使用双引号。
如果html比较长,产生了跨行,这样的字符串书写比较麻烦。
我们继续查看其它方案。
分离模板式
为了增加可读性,模板字符串内的HTML可以使用多种方式从代码中分离出来。比如采用x-template方法:
src=&/vue/dist/vue.js&
type=&x-template& id=&t&
&span&{{count}}&/span&
&button v-on:click=&inc&&+&/button&
var counter = {
'template':'#t',
return {count: 0}
methods: {
inc () {this.count++}
var app = new Vue({
components:{
counter : counter
app.$mount('#app')
模板x-template使用标签script,因为这个标签的类型是浏览器无法识别的,故而浏览器只是简单地放在DOM节点上。这样你可以使用getElementById方法获得此节点,把它作为HTML片段使用。
或者使用在HTML5引入的新标签template,看起来稍微干净些:
src=&/vue/dist/vue.js&
v-on:click=&inc&+
var counter = {
'template':'#t',
return {count: 0}
methods: {
inc () {this.count++}
var app = new Vue({
components:{
counter : counter
app.$mount('#app')
或者如果组件内容并不需要做分发的话,可以通过inline-template标记它的内容,把它当作模板:
src=&/vue/dist/vue.js&
inline-template
v-on:click=&inc&+
var counter = {
return {count: 0}
methods: {
inc () {this.count++}
var app = new Vue({
components:{
counter : counter
app.$mount('#app')
Render函数可以充分利用JavaScript语言在创建HTML模板方面的灵活性。实际上,组件的Template最终都会转换为Render函数。对于同一需求,使用Render函数的代码如下:
src=&/vue/dist/vue.js&
return {count: 1}
methods: {
inc () {this.count++}
render:function(h){
// var self =
var buttonAttrs = {
on: { click: this.inc },
domProps: {
innerHTML: '+'
var spanAttrs = {
on: { click: this.inc },
domProps: {
innerHTML: this.count.toString()
var span = h('span', spanAttrs, []);
var button = h('button', buttonAttrs, []);
return h('div'
el:'#app',
components:{
counter : a
函数render的参数h,其实是一个名为createElement 的函数,可以用来创建元素。此函数的具体说明,请参考官方手册即可。为了方便,此处完整使用createElement的实例代码抄写自vue.js手册。如下 :
createElement(
// {String | Object | Function}
// An HTML tag name, component options, or function
// returning one of these. Required.
// {Object}
// A data object corresponding to the attributes
// you would use in a template. Optional.
// (see details in the next section below)
// {String | Array}
// Children VNodes. Optional.
createElement('h1', 'hello world'),
createElement(MyComponent, {
someProp: 'foo'
如果要标签名本身都是可以动态的,怎么办?比如我希望提供一个标签,可以根据属性值动态选择head的层级,像是把
可以替代为:
:level=&1&header1
:level=&2&header2
使用render函数解决此类问题是非常便利的。具体做法就是先注册一个组件:
Vue.component('hdr', {
render: function (createElement) {
return createElement(
'h' + this.level,
// tag name
this.$slots.default // array of children
type: Number,
required: true
随后在html内使用此组件:
//javascript
el: '#example'
&div id=&example&&
&hdr :level=&1&&abc&/hdr&
&hdr :level=&2&&abc&/hdr&
可以执行的代码在此:
src=&/ajax/libs/vue/2.0.3/vue.js&
id=&example&
:level=&1&abc
:level=&2&abc
type=&text/javascript& Vue.component('hdr', {
render: function (createElement) {
console.log(this.level)
return createElement(
'h' + this.level,
this.$slots.default
type: Number,
required: true
el: '#example'
函数render会传入一个createElement函数作为参数,你可以使用此函数来创建标签。在render函数内,可以通过this.$slots访问slot,从而把slot内的元素插入到当前被创建的标签内。
web_wusheng
排名:千里之外
(1)(0)(1)(8)}

我要回帖

更多关于 vuejs methods 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信