• 重新系统学习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="100%;">
    

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

    <input type="text" style="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
    })
    
  • 相关阅读:
    [转]Spring Cloud在国内中小型公司能用起来吗?
    [转]关于maven pom.xml中dependency type 为pom的应用
    如何直接在github网站上更新你fork的repo?
    Eclipse在Tomcat环境下运行项目出现NoClassDefFoundError/ClassNotFoundException解决办法
    Jquery mobile 中在列表项上使用单选按钮
    QBus 关注并推送实时公交信息
    常用序列号
    SVN 使用锁实现独占式签出
    SQL速记
    利用交通在手数据为换乘添加关注
  • 原文地址:https://www.cnblogs.com/zt102545/p/13940215.html
Copyright © 2020-2023  润新知