vue组件原生事件以及路由

1.组件

组件就是可以扩展HTML元素,封装可重用的HTML代码,可以将组件看作自定义的HTML元素

1.1组件注册

全局注册:

组件注册时,需要给他一个名字,如下:

Vue.component('my-component-name', { /* ... */ })

# 组件名使用kebab-case (短横线分隔命名)定义时,引用这个元素时使用 <my-component-name>

# 组件名使用 PascalCase (驼峰式命名) 定义时,引用这个元素时使用<my-component-name> 和 <MyComponentName>都可以

局部注册:

通过一个普通的 JavaScript 对象来定义组件

var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }

然后在component选项中定义想要的组件

new Vue({
  el: '#app'
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})

# 局部注册的组件在其子组件中不可用

全局注册实例:

组件的复用(主体代码):

<body>
    <div id="app">
        <buttons></buttons>
        <buttons></buttons>
        <buttons></buttons>
    </div>
    <hr>
    <div id="app2">
        <buttons></buttons>
    </div>
</body>
<script>
    // 组件中data必须是一个函数,第一个参数是我们的定义标签
    Vue.component('buttons',{
        data:function(){
            return{
                count:0
            }
        },
        template:`<button v-on:click='count++'>biubiubiu{{ count }}</button>`
    })

    var app = new Vue({
        el:"#app"
    })

    var app2 = new Vue({
        el:"#app2"
    })
</script>

效果:

局部注册实例:

(父组件往子组件传值)

<body>
    <div id="app">
        <bts v-bind:name='fir'></bts>    
        <bts v-bind:name='sec'></bts>    
        <bts v-bind:name='thi'></bts>    
        <hr>
        <bts v-for='nums in list' v-bind:name='nums'></bts>
    </div>
</body>
<script>
    // 这里的buttons属于我们的自定义标签,通过props向子组件传递数据
    var myComponent = {
        template:`<button v-on:click="cli">{{name}}+{{count}}</button>`,
    // 使用props声明,组件需要外边从data给传一个字符串格式的name变量
        props:{
            name:String
        },    
        data:function(){
            return{
                count:0,
            }
        },
        methods:{
            cli:function(){
                this.count += 1
            }
        }
    }

    // 自定义局部组件
    new Vue({
        el:'#app',
        data:{
            list:[
            '1',
            '2',
            '3',
            ],
            fir:'first',
            sec:'second',
            thi:'third',
        },
        components:{
            bts:myComponent    
        }
    })
</script>

效果:

1.2props

官网链接

2.组件组织:

该图很好的表明了组件的组织关系对应图,或者说是层级关系

Vue.js通过组件,把一个单页应用中的各种模块拆分到一个一个单独的组件(component)中,只要先在父级应用中写好各种组件标签,并且在组件标签中写好要传入组件的参数(就像给函数传入参数一样,这个参数叫做组件的属性),然后再分别写好各种组件的实现,然后整个应用就算做完了

3.组件中的数据传递(props)

<body>
    <div id="app">
        <!-- 写死了 -->
        <buttons title="My journey with Vue"></buttons>
        <buttons title="Blogging with Vue"></buttons>        
    </div>
    <hr>
    <!-- 动态传递 -->
    <div id="app2">
        <buttons
        v-for="post in posts"
          v-bind:key="post.id"
          v-bind:title="post.title"
        ></buttons>
    </div>
</body>
<script>
    Vue.component('buttons', {
              props: ['title'],
              template: '<h3>{{ title }}</h3>'
    })

    var app = new Vue({
        el:"#app",
    })

    var app2 = new Vue({
        el:"#app2",
        // 动态传递一个数组
        data: {
        posts: [
              { id: 1, title: 'My journey with Vue' },
              { id: 2, title: 'Blogging with Vue' },
            ]
      }
    })
</script>

 子组件往父组件传值:

<body>
    <div id="app">
        <p>总数:{{total}}</p>
        <bts v-for='nums in list' v-bind:name='nums' v-on:zhi="add"></bts>
    </div>
</body>
<script>
    // 这里的bts属于我们的自定义标签,通过props向子组件传递数据
    var myComponent = {
        template:`
        <div>
        <button v-on:click="cli">{{count}}{{name}}</button>       
        </div>
        `,
    // 使用props声明,组件需要外边从data给传一个字符串格式的name变量
        props:{
            name:String
        },    
        data:function(){
            return{
                count:0,
            }
        },
        methods:{
            cli:function(){
                this.count += 1;
            // 在组件中通过触发自定义事件向外传递信息
            this.$emit('zhi')
            }
        }
    }

    // 自定义局部组件
    new Vue({
        el:'#app',
        data:{
            total:0,
            list:[
            '只猪','只狗','只兔子',
            ]    
        },
        components:{
            bts:myComponent    
        },
        methods:{
            add:function(){
                this.total += 1
            }
        }
    })
</script>

效果:

组件间传值(生成一个空vue对象bus):

各个组件内部要传输的数据或者要执行的命令信息,靠bus来通信。

<body>
<div id="app">
    <bt></bt>
    <hr>
    <nums></nums>
</div>

</body>
<script>
    var bus = new Vue();
    var app = new Vue({
        el:'#app',
        data:{
            name:'bt'
        },
        components:{
            bt:{
                template:`<button v-on:click='check'>点我</button>`,
                methods:{
            check(){
                bus.$emit('things')
            }
        }
    },
        nums:{
            template:`<div>{{num}}</div>`,
            data:function(){
                return {
                    num: 0
                }
                
            },
            mounted:function(){
                // 该组件中this指num实例
                var _this = this;
                console.log(_this);
                // 监听bus
                bus.$on('things', function(){
                        // 在这个作用域中 this 指的是 bus
                        console.log(this.num)  // undefined
                        // 修改num组件中的num值
                        // 此时this是谁?
                        // this.num += 1;  // 有问题
                        _this.num += 1;
                    })
                }

            }
        }
        
    })
</script>

在第一个组件中的methods方法里,通过bus.$emit()方法发射事务

在第二个组件实例化的钩子中(mounted)中,通过bus.$on监听自家$emit触发的事件

4.插槽:(使用自定义标签<slot>元素达到目的的)

官网链接

插槽是占位置的!!!
插槽多了可以起名字,进行区分! --> <span slot='heihei'>嘿嘿!</span>

<body>
    <div id="app">
        <alert-box>
            Something bad happened.
        </alert-box>
    </div>
</body>
<script>
    Vue.component('alert-box', {
        template: `
        <div class="demo-alert-box">
        <strong>Error!</strong>
        <slot></slot>
        </div>
        `
    })
    new Vue({
        el:"#app"
    })    
</script>

效果:

5.将原生事件绑定到组件(.naive修饰符)

  如果想在一个组件的根元素上直接监听一个原生事件,这时候就可以使用v-on的.naive修饰符

实例0(不推荐使用):

<body>
<div id="app">
    <ztzsb v-on:click='hehe'></ztzsb>
</div>
</body>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            name: 'ztz',
            age: 24
        },
        components: {
            ztzsb: {
                template: `<button v-on:click='shangkele'>赵天柱 逃课!</button>`,
                methods:{
                    shangkele:function(){
                        this.$emit('click')
                    }
                }
            }
        },
        methods:{
            hehe:function(){
                alert(123);
            }
        }
    })
</script>
</html>

实例1:

<body>
    <div id="app">
        <ztz v-on:click.native='hehe'></ztz>
    </div>
</body>
<script>
    var app = new Vue({
        el:"#app",
        data:{},

        components:{
            ztz:{
                template:`<button>赵天柱 逃课!</button>`
            },
        },
        methods:{
            hehe:function(){
                alert(123);
            }
        }
    })
</script>
</html>

再看看下面的实例2:

<body>
    <div id="app">
        <ztz></ztz>
    </div>
</body>
<script>
    var app = new Vue({
        el:"#app",
        data:{},
        components:{
            ztz:{
                template:`<button v-on:click='hehe'>赵天柱 逃课!</button>`,
                methods:{
                    hehe(){
                        alert(123);
                    }
                }
            },    
        }
    })
</script>

## 实例1和2两者效果一模一样,一个是在根元素上进行事件绑定,一个是在局部组件上进行绑定  

6.总结

1. Vue组件
0. 组件注意事项!!!
	data属性必须是一个函数!

1. 注册全局组件
	Vue.component('组件名',{
		template: ``
	})
	
	var app = new Vue({
		el: '#app'
	})
2. 注册局部组件
	var app = new Vue({
		el: '#app',
		components:{
			局部组件名:{
				template: `...`
			}
		}
	})
3. 传值
	1. 父组件 --> 子组件
		1. 父组件通过 v-bind:变量='值'
		2. 子组件需要通过props 声明我需要的变量
	2. 子组件 --> 父组件
		子组件通过触发自定义事件的方式向外传递信息
		1. 子组件: this.$emit('自定义事件')
		2. 父组件: v-on:自定义事件='方法名'
		
	3. 组件间传值
		1. 补充:Vue实例的生命周期钩子函数(共8个)
			1. beforeCreate    --> 数据属性声明但没有赋值
			2. created         --> 数据属性赋值
			3. beforeMount     --> 页面上的 {{name}} 还没有被渲染
			4. mounted         --> 页面上的 {{name}} 被替换成真正的内容
			...
			
		2. 基于bus对象实现
	
4. 插槽(slot)
	插槽是占位置的!!!
	插槽多了可以起名字,进行区分!   --> <span slot='heihei'>嘿嘿!</span>
	<alert>根本不显示</alert>
	
		
5. 组件的注意事项:
	1. 特殊的组件需要使用is语法声明一下 比如 table、select、ul等内部使用的组件
	2. 捕获子组件的原生事件

7.Vue.Router

  Vue Router 是 Vue.js 官方的路由管理器

  将组件 (components) 映射到路由 (routes),然后告诉 Vue Router 在哪里渲染它们,实现异步ajax界面切换效果(页面不刷新)

# 例,注意vue-router.js的引入方式

<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<body>
	<div id="app">
		<!-- 路由入口 -->
		<router-link to='/index'>index页面</router-link>	
		<router-link to='/home'>home页面</router-link>
		<hr>
		<!-- 路由出口 -->
		<router-view></router-view>	
	</div>
</body>
	<script>
		// 路由,数组包含两个路由
		const routess = [
		{path:'/index',component:{template:`<div><h2>index页面</h2></div>`}},
		{path:'/home',component:{template:`<div><h2>home页面</h2></div>`}},
		]
		// 生成实例,routes是关键字,它的值必须是一个数组
		const routerObj = new VueRouter({
			routes:routess
		})

		new Vue({
			el:'#app',
			// 路由实例挂载到vue实例中,router是关键字
			router:routerObj
		})
	</script>  
</body>
</html>

 效果:

7.1路由动态匹配 

我们有一个 User 组件,对于 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个目的

一个“路径参数”使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到 this.$route.params,如下

 

实例:

<body>
<div id="app">
    <!--路由的入口-->
    <!-- 使用 router-link 组件来导航. -->
    <!-- 通过传入 `to` 属性指定链接. -->
    <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
    <router-link to="/user/index">index页面</router-link>
    <router-link to="/user/home">home页面</router-link>
    <hr>
    <p>666</p>
    <!--路由的出口-->
    <!-- 路由匹配到的组件将渲染在这里 -->
    <router-view></router-view>
    <p>999</p>
</div>
<script>
    //写路由
    const routeArray = [
        { path: '/user/:name',
            component: {template: `<h3>这是{{$route.params.name}}的主页页面!</h3>`}
        }
    ]
    //生成路由实例
    const routerObj = new VueRouter({
        routes: routeArray
    })
    var app = new Vue({
        el:'#app',
        //router是关键字,它的值必须是数组
        router:routerObj  //将路由实例挂载到vue实例中
    })
</script> 

  效果:

7.2嵌套路由(子路由)

 URL 中各段动态路径按某种结构对应嵌套的各层组件,如下:

  

实例(关键点在于使用append拼接路由):

<div id="app">
    <router-link to="/user/index">index</router-link>
    <router-link to="/user/home">home</router-link>
    <hr>
    <router-view></router-view>
</div>
<script>
	// 生成路由数组
    const routeArray = [
        {
            path: '/user/:name',
            component: {
                //append表示当前路由拼接url,比如/user/home/info
                //router-view对应子路由的template的内容
                template: `<div>
                    <h3>这是{{$route.params.name}}的主页页面!</h3>
                    <hr>
                    <router-link to='info' append>用户详细信息</router-link>
                    <router-view></router-view>
                </div>`
            },
            // 定义子路由
            children:[
                {
                    path: 'info',
                    component:{
                        template: `
                            <div>
                                <h1>大傻逼</h1>
                            </div>
                        `
                    }
                },
            ]
        }
    ]
    //生成VueRouter实例
    const routerObj = new VueRouter({
        //routes是关键字参数,它必须对应一个数组
        routes: routeArray
    })
    var app = new Vue({
        el:'#app',
        data:{},
        //router是关键字,它的值必须是数组
        router:routerObj  //将路由实例挂载到vue实例中
    })
</script>

效果:

总结:

1. Vue全家桶
	Vue + VueRouter + VueX
2. VueRouter  https://router.vuejs.org/zh/
	1. 基本使用
		1. 必须导入vue-router.js文件
		2. 要有VueRouter()实例
		3. 要把VueRouter实例挂载到Vue实例中
		
		4. 路由的入口
			<router-link to='/index'>index页面</router-link>
		5. 路由的出口
			<router-view></router-view>
	2. 路由的参数
		1. path: '/user/:name' --> 匹配路由
		$route.params.name     --> 取值
		
		2. /user/alex?age=9000 --> url中携带参数
		$route.query.age       --> 取出url的参数
		
	3. 子路由
		children:[
			{
				path: '',
				component: {
					template: `...`
				}
			}
		]
		
		<router-link to='info' append></router-link>

 

  

posted @ 2018-07-25 18:49  -Learning-  阅读(642)  评论(0编辑  收藏  举报