Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

组件 #3

Open
Wscats opened this issue Aug 31, 2016 · 7 comments
Open

组件 #3

Wscats opened this issue Aug 31, 2016 · 7 comments

Comments

@Wscats
Copy link
Owner

Wscats commented Aug 31, 2016

全局注册组件

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
Copy link
Owner Author

Wscats commented Aug 31, 2016

自定义指令

自定义指令提供一种机制将数据的变化映射为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
Copy link
Owner Author

Wscats commented Aug 31, 2016

过滤器

视图如下,我们过滤器中可以用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
Copy link
Owner Author

Wscats commented Aug 31, 2016

混合

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

<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
Copy link
Owner Author

Wscats commented Sep 1, 2016

路由在组件间传递参数

<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)

})

@luffy115
Copy link

6666666666666666666666666666666

@qingruo
Copy link

qingruo commented Apr 27, 2017

写得很好啊

@zhanghaoranas
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants