重新系统学习vue笔记

重新系统学习一遍

视频教程地址:vue教程-黑马-205集完整版
视频教程源码:视频教程配套资料

Day1

P3:前端框架

vue Angular React三大主流框架。VUE只关注视图层,易上手。

P4:前端发展历程

原生JS》Jquery类库》前端模板引擎》Angular/Vue
在VUE里,用户不再操作DOM元素,提高渲染率,双向绑定

P6:MVC和MVVM

在这里插入图片描述
MVVM是Model-View-ViewModel的缩写。

  • Model代表数据模型负责业务逻辑和数据封装;
  • View代表UI组件负责界面和显示;
  • ViewModel监听模型数据的改变和控制视图行为,处理用户交互,简单来说就是通过双向数据绑定把View层和Model层连接起来。

在MVVM架构下,View和Model没有直接联系,而是通过ViewModel进行交互,我们只关注业务逻辑,不需要手动操作DOM,不需要关注View和Model的同步工作。

P8:v-cloak

v-cloak能够解决插值表达式未加载完成的问题。默认v-text是没有闪烁问题的。v-text会覆盖元素中原本的内容。v-cloak不会。

<p v-cloak>++++++{{ msg }}+++++</p>
<p v-text=”msg”>+++++++++++++</p>

P9:v-bind

v-bind是vue中用于提供绑定属性的指令。其中也可以写合法的js表达式。缩写是“:”

P10:v-on

v-on是事件绑定机制。methods属性中定义该实例所有的方法。缩写是“@”。

P11:

在VM实例中,如果想要获取data上的数据或调用methods中的方法,必须通过this.数据属性名或this.方法名。
VM实例会监听自己data中所有数据的改变,一改变就会同步到页面上。
箭头函数()=>

P12:定时器

setInterval()定时器。clearInterval()停止定时器。

P13:事件修饰符

.stop阻止冒泡;
.prevent阻止默认事件;
.capture添加事件监听器时使用事件捕获模式。
.self只有点击该事件的元素的时候才会触发事件处理函数(阻止自己冒泡行为)
.once事件只触发一次

P14:v-model

v-model唯一双向绑定。
v-bind 只能实现数据的单向绑定,从 M 自动绑定到 V,无法实现数据的双向绑定

 <input type="text" v-bind:value="msg" style="width:100%;">

使用 v-model 指令,可以实现 表单元素和 Model 中数据的双向数据绑定
注意: v-model 只能运用在 表单元素中,如input(radio, text, address, email…) select checkbox textarea

<input type="text" style="width:100%;" v-model="msg">

P16:使用class样式

数组

<h1 :class="['red', 'thin']">这是一个邪恶的H1</h1>

数组中使用三元表达式

<h1 :class="['red', 'thin', isactive?'active':'']">这是一个邪恶的H1</h1>

数组中嵌套对象

<h1 :class="['red', 'thin', {'active': isactive}]">这是一个邪恶的H1</h1>

直接使用对象

<h1 :class="{red:true, italic:true, active:true, thin:true}">这是一个邪恶的H1</h1>

P17:使用内联样式

在data上定义样式:

data: {
      h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' },
      h1StyleObj2: { fontStyle: 'italic' }
}

在元素中,通过属性绑定的形式,将样式对象应用到元素中:

<h1 :style="[h1StyleObj, h1StyleObj2]">这是一个善良的H1</h1>

P18~P19:v-for用法

P20:v-if和v-show的区别

v-if 的特点:每次都会重新删除或创建元素
v-show 的特点: 每次不会重新进行DOM的删除和创建操作,只是切换了元素的 display:none 样式

Day2

P26:vue-devtools调试工具的安装和使用

P28:全局过滤器的定义和使用

// 定义一个 Vue 全局的过滤器,名字叫做 msgFormat,第一个参数一定是data数据

 Vue.filter('msgFormat', function (msg, arg, arg2) {
     return msg.replace(/单纯/g, arg + arg2)
 })
 //定义第二个过滤器
 Vue.filter('test', function (msg) {
   return msg + '========'
 })

调用方法如下:使用|符号调用,msg是第一个参数

<p>{{ msg | msgFormat('疯狂+1', '123') | test }}</p>

P30:私有过滤器的定义

var vm2 = new Vue({
  el: '#app2',
  data: {
    dt: new Date()
  },
  methods: {},
  filters: {
	// 定义私有过滤器,有两个条件【过滤器名称 和 处理函数】
    // 过滤器调用的时候,采用的是就近原则,如果私有过滤器和全局过滤器名称一致了,这时候 优先调用私有过滤器
    dateFormat: function (dateStr, pattern = '') {
		//处理逻辑
    }
  }
});

P31:padStart()

//padStart方法:如果字符串没有满足长度2则自动补字符串‘0’上去。
var d = dt.getDate().toString().padStart(2, '0')

P32:自定义全局按键修饰符

定义:

//113是对应按键F2的ASCII码
Vue.config.keyCodes.f2 = 113

调用:

<input type="text" class="form-control" v-model="name" @keyup.f2="add">

P33:使用全局自定义指令

//使用Vue.directive()定义全局的指令v-focus
//其中:参数1:指令的名称,注意,在定义的时候,指令的名称前面,不需要加 v- 前缀, 
//但是:在调用的时候,必须在指令名称前加上 v- 前缀来进行调用
//参数2:是一个对象,这个对象身上,有一些指令相关的函数,这些函数可以在特定的阶段,执行相关的操作
Vue.directive('focus', {
	//注意:在每个钩子函数中,第一个参数,永远是el,表示被绑定了指令的那个元素,这个 el 参数,是一个原生的JS对象
    bind: function (el) { //每当指令绑定到元素上的时候,会立即执行这个 bind 函数,只执行一次
        //在元素 刚绑定了指令的时候,还没有 插入到 DOM中去,这时候,调用 focus 方法没有作用
        //因为,一个元素,只有插入DOM之后,才能获取焦点
        //el.focus()
 	},
    inserted: function (el) {  //inserted 表示元素 插入到DOM中的时候,会执行 inserted 函数【触发1次】
        el.focus()
        //和JS行为有关的操作,最好在 inserted 中去执行,放置 JS行为不生效
    },
    updated: function (el) {  //当VNode更新的时候,会执行 updated, 可能会触发多次
    }
})

P34:binding

自定义指令中钩子函数的第二个参数binding,表示该指令元素的一个对象。该对象包含参数“name”,“value”,“expression”等。

P35~P36:定义私有指令。

原理和私有过滤器一样,Vue对象里的自定义指令属性是“directives”;

directives: { // 自定义私有指令
	'fontweight': { // 设置字体粗细的
		bind: function (el, binding) {
			el.style.fontWeight = binding.value
		}
	},
	//简写形式
	'fontsize': function (el, binding) { // 注意:这个 function 等同于 把 代码写到了 bind 和 update 中去
	 	el.style.fontSize = parseInt(binding.value) + 'px'
	}
}

P37~P38:生命周期

什么是生命周期

从Vue实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期!

  • 生命周期钩子:就是生命周期事件的别名而已;
  • 生命周期钩子 = 生命周期函数 = 生命周期事件

主要的生命周期函数分类

  • 创建期间的生命周期函数:
    beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性
    created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始 编译模板
    beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中
    mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示
  • 运行期间的生命周期函数:
    beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点
    updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!
  • 销毁期间的生命周期函数:
    beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。
    destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
  el: '#app',
  data: {
	msg: 'ok'
  },
  methods: {
	show() {
	  console.log('执行了show方法')
	}
  },
  beforeCreate() { // 这是我们遇到的第一个生命周期函数,表示实例完全被创建出来之前,会执行它
	// console.log(this.msg)
	// this.show()
	// 注意: 在 beforeCreate 生命周期函数执行的时候,data 和 methods 中的 数据都还没有没初始化
  },
  created() { // 这是遇到的第二个生命周期函数
	// console.log(this.msg)
	// this.show()
	//  在 created 中,data 和 methods 都已经被初始化好了!
	// 如果要调用 methods 中的方法,或者操作 data 中的数据,最早,只能在 created 中操作
  },
  beforeMount() { // 这是遇到的第3个生命周期函数,表示 模板已经在内存中编辑完成了,但是尚未把 模板渲染到 页面中
	// console.log(document.getElementById('h3').innerText)
	// 在 beforeMount 执行的时候,页面中的元素,还没有被真正替换过来,只是之前写的一些模板字符串
  },
  mounted() { // 这是遇到的第4个生命周期函数,表示,内存中的模板,已经真实的挂载到了页面中,用户已经可以看到渲染好的页面了
	// console.log(document.getElementById('h3').innerText)
	// 注意: mounted 是 实例创建期间的最后一个生命周期函数,当执行完 mounted 就表示,实例已经被完全创建好了,此时,如果没有其它操作的话,这个实例,就静静的 躺在我们的内存中,一动不动
  },


  // 接下来的是运行中的两个事件
  beforeUpdate() { // 这时候,表示 我们的界面还没有被更新【数据被更新了吗?  数据肯定被更新了】
	/* console.log('界面上元素的内容:' + document.getElementById('h3').innerText)
	console.log('data 中的 msg 数据是:' + this.msg) */
	// 得出结论: 当执行 beforeUpdate 的时候,页面中的显示的数据,还是旧的,此时 data 数据是最新的,页面尚未和 最新的数据保持同步
  },
  updated() {
	console.log('界面上元素的内容:' + document.getElementById('h3').innerText)
	console.log('data 中的 msg 数据是:' + this.msg)
	// updated 事件执行的时候,页面和 data 数据已经保持同步了,都是最新的
  }
});
</script>

生命周期图解
在这里插入图片描述

P39: vue-resource

Vue实现ajax:
vue-resource过时了,现在一般用的是Axios,需要引用第三方包。
axios

var test=new Vue({
    el:"#app",
    data:{        
    },
    methods:{
		send:function(){          
			axios({
				method: 'get',
				url: 'http://127.0.0.1/xinxi/public/index.php/index/index/szxx'
			})
			.then(function (response) {
				console.log(response)
			})
			.catch(function (error) {
				console.log(error)
			})
		}
	}        
});

Day3

P44:全局配置请求地址

如果我们通过全局配置了,请求的数据接口根域名,则在每次单独发起 http 请求的时候,请求的 url 路径,应该以相对路径开头,前面不能带 / ,否则 不会启用根路径做拼接;

Vue.http.options.root = 'http://vue.studyit.io/';

P45:全局启用emulateJSON

全局启用 emulateJSON 选项

Vue.http.options.emulateJSON = true;

P46:动画过渡

在进入/离开的过渡中,会有 6 个 class 切换。
在这里插入图片描述

<style>
/* v-enter 【这是一个时间点】 是进入之前,元素的起始状态,此时还没有开始进入 */
/* v-leave-to 【这是一个时间点】 是动画离开之后,离开的终止状态,此时,元素 动画已经结束了 */
.v-enter,
.v-leave-to {
  opacity: 0;
  transform: translateX(150px);
}

/* v-enter-active 【入场动画的时间段】 */
/* v-leave-active 【离场动画的时间段】 */
.v-enter-active,
.v-leave-active{
  transition: all 0.8s ease;
}
</style>

<!-- 使用 transition 元素,把需要被动画控制的元素,包裹起来 -->
<!-- transition 元素,是 Vue 官方提供的 -->
<transition>
  <h3 v-if="flag">这是一个H3</h3>
</transition>

P47:自定义动画类前缀

标签transition没有指定名称时,Vue动画类默认以“v-”做前缀。指定名称后则以名称做前缀。

<style>
.my-enter,
.my-leave-to {
  opacity: 0;
  transform: translateY(70px);
}
.my-enter-active,
.my-leave-active{
  transition: all 0.8s ease;
}
</style>
<transition name="my">
  <h6 v-if="flag2">这是一个H6</h6>
</transition>

P48:第三方动画库animate.css

第三方类库了解就行了,用的也不多,一般动画也是自己写,不会因为一个动画而且引用一整个库,

<link rel="stylesheet" href="./lib/animate.css">
<transition 
   enter-active-class="bounceIn" 
   leave-active-class="bounceOut" 
   :duration="{ enter: 200, leave: 400 }">
     <h3 v-if="flag" class="animated">bounceIn,bounceOut,animated都是第三方类库定义好的。</h3>
</transition>

P49~P51:动画钩子函数

<body>
  <div id="app">
    <input type="button" value="快到碗里来" @click="flag=!flag">
    <!-- 1. 使用 transition 元素把 小球包裹起来 -->
    <transition
      @before-enter="beforeEnter"
      @enter="enter"
      @after-enter="afterEnter">
      <div class="ball" v-show="flag"></div>
    </transition>
  </div>
</body>  
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
  el: '#app',
  data: {
	flag: false
  },
  methods: {
	// 注意: 动画钩子函数的第一个参数:el,表示 要执行动画的那个DOM元素,是个原生的 JS DOM对象
	// 大家可以认为 , el 是通过 document.getElementById('') 方式获取到的原生JS DOM对象
	beforeEnter(el){
	  // beforeEnter 表示动画入场之前,此时,动画尚未开始,可以 在 beforeEnter 中,设置元素开始动画之前的起始样式
	  // 设置小球开始动画之前的,起始位置
	  el.style.transform = "translate(0, 0)"
	},
	enter(el, done){
	  // 这句话,没有实际的作用,但是,如果不写,出不来动画效果;
	  // 可以认为 el.offsetWidth 会强制动画刷新
	  el.offsetWidth
	  // enter 表示动画 开始之后的样式,这里,可以设置小球完成动画之后的,结束状态
	  el.style.transform = "translate(150px, 450px)"
	  el.style.transition = 'all 1s ease'

	  // 这里的 done, 起始就是 afterEnter 这个函数,也就是说:done 是 afterEnter 函数的引用
	  done()
	},
	afterEnter(el){
	  // 动画完成之后,会调用 afterEnter
	  // console.log('ok')
	  this.flag = !this.flag
	}
  }
});
</script>

P52~P54:列表动画transition-group

<!-- <ul> -->
  <!-- 在实现列表过渡的时候,如果需要过渡的元素,是通过 v-for 循环渲染出来的,不能使用 transition 包裹,需要使用 transitionGroup -->
  <!-- 如果要为 v-for 循环创建的元素设置动画,必须为每一个 元素 设置 :key 属性 -->
  <!-- 给 ransition-group 添加 appear 属性,实现页面刚展示出来时候,入场时候的效果 -->
  <!-- 通过 为 transition-group 元素,设置 tag 属性,指定 transition-group 渲染为指定的元素,如果不指定 tag 属性,默认,渲染为 span 标签 -->
  <transition-group appear tag="ul">
	<li v-for="(item, i) in list" :key="item.id" @click="del(i)">
	  {{item.id}} --- {{item.name}}
	</li>
  </transition-group>
<!-- </ul> -->

P55:模块化和组件化的区别

  • 模块化: 是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一;
  • 组件化: 是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用;

P56~P58:创建组件的三种方式

  1. 使用 Vue.extend 配合 Vue.component 方法:
// 1.1 使用 Vue.extend 来创建全局的Vue组件
// var com1 = Vue.extend({
//   template: '<h3>这是使用 Vue.extend 创建的组件</h3>' // 通过 template 属性,指定了组件要展示的HTML结构
// })
// 1.2 使用 Vue.component('组件的名称', 创建出来的组件模板对象)
// Vue.component('myCom1', com1)
// 如果使用 Vue.component 定义全局组件的时候,组件名称使用了 驼峰命名,则在引用组件的时候,需要把 大写的驼峰改为小写的字母,同时,两个单词之前,使用 - 链接;
// 如果不使用驼峰,则直接拿名称来使用即可;
// Vue.component('mycom1', com1)
// Vue.component 第一个参数:组件的名称,将来在引用组件的时候,就是一个 标签形式 来引入 它的
// 第二个参数: Vue.extend 创建的组件  ,其中 template 就是组件将来要展示的HTML内容
var login = Vue.extend({
      template: '<h1>登录</h1>'
    });
Vue.component('login', login);
//调用方式在html里面直接<login></login>
  1. 直接使用 Vue.component 方法:
Vue.component('register', {
      template: '<h1>注册</h1>'
});
  1. 将模板字符串,定义到script标签种:
<script id="tmpl" type="x-template">
	<div><a href="#">登录</a> | <a href="#">注册</a></div>
</script>

同时,需要使用 Vue.component 来定义组件:

Vue.component('account', {
      template: '#tmpl'
    });

注意: 组件中的DOM结构,即template的值有且只能有唯一的根元素(Root Element)来进行包裹!

P59:定义实例内部私有组件

var vm2 = new Vue({
  el: '#app2',
  components: { // 定义实例内部私有组件的
	login: {
	  template: '#tmpl2'
	}
  },
})
<template id="tmpl2">
  <h1>这是私有的 login 组件</h1>
</template>
<div id="app2">
  <login></login>
</div>

P60~P61:组件中的data数据

// 1. 组件可以有自己的data数据
// 2. 组件的data和实例的data有点不一样,实例中的data可以为一个对象,但是 组件中的data必须是一个方法
// 3. 组件中的data除了必须为一个方法之外,这个方法内部,还必须返回一个对象才行;
// 4. 组件中的data数据,使用方式,和实例中的data使用方式完全一样!!!
Vue.component('mycom1', {
  template: '<h1>这是全局组件 --- {{msg}}</h1>',
  data: function () {
	return {
	  msg: '这是组件的中data定义的数据'
	}
  }
})

P63:组件的切换

<body>
  <div id="app">
    <a href="" @click.prevent="comName='login'">登录</a>
    <a href="" @click.prevent="comName='register'">注册</a>
    <!-- Vue提供了 component ,来展示对应名称的组件 -->
    <!-- component 是一个占位符, :is 属性,可以用来指定要展示的组件的名称 -->
    <component :is="comName"></component>
    <!-- 总结:当前学习了几个 Vue 提供的标签了??? -->
    <!-- component,  template,  transition,  transitionGroup  -->
  </div>
  <script>
    // 组件名称是 字符串
    Vue.component('login', {
      template: '<h3>登录组件</h3>'
    })
    Vue.component('register', {
      template: '<h3>注册组件</h3>'
    })
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        comName: 'login' // 当前 component 中的 :is 绑定的组件的名称
      },
      methods: {}
    });
  </script>
</body>

P64:组件切换动画

在组件component外面再包一层transition实现动画效果

<!-- 通过 mode 属性,设置组件切换时候的 模式 -->
<transition mode="out-in">
  <component :is="comName"></component>
</transition>

Day4

P67:父组件向子组件传值

  1. 组件实例定义方式,注意:一定要使用props属性来定义父组件传递过来的数据
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
  el: '#app',
  data: {
	msg: '123 啊-父组件中的数据'
  },
  components: {
	// 子组件默认无法访问到父组件中的 data 上的数据 和 methods 中的方法
	com1: {
	  data() { // 注意: 子组件中的 data 数据,并不是通过 父组件传递过来的,而是子组件自身私有的,比如: 子组件通过 Ajax ,请求回来的数据,都可以放到 data 身上;
		// data 上的数据,都是可读可写的;
		return {
		  title: '123',
		  content: 'qqq'
		}
	  },
	  template: '<h1 @click="change">这是子组件 --- {{ parentmsg }}</h1>',
	  // 注意: 组件中的 所有 props 中的数据,都是通过 父组件传递给子组件的
	  // props 中的数据,都是只读的,无法重新赋值
	  props: ['parentmsg'], // 把父组件传递过来的 parentmsg 属性,先在 props 数组中,定义一下,这样,才能使用这个数据
	  methods: {
		change() {
		  this.parentmsg = '被修改了'
		}
	  }
	}
  }
});
</script>
  1. 使用v-bind或简化指令,将数据传递到子组件中:
<div id="app">
<!-- 父组件,可以在引用子组件的时候, 通过 属性绑定(v-bind:) 的形式, 把 需要传递给 子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用 -->
<com1 :parentmsg="msg"></com1>
</div>

P68:子组件向父组件传数据

  1. 原理:父组件将方法的引用,传递到子组件内部,子组件在内部调用父组件传递过来的方法,同时把要发送给父组件的数据,在调用方法的时候当作参数传递进去;
  2. 父组件将方法的引用传递给子组件,其中,show是父组件中methods中定义的方法名称,func是子组件调用传递过来方法时候的方法名称
<com2 @func="show"></com2>
  1. 子组件内部通过this.$emit('方法名', 要传递的数据)方式,来调用父组件中的方法,同时把数据传递给父组件使用
<body>
  <div id="app">
    <!-- 父组件向子组件 传递 方法,使用的是 事件绑定机制; v-on, 当我们自定义了 一个 事件属性之后,那么,子组件就能够,通过某些方式,来调用 传递进去的 这个 方法了 -->
    <com2 @func="show"></com2>
  </div>

  <template id="tmpl">
    <div>
      <h1>这是 子组件</h1>
      <input type="button" value="这是子组件中的按钮 - 点击它,触发 父组件传递过来的 func 方法" @click="myclick">
    </div>
  </template>
</body>
<script>
// 定义了一个字面量类型的 组件模板对象
var com2 = {
  template: '#tmpl', // 通过指定了一个 Id, 表示 说,要去加载 这个指定Id的 template 元素中的内容,当作 组件的HTML结构
  data() {
	return {
	  sonmsg: { name: '小头儿子', age: 6 }
	}
  },
  methods: {
	myclick() {
	  // 当点击子组件的按钮的时候,如何 拿到 父组件传递过来的 func 方法,并调用这个方法???
	  //  emit 英文原意: 是触发,调用、发射的意思
	  // this.$emit('func123', 123, 456)
	  this.$emit('func', this.sonmsg)
	}
  }
}
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
  el: '#app',
  data: {
	datamsgFormSon: null
  },
  methods: {
	show(data) {
	  // console.log('调用了父组件身上的 show 方法: --- ' + data)
	  // console.log(data);
	  this.datamsgFormSon = data
	}
  },
  components: {
	com2
	// com2: com2
  }
});
</script>

P71:ref获取DOM元素和组件

使用 this.$refs 来获取元素和组件

<div id="app">
  <div>
    <input type="button" value="获取元素内容" @click="getElement" />
    <!-- 使用 ref 获取元素 -->
    <h1 ref="myh1">这是一个大大的H1</h1>
    <hr>
    <!-- 使用 ref 获取子组件 -->
    <my-com ref="mycom"></my-com>
  </div>
</div>
<script>
  Vue.component('my-com', {
    template: '<h5>这是一个子组件</h5>',
    data() {
      return {
        name: '子组件'
      }
    }
  });
  // 创建 Vue 实例,得到 ViewModel
  var vm = new Vue({
    el: '#app',
    data: {},
    methods: {
      getElement() {
        // 通过 this.$refs 来获取元素
        console.log(this.$refs.myh1.innerText);
        // 通过 this.$refs 来获取组件
        console.log(this.$refs.mycom.name);
      }
    }
  });
</script>

P72:前端路由

  1. 前端路由:对于单页面应用程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时,hash有一个特点:HTTP请求中不会包含hash相关的内容;所以,单页面程序中的页面跳转主要用hash实现;
  2. 在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由);

P73:导入vue-router组件

<!-- 1.导入 vue-router 组件类库 -->
<script src="./lib/vue-router-2.7.0.js"></script>

P74~P78:vue-router基本使用

// 组件的模板对象
var login = {
  template: '<h1>登录组件</h1>'
}
var register = {
  template: '<h1>注册组件</h1>'
}
// 创建一个路由对象, 当 导入 vue-router 包之后,在 window 全局对象中,就有了一个 路由的构造函数,叫做 VueRouter
// 在 new 路由对象的时候,可以为 构造函数,传递一个配置对象
var routerObj = new VueRouter({
  // route // 这个配置对象中的 route 表示 【路由匹配规则】 的意思
  routes: [ // 路由匹配规则 
	// 每个路由规则,都是一个对象,这个规则对象,身上,有两个必须的属性:
	//  属性1 是 path, 表示监听 哪个路由链接地址;
	//  属性2 是 component, 表示,如果 路由是前面匹配到的 path ,则展示 component 属性对应的那个组件
	// 注意: component 的属性值,必须是一个 组件的模板对象, 不能是 组件的引用名称;
	// { path: '/', component: login },
	{ path: '/', redirect: '/login' }, // 这里的 redirect 和 Node 中的 redirect 完全是两码事
	{ path: '/login', component: login },
	{ path: '/register', component: register }
  ],
  linkActiveClass: 'myactive'//用来修改路由router-link标签默认的class类
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
  el: '#app',
  data: {},
  methods: {},
  router: routerObj // 将路由规则对象,注册到 vm 实例上,用来监听 URL 地址的变化,然后展示对应的组件
});
<div id="app">
<!-- router-link 默认渲染为一个a 标签,可以用tag修改-->
<router-link to="/login" tag="span">登录</router-link>
<router-link to="/register">注册</router-link>

<!-- 在外面包一层transition实现动画效果 -->
<transition mode="out-in">
	<!-- 这是 vue-router 提供的元素,专门用来 当作占位符的,将来,路由规则,匹配到的组件,就会展示到这个 router-view 中去,所以我们可以把 router-view 认为是一个占位符 -->
	<router-view></router-view>
</transition>
</div>

P79~P80:路由传参的两种方式

   <!-- 这种方式给路由传递参数,不需要修改路由规则的 path 属性,组件内部使用$route.query获取参数 -->
   <router-link to="/login?id=10&name=zs">登录</router-link>
    var login = {
      template: '<h1>登录 --- {{ $route.query.id }} --- {{ $route.query.name }}</h1>',
    }
    var router = new VueRouter({
      routes: [
        { path: '/login', component: login }
      ]
    })
   <!-- 这种方式给路由传递参数,不需要加参数名但参数名需要在path里面指定,组件内部使用$route.params获取参数 -->
   <router-link to="/login/10/zs">登录</router-link>
    var login = {
      template: '<h1>登录 --- {{ $route.params.id }} --- {{ $route.params.name }}</h1>',
    }
    var router = new VueRouter({
      routes: [
        { path: '/login/:id/:name', component: login }
      ]
    })

P81:路由嵌套

使用children实现路由嵌套

var router = new VueRouter({
  routes: [
    {
      path: '/account',
      component: account,
      // 使用 children 属性,实现子路由,同时,子路由的 path 前面,不要带 / ,否则永远以根路径开始请求,这样不方便我们用户去理解URL地址
      children: [
        { path: 'login', component: login },
        { path: 'register', component: register }
      ]
    }
  ]
})

P82:使用路由的命名视图实现布局

  <div id="app">
    <router-view></router-view>
    <div class="container">
      <router-view name="left"></router-view>
      <router-view name="main"></router-view>
    </div>
  </div>
<script>
var header = {
  template: '<h1 class="header">Header头部区域</h1>'
}
var leftBox = {
  template: '<h1 class="left">Left侧边栏区域</h1>'
}
var mainBox = {
  template: '<h1 class="main">mainBox主体区域</h1>'
}
// 创建路由对象
var router = new VueRouter({
	routes: [
	{
	  path: '/', components: {
		'default': header,
		'left': leftBox,
		'main': mainBox
	  }
	}]
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
  el: '#app',
  data: {},
  methods: {},
  router
});
</script>

Day5

P87:watch

用于监听数据或对象的改变

<div id="app">
    <input type="text" v-model="firstName"> +
    <input type="text" v-model="lastName"> =
    <span>{{fullName}}</span>
  </div>
  <script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        firstName: 'jack',
        lastName: 'chen',
        fullName: 'jack - chen'
      },
      methods: {},
      watch: {
        'firstName': function (newVal, oldVal) { // 第一个参数是新数据,第二个参数是旧数据
          this.fullName = newVal + ' - ' + this.lastName;
        },
      }
    });
  </script>

P89:computed

<div id="app">
<input type="text" v-model="firstname"> +
<input type="text" v-model="middlename"> +
<input type="text" v-model="lastname"> =
<input type="text" v-model="fullname">
<p>{{ fullname }}</p>
</div>
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
  el: '#app',
  data: {
	firstname: '',
	lastname: '',
	middlename: ''
  },
  methods: {},
  computed: { // 在 computed 中,可以定义一些 属性,这些属性,叫做 【计算属性】, 计算属性的,本质,就是 一个方法,只不过,我们在使用 这些计算属性的时候,是把 它们的 名称,直接当作 属性来使用的;并不会把 计算属性,当作方法去调用;

	// 注意1: 计算属性,在引用的时候,一定不要加 () 去调用,直接把它 当作 普通 属性去使用就好了;
	// 注意2: 只要 计算属性,这个 function 内部,所用到的 任何 data 中的数据发送了变化,就会 立即重新计算 这个 计算属性的值
	// 注意3: 计算属性的求值结果,会被缓存起来,方便下次直接使用; 如果 计算属性方法中,所以来的任何数据,都没有发生过变化,则,不会重新对 计算属性求值;
	'fullname': function () {
	  console.log('ok')
	  return this.firstname + '-' + this.middlename + '-' + this.lastname
	}
  }
});
</script>

P90:watch、computed和methods之间的对比

  1. computed属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用;
  2. methods方法表示一个具体的操作,主要书写业务逻辑;
  3. watch一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;可以看作是computedmethods的结合体;

组件间的传递方式:

props

  1. 在组件内声明所有的props
  • 方式一: 只指定名称
props: ['name', 'age', 'setName']
  • 方式二: 指定名称和类型
props: {
	name: String,
	age: Number,
	setNmae: Function
}
  • 方式三: 指定名称/类型/必要性/默认值
props: {
	name: {type: String, required: true, default:xxx},
}
  1. 使用组件标签时声明
<my-component :name='tom' :age='3' :set-name='setName'></my-component>
  1. 注意
  • 此方式用于父组件向子组件传递数据
  • 所有标签属性都会成为组件对象的属性, 模板页面可以直接引用
  • 问题:
    a. 如果需要向非子后代传递数据必须多层逐层传递
    b. 兄弟组件间也不能直接props 通信, 必须借助父组件才可以

自定义事件

  1. 绑定事件监听
  • 方式一: 通过v-on 绑定
@delete_todo="deleteTodo"
  • 方式二: 通过$on()
this.$refs.xxx.$on('delete_todo', function (todo) {
	this.deleteTodo(todo)
})

2.触发事件

// 触发事件(只能在父组件中接收)
this.$emit(eventName, data)

3.注意:

  • 此方式只用于子组件向父组件发送消息(数据)
  • 问题: 隔代组件或兄弟组件间通信此种方式不合适

订阅发布

  1. 引入pubsub
//终端安装
npm install --save pubsub-js

//js引入
import PubSub from ‘pubsub-js’
  1. 订阅消息
PubSub.subscribe('msg', function(msg, data){})
  1. 发布消息
PubSub.publish('msg', data)
  1. 注意
    优点: 此方式可实现任意关系组件间通信(数据)

slot

此方式用于父组件向子组件传递标签数据

  1. 子组件里定义
<template>
	<div>
		<slot name="xxx">不确定的标签结构1</slot>
		<div>组件确定的标签结构</div>
		<slot name="yyy">不确定的标签结构2</slot>
	</div>
</template>
  1. 父组件调用
<child><!--child自定义组件的标签-->
	<div slot="xxx">xxx 对应的标签结构</div>
	<div slot="yyy">yyyy 对应的标签结构</div>
</child>
  1. 注意
    使用slot后,所有属性方法可以写在父组件里。

vuex

vuex是对vue 应用中多个组件的共享状态进行集中式的管理(读/写)

store 对象

映射store

import store from './store'
new Vue({
	store
})
  1. 所有用vuex 管理的组件中都多了一个属性$store, 它就是一个store 对象
  2. 属性:
    state: 注册的state 对象
    getters: 注册的getters 对象
  3. 方法:
    dispatch(actionName, data): 分发调用action

store的属性

  1. state
    vuex 管理的状态对象,唯一的。
const state = {
	xxx: initValue
}
  1. mutations
  • 包含多个直接更新state 的方法(回调函数)的对象
  • 谁来触发: action 中的commit(‘mutation 名称’)
  • 只能包含同步的代码, 不能写异步代码
const mutations = {
	yyy (state, {data1}) {
	// 更新state 的某个属性,data1是个对象
	}
}
  1. actions
  • 包含多个事件回调函数的对象
  • 通过执行: commit()来触发mutation 的调用, 间接更新state
  • 谁来触发: 组件中: $store.dispatch(‘action 名称’, data1) // ‘zzz’
  • 可以包含异步代码(定时器, ajax)
const actions = {
	zzz ({commit, state}, data1) {
		commit('yyy', {data1})
	}
}
  1. getters
  • 包含多个计算属性(get)的对象
  • 谁来读取: 组件中: $store.getters.xxx
const getters = {
	mmm (state) {
		return ...
	}
}
  1. modules
  • 包含多个module
  • 一个module 是一个store 的配置对象
  • 与一个组件(包含有共享数据)对应
  1. 向外暴露store 对象
export default new Vuex.Store({
	state,
	mutations,
	actions,
	getters
})
posted @ 2020-04-10 18:10  漂移青春  阅读(202)  评论(0编辑  收藏  举报