vue

作者: 萌妹撒 | 来源:发表于2018-11-19 10:50 被阅读0次

    vue(中心思想:替换app元素)

    vue脚手架

    image.png
    • 把vue-cli 安装到全局:npm install vue-cli -g或者yarn add vue-cli -g
      vue-cli:提供了一些vue的命令,用来初始化一个基于webpack的vue项目
    • 命令一:vue init webpack-simple vue-book(自定义的项目名称)
    • 命令二(一般用这个):vue init webpack vue-book(自定义的项目名称)
      • 问题:重新安装less、less-loader 、axios、boostrap
      • 如果用第三方插件需要use一下 譬如:
    //查找路径vue ---> package.json ---> main.js
    import Vue from 'vue'
    
    //第三方模块
    import VueAwesomeSwiper from 'vue-awesome-swiper';
    Vue.use(VueAwesomeSwiper);
    
    是一个MVVM框架,m-model  v-view  vm-view-model
    model:数据模型  view:视图  view-model:数据和视图之间数据的传递
    

    MVVM

    1. Mvvm定义MVVM是Model-View-ViewModel的简写。即模型-视图-视图模型。【模型】指的是后端传递的数据。【视图】指的是所看到的页面。【视图模型】mvvm模式的核心,它是连接view和model的桥梁。它有两个方向:一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定。总结:在MVVM的框架下视图和模型是不能直接通信的。它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信。
    2. MVC的定义:MVC是Model-View- Controller的简写。即模型-视图-控制器。M和V指的意思和MVVM中的M和V意思一样。C即Controller指的是页面业务逻辑。使用MVC的目的就是将M和V的代码分离。‘MVC是单向通信。也就是View跟Model,必须通过Controller来承上启下。MVC和MVVM的区别并不是VM完全取代了C,ViewModel存在目的在于抽离Controller中展示的业务逻辑,而不是替代Controller,其它视图操作业务等还是应该放在Controller中实现。也就是说MVVM实现的是业务逻辑组件的重用。由于mvc出现的时间比较早,前端并不那么成熟,很多业务逻辑也是在后端实现,所以前端并没有真正意义上的MVC模式。而我们今天再次提起MVC,是因为大前端的来到,出现了MVVM模式的框架,我们需要了解一下MVVM这种设计模式是如何一步步演变过来的。2. 为什么会有MVVM框架?在过去的10年中,我们已经把很多传统的服务端代码放到了浏览器中,这样就产生了成千上万行的javascript代码,它们连接了各式各样的HTML 和CSS文件,但缺乏正规的组织形式,这也就是为什么越来越多的开发者使用javascript框架。比如:angular、react、vue。浏览器的兼容性问题已经不再是前端的阻碍。前端的项目越来越大,项目的可维护性和扩展性、安全性等成了主要问题。当年为了解决浏览器兼容性问题,出现了很多类库,其中最典型的就是jquery。但是这类库没有实现对业务逻辑的分成,所以维护性和扩展性极差。综上两方面原因,才有了MVVM模式一类框架的出现。比如vue,通过数据的双向绑定,极大了提高了开发效率。3. MVVM框架:VUE的介绍Vue就是基于MVVM模式实现的一套框架,在vue中:Model:指的是js中的数据,如对象,数组等等。View:指的是页面视图viewModel:指的是vue实例化对象为什么说VUE是一个渐进式的javascript框架, 渐进式是什么意思?1.如果你已经有一个现成的服务端应用,你可以将vue 作为该应用的一部分嵌入其中,带来更加丰富的交互体验;2.如果你希望将更多业务逻辑放到前端来实现,那么VUE的核心库及其生态系统也可以满足你的各式需求(core+vuex+vue-route)。和其它前端框架一样,VUE允许你将一个网页分割成可复用的组件,每个组件都包含属于自己的HTML、CSS、JAVASCRIPT以用来渲染网页中相应的地方。3.如果我们构建一个大型的应用,在这一点上,我们可能需要将东西分割成为各自的组件和文件,vue有一个命令行工具,使快速初始化一个真实的工程变得非常简单(vue init webpack my-project)。我们可以使用VUE的单文件组件,它包含了各自的HTML、JAVASCRIPT以及带作用域的CSS或SCSS。以上这三个例子,是一步步递进的,也就是说对VUE的使用可大可小,它都会有相应的方式来整合到你的项目中。所以说它是一个渐进式的框架。VUE最独特的特性:响应式系统VUE是响应式的(reactive),也就是说当我们的数据变更时,VUE会帮你更新所有网页中用到它的地方。关于这个响应式原理,官方已经讲得很清楚,不懂的同学,可以去官网 查看。我们讲一下主流框架实现双向绑定(响应式)的做法:1. 脏值检查:angularangular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过 setInterval() 定时轮询检测数据变动,当然Google不会这么low,angular只有在指定的事件触发时进入脏值检测,大致如下: DOM事件,譬如用户输入文本,点击按钮等。( ng-click ) XHR响应事件 ( http ) 浏览器Location变更事件 (location ) Timer事件( timeout ,interval ) 执行 digest() 或apply()在 Angular 中组件是以树的形式组织起来的,相应地,检测器也是一棵树的形状。当一个异步事件发生时,脏检查会从根组件开始,自上而下对树上的所有子组件进行检查,这种检查方式的性能存在很大问题。2.观察者-订阅者(数据劫持):vueObserver 数据监听器,把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用Object.defineProperty()方法把这些属性全部转成setter、getter方法。当data中的某个属性被访问时,则会调用getter方法,当data中的属性被改变时,则会调用setter方法。Compile指令解析器,它的作用对每个元素节点的指令进行解析,替换模板数据,并绑定对应的更新函数,初始化相应的订阅。Watcher 订阅者,作为连接 Observer 和 Compile 的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数。Dep 消息订阅器,内部维护了一个数组,用来收集订阅者(Watcher),数据变动触发notify 函数,再调用订阅者的 update 方法。
      当执行 new Vue() 时,Vue 就进入了初始化阶段,一方面Vue 会遍历 data 选项中的属性,并用 Object.defineProperty 将它们转为 getter/setter,实现数据变化监听功能;另一方面,Vue 的指令编译器Compile 对元素节点的指令进行解析,初始化视图,并订阅Watcher 来更新视图, 此时Wather 会将自己添加到消息订阅器中(Dep),初始化完毕。当数据发生变化时,Observer 中的 setter 方法被触发,setter 会立即调用Dep.notify(),Dep 开始遍历所有的订阅者,并调用订阅者的 update 方法,订阅者收到通知后对视图进行相应的更新。因为VUE使用Object.defineProperty方法来做数据绑定,而这个方法又无法通过兼容性处理,所以Vue 不支持 IE8 以及更低版本浏览器。另外,查看vue原代码,发现在vue初始化实例时, 有一个proxy代理方法,它的作用就是遍历data中的属性,把它代理到vm的实例上,这也就是我们可以这样调用属性:vm.aaa等于vm.data.aaa。好了,关于mvvm设计模式及vue的双向绑定原理就讲到这。说实话,写这篇文章很费脑子,我们也参考了很多人的文章,可以说是总结的一个大杂烩。最近这两年Vue太火了,不懂VUE都不好意思说自己是干前端的,程序思维现在正着力把之前写的项目改造成vue的方式,目前已遇到了一堆坑,之后我们会把vue实战过程中的坑给大家总结一下,方便大家更好的学习。欢迎您继续关注程序思维。
      MVC:model view controller :数据单项通信,只能通过数据影响视图;
      MVVM:model(后端返回的数据)和view是不能直接进行通信的;需要通过view-model 来进行数据的传递;model-->view:绑定数据;model-->view:DOM的监听事件【发布订阅模式】
    • 数据是响应式的,当数据发生变化,会自动影响视图,当视图数据发生变化,会影响数据---> 数据的双向绑定
    • vue中常见的指令
      v-model:一般用于表单元素,体现双向绑定,单选框用于一组和name作用一样,具有互斥的作用,多选框(1个)false或者true,多个多选框v-model放的是数据,也需要有value值;在使用下拉框时,如果select有multiple;那么v-model绑定的值最好是一个数组类型
      如果v-model绑定的值不是一个数组类型的,那么浏览器解析吧其换成布尔类型;同时选中,同时不被选中;所以需要给每个input加上value属性值进行区分
      v-text:把数据绑定DOM元素中,具有响应式;并且会把之前的进行覆盖
      v-html:可以识别标签
      v-for:要循环谁,把v-for放在谁身上;
      v-once:事件、一次
      v-if、 v-else::当属性值是true,则显示当前的元素;为false,那么显示v-else的元素,控制的是DOM元素的存在,不是控制display:none
      v-else-if:
      v-once:页面指挥绑定一次,视图和数据不在有任何的关联,放在小胡子里面
      v-cloak:元素加在数据比较多,vue解析事件比较长;为了防止{{}}出现,给该元素加上v-cloak属性,直到vue中吧DOM数据插入到真实DOM中时,当前元素显示;在css中加样式[v-cloak]{display:none};直接用v-text也可以
      v-show:控制元素的显示隐藏;通过控制css的display属性;频繁操作dom元素
      v-bind:用于绑定动态的属性,最后简写成一个:就可以取到动态的属性
      v-:自定义属性;v-开头的属性值是变量;不是字符串
      v-on: <div @click="fn($event,1)" >{{msg}} < /div>
    • 如果在绑定时,fn不带(),那么函数会默认接收一个事件对象e;mouseEvent,
    • 如果绑定时,带有(),那么不会默认接收事件对象,
    • 既需要事件对象,又需要参数,需要在绑定参数加一个($event),后面的参数才是真正的实参
      input 单选input type=‘redio’;v-model=‘b’;value=‘内容’ onchange:当input的value发生改变时,就会触发这个change事件;在input由于值发生变化,单只触发的事件一般都用change事件 onclick:点击的时候,立即执行这个行为绑定的方法
      @blur="cancel" v-focus

    小胡子语法:{{}}不仅仅可以取值,还可以放运算表达式
    在小胡子语法中遇到null,遇到undefined是没显示任何内容的

    • 事件修饰符;@click.prevent="fn"
      .prevent:阻止事件的默认行为
      .stop:阻止事件的冒泡行为
      .capture:事件行为在捕获
      .once:只执行一次
      .self:只有自己触发自己时,自己的事件行为才会执行
    • 键盘事件的修饰符:@keydown.enter="fn". .数字或者.字母也可以
      .enter:回车键
      .esc:退出
      .delete:退格
      .space:空格
      .tab:tab键
      .left/.right./.up/.down 上下左右
    • data中数据最终会放在vue的实例上
    • vue 会遍历data中的所有的属性,通过Object.defineProperty把所有的属性转换成get和set方法
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <input type="text" id="box">
    <script>
        let obj = {};
        // 第三方变量;为了防止获取obj.name 时出现无限循环;
        let temp = {};
        // 让对象中的值发生变化,那么input内容也跟着变化,当input框中值发生改变,对象的值也跟着变化;name;
        Object.defineProperty(obj,"name",{
            get(){
                return temp.name;// get 的返回值就是obj.name 的获取值;
            },
            set(val){
                temp.name = val;
                box.value = val;
            }
        });
        // VUE利用DOM事件监听机制;
        // 视图 影响数据;
        box.addEventListener("input",function () {
            obj.name = this.value;// 把input框的值赋值给obj.name属性;
        })
    
    </script>
    </body>
    </html>
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="keywords" content=""/>
        <meta name="description" content=""/>
        <title>珠峰培训</title>
        <link rel="icon" href=""/>
        <link rel="stylesheet" href="">
    </head>
    <body>
    <script src="node_modules/vue/dist/vue.js"></script>
    <div id="app">
        {{a.school}}
    </div>
    <script>
        let vm = new Vue({
            el:'#app',
            data:{
                a:{},
            }
        });
        //vm.a.school = 'zfpx',新增的属性不会有响应式,但是如果原先有这个属性可以监听
        //1、直接覆盖原有的空间地址;新的地址进行替换;属性都有响应式
        vm.a = {school:'zfpx'};
    
        //2、vm.$set()  设置data对象的属性
       console.log(vm);
        vm.$set(vm.a,'school','珠峰00')
    </script>
    </body>
    </html>
    
     let vm = new Vue({
            el:'#app',
            data:{
                arr:[1,2,3,4,5,6]
            }
        });
        //1、通过索引不可以修改data中数组的某一项
        //2、通过改变数组的length,也不能实现响应式
        //3、通过原型上的方法,可以对数组实现修改;
        //4、数组的方法中,原有数组发生改变:pop、push、shift、unshift、splice、sort、reverse,另一个方法可以给vm.arr重新赋值
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">
        <ul>
            <!--v-for : Array  -->
            <!--v-for : Object-->
            <!--v-for : number -->
            <!--v-for : string -->
            <!--要循环谁,就把v-for放在谁在身上-->
            <!--(a,index) in  arr : a 代表是数组的每一项,index代表索引-->
            <!--<li v-for="(a,index) in arr">{{a}}{{index}}</li>-->
            <!--<li v-for="a in num">{{a}}</li>-->
            <!--<li v-for="a in  str">{{a}}</li>-->
            <!--在循环对象中,如果只有一个值,那么得到是属性值;第二个参数代表是属性名,第三个代表的是索引-->
            <!--<li v-for="(a,b,index) in  obj">{{a}}{{b}}{{index}}</li>-->
            <li v-for="a in arr">
                <ul>
                    <li v-for="b in a">{{b}}</li>
                </ul>
            </li>
        </ul>
    </div>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
        let vm = new Vue({
            el:"#app",
            data:{
                arr:[[1,2,3],[4,5,6],[7,8,9]],
                num:5,
                str:"zfpx",
                obj:{name:"12",age:"34",sex:"56"}
            }
        });
    </script>
    </body>
    </html>
    

    data的属性和methods中的属性不能重名
    data的属性和fillter中的属性能重名
    methods的属性和fillter中的属性能重名
    computed中的属性不能和data或者methods中的属性名重名
    watch都可以重名

    let vm = new Vue({
    el:'#app',绑定
    data:{},数据
    methods:{},方法
    created(){},一开始就执行,
    computed:{},传一个对象,对象中有get和set方法;传一个方法,默认走get,计算属性
    watch:{},监听数据
    template:'',
    filters:{},过滤器,方法中有两个参,第一个参数是前面这个元素,第二个参数是传进来的
    directives:{},自定义方法,自动执行,函数的名字和自定义的名字必须一致;自定义方法第一个参数是此元素,第二个参数是个对象,对象中value值是我们需要的
    })

    computed

    computed :计算的属性会缓存
    checkAll:这个属性的属性值是由下面两个input的v-model计算的来的;当下面有一个是false,checkAll就是false,两个都是true,结果是true;
    在computed中的,属性都有一个get和一个sat方法;当获取checkAll时,会执行get方法,那么checkAll是get方法的返回值
    computed中的属性都会被vue实例所代理,最终放在实例的属性中

    computed中的属性不能和data或者methods中的属性名重名
    computed属性还可以是一个函数,那么函数执行会默认调用get方法,那么sum函数执行的返回值就是sum这个属性的属性值
    computed不支持异步的方法,watch可以支持异步的方法

    computed的数据不需要再data有,但是watch数据必须存在于data中
    如果一个属性依赖于其他属性计算而来,那么这个属性最好用computed;因为computed计算的属性会缓存

    • computed:
      1、支持缓存,只有依赖数据发生改变,才会重新进行计算

    2、不支持异步
    3、如果一个属性是由其他属性计算而来的,这个属性依赖于其他属性,是多对一;一般用computed;
    4、如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;

    • watch
      1、不支持缓存,数据变,直接会触发响应的操作
      2、watch支持异步
      3、当一个属性发生变化是,需要执行对应的操作;一对多
     computed:{
                // computed :计算的属性会缓存
                //checkAll:这个属性的属性值是由下面两个input的v-model计算的来的;当下面有一个是false,checkAll就是false,两个都是true,结果是true;
                //在computed中的,属性都有一个get和一个sat方法;当获取checkAll时,会执行get方法,那么checkAll是get方法的返回值
                //computed中的属性都会被vue实例所代理,最终放在实例的属性中
                //computed中的属性不能和data或者methods中的属性名重名
                checkAll:{
                    get(){
                        return this.products.every(item => item.isSelected)
                        //checkAll 会依赖item的isSelected属性执行get方法;由于item发生改变,所以会再次触发get方法;先执行set再执行get,如果return 固定值,不会再执行get方法
                        //computed属性会被缓存,触发当依赖的属性(别人的某个属性可以影响自己的属性)发生改变时,会调用get方法,在页面中需要获取这个值(dom元素必须存在)
                    },
                   set(val) {
                        this.products.forEach(item => item.isSelected = val)
                        //会把当前的值value传给set的参数;true/false
                    }
                }
            },
    
    //<td colspan="6">总价格:{{sum | toFixed(2)}}</td>
    sum(){
                    //计算出所有选中商品的总价
                    return this.products.reduce((prev,next)=>{
                        //如果当前的商品是false,不需要进行求和计算;但是需要把以前进行求和结果传给下一次的计算求和
                        if(!next.isSelected) {return prev}
                        return prev + next.productPrice * next.productCount
                    },0);
                }
    

    watch

      watch:{
                a(newVal,oldVal){
                    // 监听a属性,当a属性发生变化,会这行这个函数;
                    // watch会把最新的值和上一次的值传给这个函数;第一个接收新的数值,第二个接收上一次的值;
                    //console.log(newVal);
                    //console.log(oldVal);
                    setTimeout(()=>{
                        this.msg = "";
                        if(newVal.length>5){
                            this.msg = "太长了"
                        }
                        if(newVal.length<3){
                            this.msg = "太短了";
                        }
                    },2000);
    
                    // 在工作中,能用computed,就不要用watch;
                }
            }
    
        })
        // 1. MVVM模式
        // 2.vue双向数据绑定原理
        // 3.vue的声明周期
        // 4.vue 中computed和watch有什么区别;
        // 5.用过VUEX吗;
    

    transition-group

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="node_modules/animate.css/animate.css">
    </head>
    <body>
    <div id="app">
        <input type="text" v-model="a">
        <!--解析出一个span标签-->
        <transition-group enter-active-class="animated bounceInUp" leave-active-class="animated bounceOutDown">
    
            <!--transition-group :子元素会进行复用;应该给每一个元素加一个标识;区分是不同的元素;元素就不再进行复用-->
            <!--key 最好不要相同-->
            <div v-for="(val,index) in  newArr" :key="index">{{val}}</div>
        </transition-group>
    </div>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
        let vm = new Vue({
            el:"#app",
            data:{
                a:"",
                query:[1,2,3,4,5],// 存储值;
            },
            computed:{
                // newArr: 是根据input中的输入值发生变化;根据input输入的内容;得出一个最新的数组;
                newArr(){
                    return this.query.filter(item=>item==this.a);
                }
            }
    
        })
    </script>
    </body>
    </html>
    
    • v-bind的class
      class中传一个对象,譬如class='a',v-bind:class{x:true,y:false},
    • 1、如果class名字相同,不会互相影响;如果样式相同,后面的会把前面的覆盖
      class中传一个对象,譬如class='a',v-bind:class{x:100,y:false},
    • 2、如果动态的class这个对象中,class的对象的属性名的属性值如果不是布尔值,默认转成布尔;如果是true,当前class生效;如果false,那么class不生效
      class中传一个对象,譬如class='a',v-bind:class{a:class1,y:false}['a']
    • 3、可以通过对象获取属性名对应的属性值
      class中传一个数组,譬如class='a',v-bind:class[class1,class2]、v-bind:class[class1,class2][0]

    • v-bind的style
     v-bind:style;动态绑定样式,属性值可以是一个对象,或者是一个数组;如果是对象,里面可以存储具体的样式,如果是数组,数组中的数据应该是从data中或者computed中拿到的
     v-bind:style='{width:'100px'}'
     v-bind:style=[bg1,bg2]
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="keywords" content=""/>
        <meta name="description" content=""/>
        <title>珠峰培训</title>
        <link rel="icon" href=""/>
        <link rel="stylesheet" href="">
        <style>
            #app div {
                width: 100px;
                height: 100px;
                background: pink;
                position: absolute;
            }
    
            #app div:nth-child(2) {
                top: 200px;
            }
        </style>
    </head>
    <body>
    <div id="app">
        <div v-drag>1</div>
        <div v-drag>2</div>
    </div>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
        let vm = new Vue({
            el: '#app',
            directives: {
                //这里面存储的都是自定义的指令
                drag(el) {
                    //drag:第一个参数就是拖拽这个元素
                    el.onmousedown = function (e) {
                        let disX = e.pageX - this.offsetLeft;
                        let disY = e.pageY - this.offsetTop;
                        document.onmousemove = function (e) {
                            el.style.left = e.pageX - disX + 'px';
                            el.style.top = e.pageY - disY + 'px';
                        };
                        document.onmouseup = function () {
                            document.onmousemove=document.onmouseup = null
                        }
                    }
                }
            }
        })
    </script>
    </body>
    </html>
    
    
    //生命周期;
        // vue的实例具有生命周期;vue实例在生成时,会经历一系列的初始化过程;数据的监听,编译模板,实例挂载DOM元素,或者数据更新DOM更新;在执行的过程中,会运行一些叫做生命周期的钩子函数;在vue实例生命周期中的特定的时间点内,执行的函数;
    
        // 生命周期钩子函数,不能控制其执行的顺序;
    ![lifecycle.jpg](https://img.haomeiwen.com/i14091103/7e015813ac1d29e3.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    - this就是vm或者别的实例的名字
    > - vue 中提供一个行间属性: ref;
    > - this.$refs : 获取到所有的元素带有行间属性ref的属性;同名字的会覆盖除非是for循环出来的
    > - this.$set :
    > - this.$mount : 挂载 `vue实例中没有指定元素` 在实例外面,
    > - this.$el : 挂载的元素;
    > - this.$data:
    > - this.$options
    > - this.$nextTick,传一个回调函数,回调函数会等待DOM异步渲染完成执行,在异步之前
    > - this.$emit : 发布 ,在methods里面
                   >  -   $emit存在于每一个vue的实例上;
                   >  -   需要和DOM行间的的属性是保持一致;
    > - this.$on: 订阅
    ###template (template:"")
    - 1.template的属性值会把外层div给替换掉;
    - 2.template 只支持一个子元素;组件模板中只能由一个根元素;如果有多个元素,需要在外面加一个元素包裹起来;
    - 3.两个不同的写法;
            template:"#divs" 或者  template:" < div>< div>< /div>< /div> ",
    ####slot
    ```javascript
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">
        <model>
    
            <div slot="aaa">122</div>
            <div slot="bbb">223</div>
        </model>
    </div>
    <template id="add">
    <div>
    <!--<slot name="a"></slot>
    <slot name="b"></slot>
    <slot></slot>
    <slot></slot>
    <slot></slot>
    <slot></slot>-->
        <slot name="bbb"></slot>
        <slot name="aaa"></slot>
        <div>我的使命</div>
    </div>
    </template>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
    let model={
        template:'#add'
    };
        let vm=new Vue({
            el:'#app',
            data:{},
            components:{
                model
            }
        })
    </script>
    </body>
    </html>
    

    组件

    全局组件(Vue.componen 创建+注册)

    组件: 把页面中公共部分提炼出来,可以进行复用;Vue.componen是一个函数,传两个参数,第一个参数是名字,第二个参数是一个对象,对象里面有个data是个函数return一个对象,要不然报错

    每个组件都是一个vue的实例;那么具有生命周期;并且也有data ,computed,methods ,watch这些属性;

    • 1.组件的名字,在JS中可以带有-;还可以驼峰的命名;
    • 2.在HTML中进行引用时,支持-;但是不支持驼峰;
    • 3.Vue.component 是全局注册组件,在其他各个vue的实例中,可以使用;
      注意顺序

    局部组件(平行组件和嵌套性组件)

    局部组件使用三部曲 :

    • 1.创建组件;
    • 2.注册组件
    • 3.使用组件;
    嵌套性组件
    • 1、必须从内部往外部写,要不然找不到
    • 2、最里面的组件有template,但是没有components,其他都有,并且components使用的是(内组件 + 本组件的数据)
    • 3、最大的注册一下

    动态组件

    <div id="app">
        <input type="radio" v-model="title" value="home">home
        <input type="radio" v-model="title" value="list">list
        <!-- 在使用component这个自定义组件时,需要配合:is这个属性,动态绑定一个组件的名称;-->
        <!--is后面的属性值是哪个组件的名称,显示哪个组件;不可以同时显示两个-->
        <keep-alive>
            <component v-bind:is="title"></component>
        </keep-alive>
    
        <!--<component is="home"></component>-->
    
    </div>
    <script src="../0905(zujian)/node_modules/vue/dist/vue.js"></script>
    <script>
        // 创建组件
        // 动态组件进行切换时,会将上一个组件进行销毁,然后再挂载最新的组件;
        //keep-alive: 保存了组件第一次生成时的状态;以后需要该组件,直接读取缓存中的组件就可以;不再执行挂载,销毁;从而提高了浏览器的性能;
        let home  = {
            template:"<div>home</div>",
            mounted(){
                console.log("挂载home")
            },
            destroyed(){
                console.log("已销毁home")
            }
        };
        let list  = {
            template:"<div>list</div>",
            mounted(){
                console.log("挂载list")
            },
            destroyed(){
                console.log("已销毁list")
            }
        };
        let vm = new Vue({
            el: '#app',
            data: {
                title:"home",
    
            },
            // 注册组件
            components:{
                home,list
            }
        });
    </script>
    

    keep-alive

    keep-alive标签数据走缓存不刷新

    数据传递问题 (数组是单向的)

    • 1.把父组件中的数组绑定子组件中的一个行间属性;并且是动态绑定的这个属性;
    • 2.利用子组件中的props,去接收一下这个行间的属性;
    • 3.在子组件template中进行使用;
    • 4.数据被私有化,改变的话上级也变

    父传子

    <div id="app">
        <son :m="msg"></son>
    </div>
    
     let son = {
            // 在子组件中,data  computed  watch  methods 这些属性都有;子组件就是一个vue的实例;
            data(){
                return {
                    val:100//没用
                }
            },
            // props
            props:["m"],
            template:"<div>{{m}}</div>"
        };
        
        let vm = new Vue({
            el:"#app",
            data: {
                msg:"hello"
            },
            components:{
                son
            }
    
        });
    

    子传父

    如果需要当触发子组件上的操作改变父组件上的数据时,需要在父组件定义方法,改变自己的值;在父组件中定义的方法,需要订阅到子组件的自定义事件上;当触发子组件中的某个操作时,通过$emit 去触发这个自定义的事件;让其对应的父组件的方法执行;

    <div id="app">
        父亲: {{money}}
        <child :a="money"  @changem = "change"></child>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
    
        // 子传父: 如果需要当触发子组件上的操作改变父组件上的数据时,需要在父组件定义方法,改变自己的值;在父组件中定义的方法,需要订阅到子组件的自定义事件上;当触发子组件中的某个操作时,通过$emit 去触发这个自定义的事件;让其对应的父组件的方法执行;
        let vm = new Vue({
            el: '#app',
            data: {
                money:400
            },
            methods:{
                change(val){
                    console.log(1);
                    this.money = val;
                }
            },
            components:{
                child:{
                    data(){
                        return {};
                    },
                    props:["a"],
                    template:"<div>儿子:{{a}}<button @click='fn'>多要钱</button></div>",
                    methods:{
                        fn(){
                            // $emit存在于每一个vue的实例上;
                            // 需要和DOM行间的的属性是保持一致;
                            this.$emit("changem",800)
                        }
                    }
    
                }
            }
        });
    </script>
    

    事件车

    <div id="app">
       <brother1></brother1>
       <brother2></brother2>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
        // 每一个vue的实例都是独立的;相互之间不能直接进行改变数据;
        // 给两个不同的组件找一个载体;把共同的方法放在这个载体上;
        let eventBus = new  Vue;// 创建一个新的vue实例;
        // 在这个新的实例上,有$on: 订阅  $emit: 发布;
        let brother1  ={
            data(){
                return {
                    color:"绿色"
                }
            },
            created(){
                // $on  : param1 : 自定义事件名称, param2 :方法名称;
                eventBus.$on('changeG',this.green);
            },
            methods:{
                changeGreen(){
                    eventBus.$emit("changeR")
                },
                green(){
                    this.color="红色"
                }
            },
            // 变绿改变兄弟的数据;
            template:"<div>{{color}}<button @click='changeGreen'>变绿</button></div>"
        };
        let brother2  ={
            data(){
                return {
                    color:"红色"
                }
            },
            created(){
                // 给事件车订阅方法;
                eventBus.$on('changeR',this.changeRed);
            },
            methods:{
                changeRed(){
                   this.color="绿色";
                },
                red(){
                    eventBus.$emit("changeG")
                }
            },
            template:"<div>{{color}}<button @click='red'>变红</button></div>"
        }
        let vm = new Vue({
            el: '#app',
            data: {},
            components:{
                brother1,brother2
            }
        });
    
    </script>
    

    props

    <div id="app">
       <child :m="msg"></child>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
        let vm = new Vue({
            el: '#app',
            data: {
                msg:100
            },
            components:{
                child:{
                    data(){
                        return {}
                    },
                    // props  : 不仅可以传数组,还可以传对象;
                    props:{
                        // 单个类型校验
                        //m:Number
                        //m:[Number,String,Object,Function]
                        m:{
                            type:Number,// 校验类型的;
                            required:true,// 必填项
                            //default:100,// 默认值;
                            validator(val){
                                //console.log(val);
                                // 会根据当前validator的返回值,向浏览器的控制台抛出警告;
                                /*if(val>100){
                                    return true;
                                }*/
                                return false;
                            }
                        }
                    },
                    template:"<div @click='fn'>{{m}}<div>",
                    methods:{
                        fn(){
                            console.log(typeof this.m);
                        }
                    }
                }
            }
        });
    

    路由

    • 1.创建组件
    • 2.配置路由映射表routes=[{path:'/路径',component:组件名字}]
    • 3.路由映射表放进VueRouter 进行注册;let router = new VueRouter({ routes});
    • 4.在vue的实例中使用
      在元素的自定义属性取属性值时,是取得当前父组件中的数据
    <body>
    <div id="app">
        <!--to 是一个router-link 必须一个属性-->
        <!--router-link 是一个自定义的标签-->
        <!--router-link 中行间属性tag;属性值是展示对应的标签;把route-link 解析成对应的标签-->
       <router-link to="home" tag="div">首页</router-link>
       <router-link to="list">列表页</router-link>
        <!--是一个标签,也全局一个组件-->
        <!--显示真实的对应的组件-->
        <router-view></router-view>
        <!--<router-view></router-view>-->
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script src="node_modules/vue-router/dist/vue-router.js"></script>
    <script>
        // 路由: node
        // 根据不同的路径,执行不同的内容;
        // 路由 : 切换组件;
        // vue-router : 实现页面的跳转;
        // 1.创建组件
        // 2.配置路由映射表
        // 3.路由映射表放进VueRouter 进行注册;
        // 4.在vue的实例中使用
        let  home = {
            template:"<div>首页</div>"
        };
        let list = {
            template:"<div>列表页</div>"
        };
        // routes ; 路由映射表
        //在routes中路径必须加上/;
        let  routes = [
            {path:"/home",component:home},
            {path:"/list",component:list}
        ];
        // vue-router : 提供一个构造函数
        let router = new VueRouter({
            // routes : 路由映射表;
            routes
        });
        let vm = new Vue({
            el: '#app',
            data: {},
            router
        });
    </script>
    </body>
    

    路由的参数

    <body>
    <div id="app">
        <!--:to : 编程式的路径;一定要加一个名字-->
        <!--在元素的自定义属性取属性值时,是取得当前父组件中的数据;-->
        <router-link :to="{name:'product',params:{id:flag,txt:'a'}}">商品1</router-link>
        <router-link to="/article/2/b">商品2</router-link>
        <router-link to="/article/3/c">商品3</router-link>
        <router-view></router-view>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script src="node_modules/vue-router/dist/vue-router.js"></script>
    <script>
        // $router : 上面放的都是一些方法
        // $route : 放了一些键值对
        let article ={
            data(){
               return {f:89}
            },
            created(){
                console.log(this.$route);
                console.log(this.$router);
                // $route.params :存储了当前路由的参数;
            },
            template:"<div>第{{$route.params.id}}篇文章</div>"
        };
        let routes = [
            {path:"/article/:id/:txt",component:article,name:'product'}
        ];
        let router = new  VueRouter({
            routes
        });
        let vm = new Vue({
            el: '#app',
            data: {
                flag:11
            },
            router
        });
    </script>
    </body>
    

    .vue文件可以把template直接放在对象中

    相关文章

      网友评论

          本文标题:vue

          本文链接:https://www.haomeiwen.com/subject/xssofqtx.html