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>