vue-tutorial icon indicating copy to clipboard operation
vue-tutorial copied to clipboard

组件

Open Wscats opened this issue 9 years ago • 7 comments

全局注册组件

Vue中的组件可以扩展 HTML 元素,封装可重用的代码,是Vue重要的一部分

//定义组件
var wsscat = Vue.extend({
	template: "<div>I am wsscat</div>"
})
//注册组件
Vue.component('wsscat', wsscat)
var demo = new Vue({
	el: '#demo',
	data: {
		name: 'wsscat',
	}
})

这里注意的是extend和component方法要放在new Vue()之前,不然会报错

局部注册组件

当我们全局注册组件的时候,该组件在任何地方使用,我们也可以局部注册组件,就是在父组件定义即extend时候跟着注册子组件,那么该子组件就只能在父组件中使用

<body id="demo">
	{{name}}
	<wsscat>
		<!--写在里面会被替换掉-->
		<!--<wsscat-child></wsscat-child>
            <wsscat-Child-Second></wsscat-Child-Second>-->
	</wsscat>
</body>
<script>
	var wsscatChild = Vue.extend({
		template: "<p>I'm child</p>"
	})
	var wsscatChildSecond = Vue.extend({
		template: "<span>I'm child2</span>"
	})
	//定义组件
	var wsscat = Vue.extend({
		template: "<div>I'm wsscat<wsscat-child></wsscat-child><wsscat-Child-Second></wsscat-Child-Second></div>",
		replace: true,
		components: {
			//也可以这样写wsscatChild
			'wsscatChild': wsscatChild,
			'wsscatChildSecond': wsscatChildSecond
		}
	})
	//注册组件
	Vue.component('wsscat', wsscat)
	var demo = new Vue({
		el: '#demo',
		data: {
			name: 'wsscat',
		}
	})
</script>

注意下面两种写法等价,当键值对都是同一个的时候就可以这样写

components: {
	wsscatChild: 'wsscatChild'
}
components: {
	wsscatChild
}

局部注册中定义组件并使用 下面我们就把wsscatChildThird放在wsscat这个组件定义的时候定义并注册使用

var wsscatChild = Vue.extend({
	template: "<p>I'm child</p>"
})
var wsscatChildSecond = Vue.extend({
	template: "<p>I'm child2</p>"
})
//定义组件
var wsscat = Vue.extend({
	template: "<div>I'm wsscat<wsscat-child></wsscat-child><wsscat-Child-Second></wsscat-Child-Second><wsscat-child-third></wsscat-child-third></div>",
	replace: true,
	components: {
		//也可以这样写wsscatChild
		'wsscatChild': wsscatChild,
		'wsscatChildSecond': wsscatChildSecond,
		'wsscatChildThird': {
			template: "<p>I'm child3</p>"
		}
	}
})

编写模版

我们可以用script标签设置type="text/template",并且给一个id名

<script type="text/template" id="tpl">
    <div>Hello {{name}}</div>
</script>

或者我们还可以用template标签定义这个模版

<template id="tpl">
    <div>Hello {{name}}</div>
</template>

我们就可以在template属性绑定id名,就可以读取上面的模版

var wsscat = Vue.extend({
        template: '#tpl',
        data: function() {
            return {
                name: 'Wsscat'
            }
        }
})

组件中传递数据

在组件中我们可以在定义的时候用data属性绑定数据到模版上 注意这里我们使用函数返回一个对象把数据定义出来的

var wsscatChildSecond = Vue.extend({
	template: "<p>I'm child2, I like {{skill}}</p>",
	data: function() {
		return {
			skill: "javascript"
		}
	}
})

组件接收组件外的数据

我们可以用props获取组件所在id="demo"这个作用域下定义的name数值,由于组件wsscat中的name和id=demo的name是互不影响的,所以我们可以用这样的方法把name传进去给wsscat这个组件

var wsscat = Vue.extend({
            template: '#tpl',
            props:['msg'],
            data: function() {
                return {
                    name: 'Wsscat'
                }
            }
})
// 注册
Vue.component('wsscat', wsscat)
        new Vue({
            el: '#demo',
            data: {
                name: 'wsscats'
            }
})

视图,记得msg这个属性前面要加上个冒号,其实就是等同于v-bind:msg缩写为:msg

<div id="demo">
        <wsscat :msg="name"></wsscat>
</div>
<script type="text/template" id="tpl">
        <div>Hello {{name}}</div>
        <div>{{msg}}</div>
</script>

父组件向子组件传递数据

我们只需要在子组件中加一个props属性,props属性接受一个数组,接受子组件标签上的属性,因为子组件上的属性父组件是可以控制的,我们就可以在子组件中获取到父组件的数据 例如下面<wsscat-child :test='sweet'></wsscat-child> :test相当于v-bind:test加了冒号父组件的数据就会与子组件的数据实现双向数据绑定,当然父组件能控制子组件的值,但是子组件却不能影响父组件的值

var wsscat = Vue.extend({
    template: "<input v-model='sweet' /><div>I'm wsscat<wsscat-child :test='sweet'></wsscat-child><wsscat-Child-Second></wsscat-Child-Second><wsscat-child-third></wsscat-child-third></div>",
    data:function(){
        return {
            sweet:"你好",
        }
    },
    replace:true,
    components: {
        //也可以这样写wsscatChild
        'wsscatChild': wsscatChild,
        'wsscatChildSecond': wsscatChildSecond,
        'wsscatChildThird': {
        	template:"<p>I'm child3</p>"
        }
    }
})
  • v-bind:test``:test默认单项绑定,父能影响子,子不能影响父
  • v-bind:test.sync``:test.sync父子互相能影响
  • v-bind:test.once``:test.once除了第一次赋值,父子互不影响

子组件可以用 this.$parent 访问它的父组件。根实例的后代可以用 this.$root 访问它。 参考文档 例如我们在第一个子组件wsscatChild的ready属性中添加函数,输出this.$parent,就可以在this.$parent.$data中看到父组件wsscat的name值

var wsscatChild = Vue.extend({
	props: ['test'],
	ready: function() {
		console.log(this.$parent);
	},
	template: "<p>I'm child, {{test}}</p><input v-model='test' />"
})

尽管可以访问父链上任意的实例,不过子组件应当避免直接依赖父组件的数据,尽量显式地使用 props 传递数据。另外,在子组件中修改父组件的状态是非常糟糕的做法

Wscats avatar Aug 31 '16 13:08 Wscats

自定义指令

自定义指令提供一种机制将数据的变化映射为DOM行为,也就是说我们可以用这个自定义指令来操作这个dom Vue.directive(id, definition)方法注册一个全局自定义指令

Vue.directive('mydir', {
	bind: function() {
		this.el.style.backgroundColor = '#eee'
		this.el.addEventListener("click", function() {
			alert("123")
		})
	}
})

我们就可以在组件的模版中把这个自定义指令以v-加上组件名字来绑定这个指令到该组件

var wsscat = Vue.extend({
            template: "<input v-model='sweet' /><div v-mydir>I'm wsscat</div>",
})

或者在dom中的标签上加上 <div v-mydir>abc</div>

  • bind:只调用一次,在指令第一次绑定到元素上时调用。
  • update: 在 bind 之后立即以初始值为参数第一次调用,之后每当绑定值变化时调用,参数为新值与旧值。
  • unbind:只调用一次,在指令从元素上解绑时调用。 在bind上面我们就可以在使用该指令的时候让它去绑定事件,或者操作dom 而updata我们可以这样用 视图
{{name}}
<input v-model="name" v-mydir="name" />

指令

Vue.directive('mydir', {
	bind: function() {
		this.el.style.backgroundColor = '#eee'
		this.el.addEventListener("click", function() {
			alert("123")
		})
	},
	update: function(newValue, oldValue) {
		console.log("新:"
			newValue + "旧:" + oldValue)
	},
})

我们就可以看到当我们v-mydir指令中name值发生变化的时候就会触发update函数 我们要注意的是update也会以初始值为参数调用一次

Wscats avatar Aug 31 '16 15:08 Wscats

过滤器

视图如下,我们过滤器中可以用filterBy和orderBy处理数组,filterBy是筛选对象数组中对应属性的关键词,orderBy是根据属性的值进行排序,过滤器支持链式调用,用管道符号隔开每个过滤器

<ul>
    <li v-for="todo in todos|filterBy 'Learn' in 'content'|orderBy 'id'">
            {{todo.content}}
    </li>
</ul>
data: {
	order: -1,
	todos: [{
		id: 2,
		content: 'Learn JavaScript'
	}, {
		id: 3,
		content: 'Learn Vue.js'
	}, {
		id: 1,
		content: 'Learn Angular.js'
	}, {
		id: 0,
		content: 'Wsscat'
	}],
}

输出的结果如下 qq20161008-0

当然我们可以在过滤器中穿变量来控制筛选和排序的结果

<input v-model="filter" />
<button @click="order=-order">排序</button>
<p>{{order}}</p>
<ul>
	<li v-for="todo in todos|filterBy filter in 'content'|orderBy 'id' order">
		{{todo.content}}
	</li>
</ul>

上面代码中filter和order就是变量,我们可以在input输入框和button按钮去改变它的值 这里用座变量的话就不用加单引号了,这里注意作为orderBy接收的第二个参数,改变它的值正数和负数就可以实现两种排序的方法

自定义过滤器

视图 {{name|strLength 'left' 'right'}} 过滤器

Vue.filter('strLength', function(value, l, r) {
	console.log(value + " " + l + " " + r)
	//输出字符串的长度
	return value.length
})

我们就可以自定义一个全局的过滤器,然后接受它的参数进行处理,并返回处理的结果

我们还可以在构造器Vue里面定义过滤器 视图如下 <p>{{120|wsscat 40}}</p> 代码如下

var demo = new Vue({
	el: '#demo',
	data: {
		filters: {
			wsscat: function(value, discount) {
				return value * (discount / 100);
			}
		}
	}
})

所以定义在全局就能在所有的实例中调用过滤器,如果定义在了实例里就在实例里调用过滤器

Wscats avatar Aug 31 '16 16:08 Wscats

混合

混合以一种灵活的方式为组件提供分布复用功能。混合对象可以包含任意的组件选项。 可以简单理解为组件之间复用相同的属性

<script>
	// 定义一个混合对象
	var myMixin = {
		template: "<p>{{msg}}</p>",
		created: function() {
			this.hello()
		},
		methods: {
			hello: function() {
				console.log('hello from mixin!')
			}
		}
	}
	var Component1 = Vue.extend({
		mixins: [myMixin],
		data: function() {
			return {
				msg: "第一个组件"
			}
		}
	})
	var Component2 = Vue.extend({
		mixins: [myMixin],
		data: function() {
			return {
				msg: "第二个组件"
			}
		}
	})
	Vue.component('firstComponent', Component1);
	Vue.component('secondComponent', Component2);
	var demo = new Vue({
		el: '#demo',
		data: {
			name: 'wsscat',
		}
	})
</script>

视图

<body id="demo">
	<first-component></first-component>
	<second-component></second-component>
</body>

在上面的例子中我们就可以看到Component1和Component2都复用来myMixin这个混合,然后根据定义时候传入不同的data达到不同组件复用相同属性但又有各自独特属性的效果

var demo = new Vue({
	el: '#demo',
	data: {
		name: 'wsscat',
		msg: 'wsscat的组件'
	}
})

需要注意的是我们在**#demo**中绑定msg,这个msg的值时不会影响到组件里面的值

Wscats avatar Aug 31 '16 23:08 Wscats

路由在组件间传递参数

<a v-link="{ path: '/foo' ,query: {a:'1',b:'2'}}">Go to Foo</a> 如上我们可以在v-link指令上加一个query属性,当我们链接的时候我们的路由就会变成这样route.html#!/foo?a=1&b=2 此时我们就可以在路由中带上参数传递到另一个组件 而我们就可以在组件中接受这个参数

var Foo = Vue.extend({
	template: '<p>This is foo!</p>',
	route: {
		data: function(transition) {
			this.$http.get('test.php', {
				params: {
					a: transition.to.query.a
				}
			}).then(
				function(data) {
					console.log(data);
				},
				function() {

				}
			)
		}
	},
})

我们就可以在组件定义Vue.extend()函数内的对象中用route,并获取transition.to的对象从中获取参数

另一种带参数的形式 <a v-link="{ name:'foo', params:{id:1}}">Go to Foo</a> 需要注意的是这里我们用name来寻找路由名字 所以我们在路由中要给路由添加名字name为foo,并写上路由格式/foo/:id

router.map({
        '/foo/:id': {
                name:'foo',
                component: Foo
        },
})

此时路由如果带上这个参数route.html#!/foo/1 我们就可以用transition.to.params来获取路由的参数了

.v-link-active 如果v-link对应的 URL 匹配当前的路径,该元素会被添加特定的 class 当路由切换对应的v-link就会在让该链接的样式字体变成红色

<style>
    .v-link-active {
        color: red;
    }
</style>

路由嵌套

我们要在wsscat.vue组件中再加上<router-view>标签,并且在定义wsscat路由的时候加上subRoutes属性,并设置,那我们就可以'/wsscat/ab进入到嵌套路由中

router.map({
    '/wsscat': {
        component: Wsscat,
        subRoutes: {
            '/': {
                component: {
                    template: '<p>Default sub view for Foo</p>'
                }
            },
            '/ab': {
                component: {
                    template: '<p>123</p>'
                }
            }
        }
    },
})

Vue2路由传参

我们可以用http://localhost:9000/#/foo/1匹配path: '/foo/:id这个路由,并且通过props传递参数到Foo组件,让组件接受参数

path: '/xxx/:id' props:{id:xxx} meta:{skill:xx} path: '/xxx/:id拼接(?age=1)'
this.$route.params.id接受 props:['id']接受 this.$route. meta.skill接受 this.$route.query.age接受

http://localhost:9000/#/foo/1?age=1

const router = new VueRouter({
    routes: [{
            path: '/foo/:id',
            component: Foo,
            props: {
                default: true,
                sidebar: false,
                name: 'wscats'
            },
            meta:{
                skill: 'ps'
            }
        }
    ]
})

路由守卫

全局路由守卫

router.beforeEach((to, from, next) => {
    // to: Route: 即将要进入的目标 路由对象
    // from: Route: 当前导航正要离开的路由
    // 3秒后进入页面
    setTimeout(() => {
        next() // 一定要调用next才能进入下个路由
    }, 3000)

})

Wscats avatar Sep 01 '16 15:09 Wscats

6666666666666666666666666666666

luffy115 avatar Dec 13 '16 08:12 luffy115

写得很好啊

qingruo avatar Apr 27 '17 07:04 qingruo

学习了,感觉有的比官方的文档更容易理解。(难道是我理解能力太差了?)

zhanghaoranas avatar Oct 27 '17 14:10 zhanghaoranas