默认情况下子组件是无法访问父组件中的data和methods的:
<div id="app"> <comp></comp> </div> <script> var vm = new Vue({ el:'#app', data:{ msg:' This is father msg' }, methods:{}, components:{ comp: { template:'<h2>这是子组件--{{msg}}</h2>'//此处是无法访问到父组件中的data和methods的 } } }); </script>语法:
v-bind:自定义一个属性名称="传入的父组件中的变量名称" 但是该自定义的属性必须要在子组件中事先声明,需要在子组件中的props数组中定义 props:['自定义属性名称']组件中的props数组数据全都是父组件传递给子组件的。props中的数据都是只读的,无法重新赋值。data中的数据是组件私有的可读可写的
实现方式:
<div id="app"> <comp v-bind:parentmsg="msg"></comp> </div> <script> var vm = new Vue({ el:'#app', data:{ msg:' This is father msg' }, methods:{}, components:{ comp: { data:{},//子组件中的data是自身私有的,不是父组件传入的。是可读可写的,比如子组件通过ajax请求的数据可以放在data上。 template:'<h2>这是子组件--{{msg}}</h2>',//此处是无法访问到父组件中的data和methods的 props:['parentmsg']//该数组中的数据,都是父组件传入的,并且都是只读的,父组件定义的属性名称,要在此声明,才能接收。 } } }); </script>语法:
组件标签中通过v-on:自定事件属性名称="父组件中的方法名称" 简写为@自定义属性名称="父组件中的方法名称" 子组件在对应事件触发入口通过 this.$emit('自定义属性名称')实例:
<div id="app"> <comp @func="show"></comp> </div> <template id="temp"> <div> <h1>这是子组件</h1> <input type="button" value="调用父组件的方法" @click="mycompClick"> </div> </template> <script> var vm = new Vue({ el:'#app', data:{ msg:' This is father msg' }, methods:{ show(){ } }, components:{ comp: { data:{}, template:'#temp', methods:{ mycompClick(){ this.$emit('func');//这样就实现了对父组件中的方法的调用 //this.$emit('func',参数1,参数2)//实现调用父组件中的方法并传参,参数只要跟着方法名后面就行了,其实通过参数的这种方式也可以实现子组件向父组件传值。 } } } } }); </script>上面已经说了,可以通过父组件向子组件传入一个有参数的方法的方式,可以实现父组件中接收该参数的该方式,来实现子组件向父组件传值。
vue提供了ref属性可以帮助我们快速获取到元素,vue实例中有一个$refs 中就是元素
<div id="app"> <input type="button" value="获取元素内容" @click="getElement"> <h3 ref="myh3">This is H3 </h3> <login ref="mylogin"></login> </div> <script> var login = { template: '<h3>这是登录组件</h3>' }; var vm = new Vue({ el:'#app', data:{}, methods:{ getElement(){ console.log(this.$refs.myh3.innerText); console.log(this.$refs.mylogin.innerText); } }, components:{ login } }); </script>上面可以得到我们可以使用ref获取组件,因此可以通过$refs获取到组件,然后直接获取使用其数据和方法。
this.$refs.mylogin.msg;//直接调取其数据 this.$refs.mylogin.login();//直接调用其方法对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上的资源。
对于单页面应用程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时,hash有一个特点:HTTP请求中不会包含hash相关的的内容,及#号后面的内容;所以,单页面程序中的页面跳转主要用hash实现。在单页面应用程序中,这种通过hash改变切换页面的方式,叫做前端路由。
Unpkg.com提供了基于npm的cdn链接。https://unpkg.com/vue-router/dist/vue-router.js 该链接一致指向NPM发布的最新版本。你也可以像https://unpkg.com/vue-router@2.0.0/dist/vue-router.js这样指定版本号或者Tag。在Vue后面加载vue-router,它会自动安装的:
<script src="/path/to/vue.js"></script> <script src="/path/to/vue-router.js"></script>如果在一个模块化工程(比如说通过webpack构建的)中使用它,必须要通过Vue.use()明确的安装路由功能:
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter)如果使用全局的script标签,则无需如此(手动安装),即3.2.1的方式是不需要使用Vue.use(VueRouter)这种操作的。
安装vue-router之后便可使用,创建VueRouter实例对象,传入一个配置对象或者配置对象数组,配置对象即路由配置规则,每一个路由配置规则有两个属性:
path : 表示监听的那个路由链接地址;component : **该属性的值只能放模板对象不能放组件名称. **表示 如果路由是前面匹配到的path,则展示component属性对应的组件。vue实例通过router属性,建立与VueRouter实例对象的关系,router属性的租用是将路由规则对象VueRouter注册到vm实例上,用来监听URL地址的变化,然后展示对应的组件。页面中通过vue-router提供的元素router-view标签来进行展示,否则无效果,因为该标签是专门用来当做占位符的,路由规则匹配到的组件就会展示到这个router-view中去。所以我们可以认为router-view 是一个占位符。
实例代码如下:
<script src="libs/vue.js"></script> <script src="libs/vue-router.js"></script> <body> <div id="app"> <a href="#/login">登录</a><!-- 因为vue中的路由是基于hash的所以必须要加#号 --> <a href="#/register">注册</a><!-- 因为vue中的路由是基于hash的所以必须要加#号 --> <router-view></router-view> </div> <script> var login = { template: '<h3>我是登录组件</h3>' }; var register = { template: '<h3>我是注册组件</h3>' }; var routerObj = new VueRouter({//在创建路有对象的时候可以通过构造函数,传递一个配置对象 //route //这个配置对象中的route 表示路由配置规则 routes: [// 路由匹配规则,可以有多个,即每个按钮跳转的组件或者页面 {path:'/login',component:login},//每个路由规则都是一个对象,path属性表示监听的那个路由链接地址,component属性表示如果路由是前面匹配到的path,则展示component属性对应的组件。此处component 值只能写成login不能写成'login' {path:'/register',component:register} ]// }); var vm = new Vue({ el:'#app', data:{}, methods:{}, router:routerObj//通过该属性与VueRouter对象建立关联关系 }); </script> </body>从上述实例中我们可以得出,其实路由的改变规则就是通过hash方式改变了地址栏(即通过修改URL地址,因为该URL地址已经注册到了VueRouter对象上了,路由规则对象会监听URL的改变进行对路由规则的匹配,一旦检测到对应的path与该URL匹配便展示该path对应的对象的component组件到reouter-view中去。)
和上面的区别在于不使用a标签,而换成router-link标签,router-link默认渲染成一个a标签的效果。
<router-link to="/login">登录</router-link> <router-link to="/register">注册</router-link> <router-view></router-view> <script> routes: [// 路由匹配规则,可以有多个,即每个按钮跳转的组件或者页面 {path:'/',redirect:'/login'},//这里的redirect重定向是前端的重定向,和后端的重定向是不同的,这里作用是让页面默认展示某个组件 {path:'/login',component:login}, {path:'/register',component:register} ]// </script>router-link 选中时默认样式为router-link-active 类样式,所以可以通过该样式来修改被选中时的样式。
还可以通过设置链接激活时使用的CSS类名。默认值可以通过路由的构造选项linkActiveClass来全局配置
var routerObject = new VueRouter({ routes: [], linkActiveClass:'myactive' });另外可以用transition标签将router-view包裹起来实现router-view的切换效果动画。
如果在路由中使用查询字符串给路由传递参数,则不需要修改路由规则的path属性
<router-link to="/login?id=1101&name=张三"></router-link> <router-view></router-view> <script> var login = { template: '<h3>我是登录组件---{{$route.query.id}}---{{$route.query.name}}</h3>' }; </script>该方式需要再路由设置的时候指定参数
<div id="app"> <router-link to="/login/1201/张三">登录</router-link> <router-link to="/register">注册</router-link> <router-view></router-view> </div> <script> var login = { template:'<h3>登录----{{$route.params.id}}---{{$route.params.name}}</h3>' data(){ return { msg:'123' } }, created(){//组件的生命周期函数 console.log(this.$route.params.id); } } var router = new VueRouter({ routes:[ {path:'/login/:id/:name',component: login}//需要通过斜杠和冒号来指定参数 ] }); </script>通过route的children属性配置子路由
比如说一个account下嵌套login 和register两个组件,实现方式如下:
<script> var router = new VueRouter({ routes:[ { path:'/account', component:account, children:[//子路由的path 前面不要带斜线 {path:'login',component:login},//注意不能加斜线 {path:'login',component:register}//注意不能加斜线 ] } ] }); </script>给视图组件router-view进行命名,然后通过route的components属性来制定对应视图组件要展示的组件。具体实例如下:
<div id="app"> <router-view></router-view> <router-view name="left"></router-view><!-- 命名该视图组件为left--> <router-view name="main"></router-view> </div> <script> var header = { template:'我是头部' }; var leftBox = { template:'我是左侧栏' }; var mainBox = { template:'我是主面板' }; var router = new VueRouter({ routes:[ { path:'/', components:{ 'default': header,//默认展示组件header 'left': leftBox,//试图组件名称为left的展示leftBox 组件 'main': mainBox } } ] }); </script>可以通过watch属性监视 data 中指定数据的变化,触发该属性中对应的function处理函数,对应的该function函数可以传入两个参数[newValue, oldValue] 分别对应的是输入改变后和输入改变前的数据内容。
<div id="app"> <input type = "text" v-model="firstName"> <input type = "text" v-model="lastName"> <input type = "text" v-model="fullName"> </div> <script> var vm = new Vue({ el: 'app' , data: { firstName: '' , lastName: '' , fullName: '' }, methods: {}, watch: { 'firstName' : function(){//当firstName中的值发生改变就会触发该function function(newValue,oldValue)// 参数可选 this.fullName = this.firstName + ' ' + this.lastName; }, 'lastName' : function(newValue){ this.fullName = this.firstName+ ' ' + newValue;//newValue 和 this.lastName 值是一样的 } } }); </script>另一种实现上述功能的方式-- keyup
通过@keyup添加键盘抬起时的事件处理逻辑,实现数据的动态监听与改变。
<div id="app"> <input type = "text" v-model="firstName" @keyup="updateFullName"> <input type = "text" v-model="lastName" @keyup="updateFullName"> <input type = "text" v-model="fullName"> </div> <script> var vm = new Vue({ el: 'app' , data: { firstName: '' , lastName: '' , fullName: '' }, methods: { updateFullName() { this.fullName = this.firstName + ' ' + this.lastName; } } }); </script>但是,当上述事件改成路由的监听时,@keyup则无能为力了,这是就凸显了watch属性的作用了——watch监听路由地址的改变
思路:只需要监听到 $route.path 的值的改变也就是路由地址的值。
var vm = new Vue({ el:'#app', data: {}, methods: {}, router, watch: { '$route.path': function(newValue,oldValue) { //此处可以处理路由地址变更的逻辑 } } });在computed属性中,可以定义一些计算属性,计算属性的本质就是一个方法,且是有返回值的一个方法,在使用这些计算属性的时候把方法的名称直接当做属性来使用,并不会把计算属性当做方法调用。
比如我们将上述watch属性的监听方式替换成computed的方式:
<div id="app"> <input type = "text" v-model="firstName"> <input type = "text" v-model="lastName"> <input type = "text" v-model="fullName"> </div> <script> var vm = new Vue({ el: 'app' , data: { firstName: '' , lastName: '' //, //fullName: '' //此处的data中的fullName删掉 }, methods: {}, computed: { 'fullName': function(){//将fullName的声明放在此处 return this.firstName + ' ' + this.lastName; } } }); </script>methods: 该属性内是一些方法,主要处理一些业务逻辑操作;
**watch:**内容组成方式是一个键(需要观察的表达式),值(是对应的回调函数),主要用于监听指定数据的变化或者是虚拟的数据(比如路由),从而进行某些具体的业务逻辑操作,可以看成是computed和methods的结合体;
computed: 它主要处理一些计算逻辑,且必须有返回值,且计算结果会被缓存,如果没有变更是不会重新计算的,主要被当做属性来使用;