vue2.0

 Vue是一套用于构建用户界面的渐进式JavaScript框架。

渐进式:Vue可以自底向上逐层的应用;

简单应用:只需要一个轻量小巧的核心库;

复杂应用:可以引入各式各样的Vue插件;

Vue特点:

1、采用组件化模式,提高复用率,更利于维护;

2、声明式编码,让编码人员无需直接操作DOM,提高效率;

Vue开发环境搭建:

安装上对应vue的扩展,在导入vue.js后,阻止弹出一个安装版本提示。

<script>
    Vue.config.productionTip = false;
</script>

Vue小案例——hello

小结:1、想让Vue工作,必须创建一个Vue实例,且要传入一个配置对象;

        2、root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法;

        3、root容器里的代码被称为:VUE模板(vue模板只能使用实例化的vue对象中的数据);

        4、Vue实例和容器是一一对应的;

        5、真是开发中只有一个Vue实例,并且会配合组件一起使用;

        6、{{***}}中的参数要写js表达式,且参数可以自动读取到data中所有属性;

        7、一旦data中的数据发生改变,则模板中的用刀该数据的地方会自动更新;

容器里边可以使用实例之外的参数属性,但是可以使用表达式;

1、表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方;

例如:a、a+b、demo(1)、x===y?'a':'b'

2、js语句

实例:1、if(){}

        2、for(){}

(注意:区分js表达式js代码

<body>
    <div id = "root">
        <h1>Hello,{{name}}<h1>
    </div>

    <script type = "text/javascript">
        Vue.config.productionTip = false; //阻止Vue在启动后产生提示;
        new Vue({
            el:'#root';  //指定当前Vue实例为哪个容器服务,值通常为css选择器字符串;
            data:{
                name:"尚硅谷";    //data中用于存储数据,数据el所指定的容器去使用
            }
        })
    </script>
</body>

一个容器里边只能对应一个实例的参数:一对一关系;

<body>
    <div id = "root1">
        <h1>hello,{{name}},{{address}}</h1>
    </div>
    <div id = "root2">
        <h1>hello,{{name}},{{address}}</h1>
    </div>
    <script type = 'text/javascript'>
        Vue.config.productionTip = false;
        new Vue({
            el:'#root1',
            data:{
                name:'姓名',
                address:'地址';
                }
            })
        new Vue({
            el:'#root2';
            data:{
                name:'尚硅谷',
                address:'地址';
            }
        })
    </script>
</body>

Vue模板语法

指令语法:

v-bind:"v-"(Vue的特有的指令方式),为绑定的意思,这个指定可以简化为:" "

小结:

1、差值语法:

功能:用于解析标签体内容;

 写法:{{***}}是js表达式,且可以直接读取到data中的所有属性;

2、指令语法:

功能:用于解析标签(包括:标签属性、标签内容、绑定事件...)

举例:v-bind:href='***'或简写为 :href='***' ,***同样要写js表达式,且可以直接读取到data中的所有属性。

备注:Vue中很多指定,形式都是以:v-???

<body>
    <div id = "root">
        <h1>差值语法</h1>
        <h3>你好,{{name}}</h3> //读取是jack
        <hr/>
        <h1>指令语法</h1>
        <a v-bind:href="school.url.toUpperCase()">学习vue框架,名字{{school.name}}</a>   //输出的是“尚硅谷”
    </div>
</body>
    <script>
        Vue.config.productionTip = false; //阻止vue启动时弹出的生产提示
        new Vue({
            el:'#root',
            data:{
                name:'jack', 
                school:{
                    name:'尚硅谷',
                    url:'http://www.baidu.com',
                }
            }
        })
    </script>

执行结果是:

 Vue——数据绑定

Vue中有2种数据绑定方式:

        1、单向绑定(v-bind):数据只能从data流向页面;

        2、双向绑定(v-model):数据不仅可以从data流向页面,还可以从页面流向data;

                备注:

                        (1)双向绑定一般都应用在表单元素上(如:input,select等);

                        (2)v-model:value 可以简写为v-model,因此v-model默认收集的就是value值;

<body>
    <div id="root">
        单向数据绑定:<input type = 'text' v-bind:value='name'><br/>
        双向数据绑定:<input type = 'text' v-model:value='name'><br/>
    </div>
</body>
<script type='text/javascript'>
    Vue.config.productionTip=false;
    new Vue({
        el:'#root',
        data:{
            name:'尚硅谷'    
        }
    })
</script>

 简写:

<body>
    <div id="root">
    单向数据绑定:<input type = 'text' :value='name'><br/>
    双向数据绑定:<input type = 'text' v-model='name'><br/>
    </div>
</body>

el 和 data 的两种写法:

一、el的两种写法:

(1)、el:"#root";

(2)、v.$mount("#root");

<body>
    <div id="root">
        单向数据绑定:<input type = 'text' v-bind:value='name'><br/>
        双向数据绑定:<input type = 'text' v-model:value='name'><br/>
    </div>
</body>
<script type='text/javascript'>
    Vue.config.productionTip=false;
    const v = new Vue({
      //  el:'#root',第一种写法
        data:{
            name:'尚硅谷'    
        }
    })
    ocnsole.log(v);
    v.$mount("#root");   //第二种写法
</script>

二、data的两种写法

data的第一种写法:对象式

<body>
    <div id="root">
        单向数据绑定:<input type = 'text' v-bind:value='name'><br/>
        双向数据绑定:<input type = 'text' v-model:value='name'><br/>
    </div>
</body>
<script type='text/javascript'>
    Vue.config.productionTip=false;
    new Vue({
        el:'#root',
        data:{
            name:'尚硅谷',
            age:'20'
        }
    })
</script>

第二种写法:函数式

console.log(this);指向的是Vue对象;

<body>
    <div id="root">
        单向数据绑定:<input type = 'text' v-bind:value='name'><br/>
        双向数据绑定:<input type = 'text' v-model:value='name'><br/>
    </div>
</body>
<script type='text/javascript'>
    Vue.config.productionTip=false;
    new Vue({
        el:'#root',
        data:function(){
            return{
                name:'尚硅谷',
                age:'20'
            }
        }
    })
</script>

小结:

el有两种写法:

        1、new Vue时候配置el属性。(1)、el:"#root";

        2、先创建Vue实例,随后再通过"实例".$mount('#root')指定el的值。(2)、v.$mount("#root");

data的两种写法:

        1、对象式;

        2、函数式;

(学习组件时只能有函数式)

(注:Vue管理的函数,一定不能使用箭头函数,因为箭头函数this指向Window)

Vue——MVVM模型

1、M:模型(Model):对应data中的数据;

2、V:视图(View):模板;

3、VM:视图模型(ViewModel):Vue的实例对象;

 

Vue——数据代理

语法:Object.defineProperty(obj,prop,descriptor)

参数一:必须,目标对象;

参数二:必须,需要定义或修改的属性的名字;

参数三:必须,目标属性所拥有的特性——(1、这个属性用大括号括起来{};2、value设置属性的值,默认为underfined; 3、writetable是否可以重写(默认false); 4、enumerable目标属性是否可以被枚举(默认false); 5、configurable目标属性是否可以被删除或再次修改descriptor的这几个特性(默认false));

<body>
    <script>
        let number = 18;
        let person = {
            name:'姓名',
            sex:'性别',
        }
    Object.defineProperty(person,'age',{
        get:function(){
            console.log("有人读取数据");
            return number;
        },
        set:function(value){
            console.log("有人修改了age属性值为:",value);
            number = value;
        }
    })
    console.log(person );
    </script>
</body>

可以将get:function(){}set:function()进行简化:

<body>
    <script>
        let number = 18
        let person = {
            name:'张三',
            sex:'男',
        }
        Object.defineProperty(person,'age',{
            get(){
                console.log("有人读取了age属性");
                return number;
            },
            set(value){
                console.log("修改了age属性,值:",value);
                number = value;
            }
        })
    </script>
</body>

数据代理:示例通过一个对象代理对另一个对象中属性的操作(读/写)

<body>
    <script>
    let obj = {x:100};
    let obj2 = {y:200};
    Object.defineProperty('obj2','x',{
            get(){
                console.log("读取属性");
                return obj.x;
            }
            set(value){
                console.log("修改属性");
                obj.x = value;
            }
        })
    </script>
</body>

Vue中的数据代理

小结:

1、Vue中数据代理:通过vm对象来代理data对象中属性的操作(读/写);
2、Vue中数据代理的好处:更方便操作data中的数据;

3、基本原理:通过Object.defineProperty()把data对象中所有属性添加到vm上。为每一个添加到vm上的属性,都指定一个getter、setter。在getter、setter内部去操作(读/写)data中对应的属性。

<body>
    <div id="root">
        <h2>学校名称+{{name}}</h2>
        <h2>学校地址+{{address}}</h2>
    </div>
</body>
<script>
    Vue.config=productionTip=false;
    const vm =new Vue({
        el:'#root',
        data:{
            name:'尚硅谷',
            address:'科技园'
        }
    })
</script>

 Vue——事件处理

 小结:1、使用v-on:***@xxx绑定事件,其中xxx是事件名;

        2、事件的回调需要配置在methods对象中,最终会在vm中;

        3、methods中配置的函数,不要使用箭头函数!否则this就不指向vm了;

        4、methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象;

        5、@click=‘demo’ @click="demo($event)"效果一样,但后者可以传参;

(event:目标对象)

<body>
    <div id ='root'>
        <h2>欢迎来到{{name}}学习</h2>
       <button v-on:click='showInfo'>点击提示信息</button>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip= false; //阻止Vue弹出生成提示;
    const vm = new Vue(
        el:"#root",
        data:{
            name:'尚硅谷'
        },
        methods:{
            showInfo(event){
                console.log(event);
                alert("同学你好");
            }
            showInfo(number,$event){
                console.log($event);
                console.log(number);
            }
        }
    )
</script>

Vue——事件修饰符

Vue中的事件修饰符:

1、prevent,阻止默认事件(preventDefault)

<body>
    <div id="root">
        <h2>欢迎来到{{name}}学习</h2>
        <a href="http://www.baidu.com" @click.prevent="showInfo">点击提示信息</a>
    </div>
</body>
<script>
    Vue.config.productionTip=false; //阻止提示vue生成提示
    new Vue(
        el:'#root',
        data:{
            name:'尚硅谷',
        },
        methods:{
             showInfo(e){
                //e.preventDefault();
                alert(同学你好);
            }   
         }
    )
</script>

2、stop,阻止事件冒泡;

<body>
    <div id='root'>
        <h2>欢迎来到{{name}}</h2>
        <div class='demo1' @click='showInfo'>
            <div class="demo2" @click.stop="showInfo">点击弹出信息</div>
        </div>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    new Vue(
        el:'#root',
        data:{
            name:"尚硅谷"
        }
        methods:{
            showInfo(){
                alert("弹出信息");
            }
       }
)
</script>

3、once,事件只触发一次;

<body>
    <div id="root">
        <h2></h2>
        <a href='http://www.baidu.com'@click.prevent='showInfo'>点击提示信息</a>
        <button @click.once='showInfo'>点击提示信息<>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    new Vue({
        el:'#root',
        data:{
            name:'尚硅谷',
        }
    })

</script>

4、capture,使用事件的描述模式;

再捕获阶段直接处理,先执行1,再执行2;

<body>
    <div id='root'>
         <div @click.capture='showInfo'>点击提示信息1
            <div @click=showInfo>点击提示信息2</div>    
        </div>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    new Vue({
        el:'#root',
        data:{
            name:'尚硅谷',
        }
    })
</script>

5、self,只有event.target是当前操作的元素时才触发事件;

6、passive:事件的默认行为立刻执行,无需等待事件回调执行完毕;

wheel为鼠标滚轮滚动事件;

scroll是滚动条滚动事件;

使用wheel时,若不使用passive命令则会等循环执行完后再滚动默认行为;使用后则会立刻执行,通知循环也执行。

<body>
    <ul @wheel.passive='demo' class='list'>
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </ul>
</body>
<script>
    Vue.config.productionTip=false;
    new Vue({
        el:'#root',
        data:{
            name:'尚硅谷'
        }
        methods:{
            demo(){
                for(let i =0;i<1000;i++){
                    console.log('#');
                }
                console.log('打印完了');
            }
        }
    })
</script>

Vue——键盘事件

1、Vue中常用的按键别名:

回车= >enter                                                                     上= >up

删除= >delete(捕获“删除”和“退格”)                           下= >down

退出= >esc                                                                        左= >left

换行= >tab (特殊,必须配合keydown去使用)        右= >right

2、Vue未提供别名的按键,可以使用按键原始的key值去绑定,但要注意把组合单词变为这种形式:caps-locks;

3、系统修饰键(用法特殊):ctrl、alt、shift、meta

        (1)需要配合keyup使用,按下修饰键的同时,再按下其他键,随后释放其他键,时间被触发;

         (2)配合keydown使用,正常触发事件。

4、也可以使用keyCode去指定具体按键(不推荐);

5、可以自定义按 键名:Vue.config.keyCodes.自动以键名=键码,可以去定制按键别名

<body>
   <div id='root'>
        <h2>欢迎来到{{name}}学习</h2>
       <input type='text'placeholder='按下回车提示输入'@keydown.enter='showInfo'>
   </div>
</body>
<script>
    Vue.config.productionTip=false;
    new Vue({
        el:'#root',
        data:{
            name:'尚硅谷',
        }
        methods:{
            showInfo(e){
                console.log(e.keyCode);
            }
        }
    })
</script>

 事件总结:

事件修饰符后边可以跟其他的修饰符:

<body>
    <div>
        <a href='http://www.baidu.com' @click.stop.prevent='showInfo'>点击提示信息</a>
    </div>
</body>

系统修饰键后边可以跟具体的键:

<body>
    <h2></h2>
    <input type="text" placeholder="按下回车提示输入" @keyup.ctrl.y="showInfo">
</body>

姓名案例:

只要data中数据发生变化就会重新执行,解析模板。

<body>
    <div id="root">
        姓:<input type="text" v-model="firstName"><br/>
        名:<input type="text" v-model="lastName"><br/>
        全称:<span>{{fullName()}}</span>  //加上括号在方法中表示调用方法的执行结果;在声明事件时,加不加括号都可以。
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    new vue({
        el:'#root',
        data:{
            firstName:'张',
            lastName:'三'
        },
        methods:{
            fullName(){   //普通函数在Vue中的this指向Vue实例
                return this.firstName+'-'+this.lastName;
            }
        }
    })
</script>

 Vue——计算属性(computed)

小结:

1、定义:要用的属性不存在,要通过已有的属性计算得出;

2、原理:底层借助了Object.defineproperty方法提供的getter和setter;

3、get函数什么时候执行?

        (1)初次读取时会执行一次;

        (2)当依赖的数据发生改变时会被再次调用;

4、优势:与methods相比,内部会有缓存机制(复用)效率高,调试方便;

5、备注:

        (1)计算属性最终会出现在vm上,直接读取使用即可;

        (2)如果计算属性要修改,那必须写set函数去相应修改,且set中要引起计算时依赖的数据的变化;

<body>
    <div id="root">
        姓:<input type="text" v-model="firstName"><br/>
        名:<input type="text" v-model="lastName"><br/>
        全名:<span>{{fullName}}</span>
        全名:<span>{{fullName}}</span>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm= new Vue({
        el:'#root',
        data:{
            firstName:'张',
            lastName:'三'
        },
        computed:{
                //通过计算得的数据给fullName
            fullName:{   
               //get作用:当获取了fullName时,get就会调用,且返回值作为fullName值;
               // get什么时候调用? 1.当初次调用fullName时;2、所依赖的数据发生变化时;
              get(){ 
                console.log("get被调用了");
                return this.firstName+'-'+this.lastName;
                },
              set(value){
                  console.log("set被调用");
                  const arr = value.split('-');    //通过split()方法分隔字符串
                  this.firstName = arr[0];
                  this.lastName= arr[1];
                }
            }
        }
    })
</script>

以上代码的获取数据的简写:(只读取不修改时才能使用)

把通过return返回的结果的值,交给fullName这个中。

<body>
    <div id="root">
        姓:<input type='text'v-model="firstName"><br/>
        名:<input type='text'v-model="lastName"><br/>
        全名:<span>{{fullName}}</span>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    new Vue({
        el:'#root',
        data:{
           firstName:'张',
           lastName:'三'
        },
        computed:{
            fullName(){      //相当于get方法
                console.log("调用函数")
                return this.firstName +'-'+ this.lastName
            }
        }
    })
</script>

天气案例:

<body>
    <div>
        <h2>今天天气很{{info}}</h2>
        <button @click="changeWeather">切换天气</button>  
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    conset vm= new Vue({
        el:'#root',
        data:{
            isHot:true,
        },
        computed:{
            info(){
                return this.isHot?'炎热':'凉爽';
            }
        },
        methods:{
            changeWeather(){
                this.isHot=!isHot;
            }
        }
    })

</script>

在vue模板中可以在事件类型后边写简单的语句:

<body>
    <div>
        <button @click='isHot=!isHot'></button>
    </div>
</body>

监视属性(watch):

 小结:1、当监视的属性发生变化时,回调函数自动调用,进行相关操作;

2、监视的属性必须存在,才能进行监视;

3、监视的两种写法:

        (1)new Vue 时传入watch配置;(在写代码时就确定监视哪个属性时使用)

         (2)通过Vue实例化的vm.$watch坚持;(没有提前知道要具体监视哪个属性时)

<body>
    <div>
        <h2>今天天气很{{info}}</h2>
        <button @click="changeWeather">切换天气</button>  
    </div>
</body>
<script type="text/javascript">
     Vue.config.productionTip=false;
     const vm = new Vue({
        el:'#root',
        data:{
            isHot:true,
        },
        computed:{
            info:{
                return isHot?'炎热':'凉爽';
            }
        },
        methods:{
            changeWeather(){
                this.isHot=!isHot;
            }
        }
知道具体监视那个属性时
        watch:{   //监视方法
            isHot:{     //创建对象并传递值;
                immediate:true,
                handler(newValue,oldValue){
                    console.log('isHot被修改了',newValue,oldValue);
                }
            }
        }
    })
-------------------------------------
不知道具体监视那个属性时可以使用这个
    vm.$watch('isHot',{  //创建配置对象
            immediate:true,            //初始化时就调用(默认为false)
            handler(newValue,oldValue){
            console.log('isHot被修改了',newValue,oldValue);
    })
</script>

深度监视:

        (1)Vue中的watch默认不监测对象内部值的改变(看一层)

        (2)配置deep:true可以监测对象内部值的改变(多层)

备注:

        (1)Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以(false);

        (2)使用watch时根据数据的具体结构,决定是否采用深度监视;

<body>
    <div id="root">
        <h3>a的值是{{a}}</h3>
        <button @click="numbers.a++">点击加一</button>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
            numbers:{
                a=1,
                b=1
            }
        },
        watch:{
        //监视多级结构中,某个属性的变化;
            "number.a":{ 
                handler(){
                console.log("a已经改变了");
                }
            }
             -------------------
            number:{
                deep:true,
                handler(){
                    console.log("内部有一个被改变了");
                }
            }
        }
    })
</script>

简写方式:

方式一:通过new Vue时

<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'root',
        data:{
            number:{
                a=1,
                b=1
            }
        },
        watch:{
            number(newValue,oldValue){
                console.log('number被修改了',newValue,oldValue);
            }
        }
    })
</script>

 方式二:通过实例化vm.$watch()方式

<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'root',
        data:{
            number:{
                a=1,
                b=2
            }
        },
    })
    vm.$watch('number',(newValue,oldValue)={
        console.log("number中的值被改变了",newValue,oldValue);
    })
</script>

computed和watch之间的区别:

        一、computed能完成的功能,watch都可以完成;

        二、watch能完成的功能,computed不一定能完成;(例如:定时器异步任务;)

两个重要的原则:

        (1)所以被Vue管理的函数,最好写成普通函数,这样this所指向的才是vm或组件实例对象;

        (2)所有不被vue管理的函数(定时器,Ajax回调函数,promise回调函数),最好使用箭头函数,这样可以使得this指向vm 实例或者组件实例。

姓名案例(computed写法):

<body>
    <div id='root'>
        姓:<input type='text' v-model="firstName"><br/>
        名:<input type='text' v-model="lastName"><br/>
        全名:<span>{{fullName}}</span>
    </div>
</body>
<script>
    Vue.config.productionTip =false;
    const vm = new Vue({
        el"#root",
        data:{
            firstName:'张',
            lastName:'三'
        },
        computed:{
            fullName(){
                console.log('get被调用了');
                return this.firstName + '-' + this.lastName;
            }
        }
    ])
</script>

例如姓名案例(watch写法):

<body>
    <div id='root'>
        姓:<input type='text' v-model="firstName"><br/>
        名:<input type='text' v-model="lastName"><br/>
        全名:<span>{{fullName}}</span>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm=new Vue({
        el:'#root',
        data:{
            firstName:'张',
            lastName:'三',
            fullName:'张-三'
        },
        watch:{
            firstName(fName){
                setTimeout(()=>{
                    console.log(this);   //此时函数为箭头函数,没有具体指向,往外边找,
                                        //外边为普通函数,所以指向Vm实例了
                    this.fullName=fName + '-' + this.lastName;
                },1000)
            },
            lastName(lname){
                this.fullName=this.firstName + '-' + lname;
            }
        }
    })

</script>

Vue——绑定class样式

 方式一字符串写法,适用于:样式的类名不确定,需要动态指定。

<body>
    <div id="root">
        <div class="basic" :class="mood" @click="changeMood">{{name}}</div>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip=false;
    new Vue({
        el:'#root',
        data:{
            name:'尚硅谷',
            mood:'normal' //动态指定样式为:normal
        },
        methods:{
            changeMood:{
                this.mood='happy';  //指定Vue对象,点击时切换样式为happy
            }
        }
--------------------------------------------------
        methods:{
            changeMod(){
                const arr = ['happy','sad','normal']
                const indes = Math.floor(Math.random()*3)
                this.mood= arr[indes]
            }
        }
    })
</script>

方式二 数组写法,适用于:要绑定的样式个数不确定,名字也不确定.

<body>
    <div id="root">
        <div class="basic" :class="classArr">{{name}}</div>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm= new Vue({
            el:'#root',
            data:{
                name:'尚硅谷',
                classArr:['atguigu1','atguigu2','atguigu3']  
            },   
    })
</script>

 方式三对象对法,适用于:要绑定的样式的个数确定,名字也确定,但要动态决定用不用。

<body>
    <div id="root">
        <div class="basic" :class="classObj">{{name}}</div>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'尚硅谷',
        data:{
            name:'',
            classObj:{      //定义一个对象,里边包含样式是否使用
                red:true,
                blue:false
            }
        }
    })
</script>

Vue样式——style绑定

(1)Style对象样式:

<body>
    <div id="root">
        <div class='basic' :style:'styleObj'>{{name}}</div>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    conse vm=new Vue({
        el:'#root',
        data:{
            styleOby:{
                fontSize:'50px',
                color:'red'
            }
        }
})
</script>

(2)style数组绑定样式

<body>
    <div id="root">
        <div class="basic" :style="styleArr">{{name}}</div>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm=new Vue({
        el:'#root',
        data:{
            name:'尚硅谷',
            styleArr:[
                {
                fontSize:'50px',
                color:'red'
                },
                {
                backgroundColor:'blue'
                }
            ]
        }
    })
</script>

Vue——添加样式小结:

 1、class样式:

        写法:class="***",***可以是字符串,数组和对象。

        字符串方式适用于:类名不确定,要动态获取;

        对象写法适用于:要绑定多个样式,名气不确定,个数也不确定;

        数组方式适用于:要绑定多个样式,名字确定,个数确定,但不确定是否使用;

2、style样式

        :style="{fontSize:***}",其中***是动态的;

        :style="[a,b]",其中a,b是样式对象; 

 Vue技术——渲染

一、使用v-show做条件渲染

      (1)为true时显示,为false时隐藏(在结构中不消失);

      (2)当表达式为true时显示,否则隐藏;

<body>
    <div id='root'>
        <h2 v-show='false'></h2>
        <h2 v-show="1===1"></h2>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm=new Vue({
        el:'#root',
        data:{
            name:'尚硅谷',
        }
    })
</script>

二、使用v-if做条件渲染

 此时v-if如果是假值则隐藏,且执行后结构中也看不到;

<body>
    <div id="root">
        <h2>当前值为:{{n}}</h2>
        <button @click="n++">点击加1</button>
        <div v-if='false'>隐藏,结构中也看不到</div>
        <div v-if="n===1">等于一时显示</div>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
            name:'尚硅谷'
        }
    })
</script>

三、使用v-if...,v-else-if....判断做渲染

这样判断样式,只执行其中符合的一个,成功后则退出;

<body>
    <div id="root">
        <h2>当前值为:{{n}}</h2>
        <button @click="n++">点击n加一</button>
        <div v-if="n===1">等于一显示</div>
        <div v-else-if="n===2">等于二时显示</div>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm= new Vue({
        el:'#root',
        data:{
            name:'尚硅谷'
        }
    })
</script>

 v-if...可以和template一起使用,可以让符合条件的执行语句并且不会影响结构。

<body>
    <div id="root">
        <h2>当前值为:{{n}}</h2>
        <button @click="n++">点击n加一</button>
        <div v-if="n===1">等于一显示</div>
        <template v-if="n===2">
            <h2>显示</h2>
            <h2>显示</h2>
        </template>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm= new Vue({
        el:'#root',
        data:{
            name:'尚硅谷'
        }
    })
</script>

条件渲染小结:

1、v-if...写法:

        (1)v-if="表达式"

        (2)v-else-if="表达式";

         (3)v-else="表达式"

适用于:切换频率比较低的场景。

特点:不展示的DOM元素直接移除;

注意:v-if  可以和 v-else-if 、v-else 一起使用,但必须中间不能有其他结构打断;

2、v-show写法:

        v-show="表达式";

  适用于:切换频率比较高的场景;

   特点:不展示的DOM元素仅仅是看不到;

3、注意:使用v-if 时候,元素可能无法获取;但是使用v-show一定可以获取;

Vue列表渲染

通过v-for遍历渲染数组

<body>
    <div id='root'>
        <ul>
            <li v-for="p in person" :key="p.id">    //当vue中使用v-for时,要使用唯一的标识                    
                                                  // key="p.id"
                {{p.name}}--{{p.age}}
            </li>
            ----------------------------
            //前边形参可以使用两个参数  ,第一个代表得到的数据,第二个是索引值
            <li v-for="(p,index) in persons" :key="p.id/index"> 
                {{p.value}}----{{p.index}}
            </li>
        </ul>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
            person:[
                {id:'01',name:'张三',age:20},
                {id:'02',name:'李四',age:18},
                {id:'03',name:'王五',age:25}
            ]
        }
    })
</script>

通过v-for遍历对象数据

"a"位置参数表示数据值,(key:value)中的value;

"b"位置参数表示数据键,(key:value)中的key;

<body>
    <div id="root">
        <h2>汽车信息</h2>
        <ul>
            <li v-for="(a,b)in car" :key="b">
                {{b}}--{{a}}
                    //输出结果为:name--红旗
                    //price--20
                    //color:黑色
            </li>
        </ul>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
            car:{
                name:'红旗',
                price:'20',
                color:'黑色'
            }
        }
    })
</script>

v-for遍历字符串

<body>
    <div id="root">
        <h2>汽车信息</h2>
        <ul>
            <li v-for="(char,index)in car" :key="index">
                {{char}}--{{index}}
                    //输出结果为:h--0,e--1这样的
            </li>
        </ul>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
            str:'hello'
        }
    })
</script>

v-for小结:

1、用于列表数据;

2、语法:v-for="(item,index) in ***" :key="某个唯一值"

3、可以遍历:数组,对象、字符串(少)、指定次数(很少);

 Vue——key作用与原理

一、当使用inde作为key时,或者不加key值时:

<body>
    <div id="root">
        <h2>人员编标遍历</h2>
        <button @click.once="add">添加一个信息</button>
        <ul>
            <li v-for="(p,index) of persons" :key="index">
                {{p.name}}--{{p.age}}
            </li>
            <li></li>
        </ul>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm= new Vue({
        el:'#root',
        data:{
            person:[
                {id:'001',name:'张三',age:20},
                {id:'002',name:'李四',age:18},
                {id:'003',name:'王五',age:25},
            ]
        },
        methods:{
            add(){
                const p = {id:'004','新信息',24}
                this.persons.unshift(p);
            }
        }
    })
</script>

执行结果为:

 执行的原理:

二、当遍历列表用id作为key时:

<body>
    <div id="root">
        <h2>人员编标遍历</h2>
        <button @click.once="add">添加一个信息</button>
        <ul>
            <li v-for="(p,index) of persons" :key="p.id">
                {{p.name}}--{{p.age}}
            </li>
            <li></li>
        </ul>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm= new Vue({
        el:'#root',
        data:{
            person:[
                {id:'001',name:'张三',age:20},
                {id:'002',name:'李四',age:18},
                {id:'003',name:'王五',age:25},
            ]
        },
        methods:{
            add(){
                const p = {id:'004','新信息',24}
                this.persons.unshift(p);
            }
        }
    })
</script>

执行结果为:

 执行原理为:

 key原理与作用小结:

(面试题:react、vue中key的作用,内部原理)

一、虚拟DOM中key的作用:

        key是虚拟DOM对象的表示,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的对比;

        比较规则:

        1、旧虚拟DOM中如果找到了与新虚拟DOM中相同的key:

                        (1)、若虚拟DOM中内容没变,直接使用之前的真是DOM;

                        (2)、若虚拟DOM中内容变了,则生成新的真实DOM,随后替换之前页面中的真 是DOM。

        2、旧虚拟DOM中未找到与新虚拟DOM相同的key:创建新的真实DOM,随后渲染到页面中。

二、用index作为key时:

        1、若对数据进行逆序添加、逆序删除等破坏顺序的操作:会产生没有必要的真实DOM更新===》界面效果没问题,但效率低;

        2、如果结构中包括输出类DOM,会产生错误的DOM更新===》界面有问题;

三、开发中的如果选择:

        1、最好使用每条数据中唯一的值作为唯一标识key,比如id,手机号等;

        2、如果不存在对数据进行逆序添加、删除等破坏顺序的操作,仅用于渲染列表用于展示,使用index(索引)作为key也可以。

Vue列表过滤

一、通过数据监视实现:

<body>
    <div id='root'>
        <h2>过滤列表</h2>
        <input type='text' placeholder="请输入信息" v-model="keyWords">
        <ul>
            <li v-for="(p,index)of filPerons" :key="index">
                {{p.name}}--{{p.age}}
            </li>
        </ul>
    </div>
</body>
<script type='text/javascript'>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
            keyWords:'',
            persons:[
             {id:'001',name:'冬天',age:18},
             {id:'002',name:'立冬',age:25},
             {id:'003',name:'立春',age:20}   
            ],
            filPerons:[]
        },
        watch:{    //监视完全写法
            keyWords:{
                immediate:true,
                handler(val){
                    this.filPerons = this.persons.filter((p)=>{
                        return p.name.indexOf(val) !==-1
                    })
                }
            }
        }
    })
</script>

二、通过数据计算:

<body>
    <div id='root'>
        <h2>过滤列表</h2>
        <input type='text' placeholder="请输入信息" v-model="keyWords">
        <ul>
            <li v-for="(p,index)of filPersons" :key="index">
                {{p.name}}--{{p.age}}
            </li>
        </ul>
    </div>
</body>
<script type='text/javascript'>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
            keyWords:'',
            persons:[
             {id:'001',name:'冬天',age:18},
             {id:'002',name:'立冬',age:25},
             {id:'003',name:'立春',age:20}   
            ]
        },
        computed:{
            filPersons(){
              return this.persons.filter((p)=>{
                    return p.name.indexOf(this.keyWords) !==-1
                }
            })
        }
    })
</script>

vue——列表排序:

arr.sort( (a,b) => {  });

数组排序,a-b为升序;b-a为降序;

<body>
    <div id='root'>
        <h2>过滤列表</h2>
        <input type='text' placeholder="请输入信息" v-model="keyWords">
        <button>年龄升序</button>
        <button>年龄降序</button>
        <button>原顺序</button>
        <ul>
            <li v-for="(p,index)of filPersons" :key="index">
                {{p.name}}--{{p.age}}
            </li>
        </ul>
    </div>
</body>
<script type='text/javascript'>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
            keyWords:'',
            sortType:0,  //0代表原顺序,1代表升序,2代表降序
            persons:[
             {id:'001',name:'冬天',age:18},
             {id:'002',name:'立冬',age:25},
             {id:'003',name:'立春',age:20}   
            ],
            filPerons:[]
        },
        computed:{
            filPersons(){
              const arr = this.persons.filter((p)=>{
                    return p.name.indexOf(this.keyWords) !==-1
                }
                if(this.sortType !== 0){
                    arr.sort((a,b)=>{
                        return this.sortType ===1 ? a.age - b.age : b.age-a.age
                    })
                }
                return arr;
            })
        }
    })
</script>

  

 Vue——检测数据

<body>
    <div id="root">
        <h2>学生信息</h2>
        <button @click='student.age++'>年龄加一</button>
        <button @click="addSex">添加性别属性。默认值:男</button>
        <button @click="student.sex='未知'">修改性别</button>
        <button @click="addFriend">在列表首位添加一个朋友</button>
        <button @click="updataFriend">修改第一个朋友的名字:张三</button>
        <button @click="addHobby">添加一个爱好</button>
        <button @click="updataHobby">修改第一个爱好者:开车</button>

        <h3>姓名:{{student.name}}</h3>
        <h3>年龄:{{student.age}}</h3>
        <h3 v-if:"student.sex">性别:{{student.sex}}</h3>
        <h3>爱好:{{student.hobby}}</h3>
        <ul>
            <li v-for="(h,index) in student.hobby" :key="index">{{h}}</li>
        </ul>
        <h3>朋友们:</h3>
        <ul>
            <li v-for="(f,index) in student.friends" :key="index">
                {{f.name}}--{{f.age}}
            </li>
        </ul>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    conse vm= new Vue({
        el:'#root',
        data:{
            student:{
                name:'tom',
                age:20,
                hobby:["游泳","看书","敲代码"],
                friends:[
                    {name:'jerry',age:18},
                    {name:'andi',age:20}
                ]
            }
        },
        methods:{
            addSex(){
                vue.set(this.student,'sex','男') //或者 vm.$set(this.student,'sex','女');
            },
            addFriend(){
                this.student.friends.unshift({name:'aaa',age:25})
            },
            updataFriend(){
                this.student.friends[0].name="jack";
                this.student.friends[0].age=16;
            },
            addHobby(){
                this.student.hobby.push('学习');
            },
            updataHobby(){
                this.sdudent.hobby.splice(0,1,"开车")
               ----------------------------------
                vue.set(this.student.hobby,0,"开车");
                -----------------------------------
                vm.$set(this.student.hobby,0,"开车");
            }
        }
    })

</script>

一、Vue会监视data中的所有层次的数据。

Vue检测数据的原理——对象

二、通过setter实现监视,且要在new.Vue时就传入要检测的数据:

        (1)对象中后追加的属性,Vue默认不做响应式处理;

        (2)如需要给后添加的属性做响应式,需要使用如下API:

Vue.set(target, properyName/index, value)
         目标       追加的属性        追加属性的值
或者:
vm.$set(target, propertyName/index, value);

 注意:Vue.set() 和 vm.$set() 不能修改vm 或者 vm的根数据对象添加属性!!

Vue检测数据的原理——数组

三、通过包裹数组更新元素的方法实现,本质就做了两件事:

        (1)调用原生对应的方法对数组进行更新;

        (2)重新解析模板,进而更新页面;

<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
            persons:[
            {id:'001',name:'张三',age:20,sex:'女'},
            {id:'002',name:'王五',age:22,sex:'男'},
            {id:'003',name:'李四',age:18,sex:'女'},
            ]
        },
        methods:{
            upda(){
                this.persons.splice(0,1,{id:'001',name:'学习',age:25,sex:'男'})
            }
        }
    })
</script>

 也可以这样使用:

 

在Vue修改数组中的某个元素一定要用到如下方法:

        (1)、使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、 reverse();

        (2)、Vue.set() 或者 vm.$set();

Vue——表单数据收集

<body>
    <div id="root">
        <form @submit.prevent="demo">   //阻止默认提交行为,
            账号:<input type='text' v-model.trim="user"><br/>
            密码:<input type='password' v-model.trim="password"><br/>
            年龄:<input type="number" v-model.number="age"><br/>
            性别:
            男:<input type="radio" name="sex" v-model="man" value="man"><br/>
            女:<input type="radio" name="sex" v-model="woman" value="woman"><br/>
            爱好:
            学习<input type="checkbox" v-model="hobby" value="stydy"><br/>
            游戏<input type="checkbox" v-model="hobby" value="game"><br/>
            看书<input type="checkbox" v-model="hobby" value="readbook"><br/>

            所属校区
            <select v-model="city">
                <option value="">请选择校区</option>
                <option value="beijing">北京</option>
                <option value="shanghai">上海</option>
                <option value="shenzhen">深圳</option>
                <option value="wuhan">武汉</option>
                <option value="tianjin">天津</option>
            </select>
            其他信息<textarea v-model.lazy="other"></textarea>
           <input type="checkbox" v-model="agree">阅读并接收用户协议<a href="https://www.baidu.com">用户协议</a>
            <button>提交</button>
        </form>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
            user:'',
            password:'',
            sex:'man',
            hobby:[],
            city:'beijing',
            other:'',
            agree:'',
        },
        methods:{
            demo:{
                console.log(this._data);  //方式一
                ---------------------
               // console.log(JSON.stringify(this.userInfo));  此方式需要把信息放入一个    
userInfo对象里边,并需要在全部的v-model前边加userInfo前缀;
            }
        }
    })
</script>

收集表单小结:

       若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。

        若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。

        若:<input type="checkbox"> 

                        1、没有配置Input的value属性,那么收集的就是checked(勾选或者未勾选,true或false)

                        2、配置Input的value属性:

                                        (1)v-model的初始值是非数组,那么收集的就是checked值(true或false)

                                           (2)v-model的初始值是数组,那么收集的就是value组成的数据;

备注:v-model的三个修饰符:

        (1)lazy:失去焦点收集数据;

        (2)Number:输入字符串转为有效数字(一般type="number" v-model.number同时出现)

        (3)trim:输入的首位空格过滤;

Vue——过滤器

方式一:计算属性方式和构造方法(局部)

<body>
    <div id="root">
        <h2>显示格式化后的时间</h2>
        <h3>现在是:{{fmtTime}}</h3>
        <h3>现在是:{{getFmtTime()}}</h3>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
            time:1621561277603
        },
        computed:{  //计算属性方式
            fmtTime(){
                return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')  //返回调用dayjs方法
            }
        },
        methods:{
            getFmtTime(){
                return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')  //返回调用dayjs方法
            }
        }
    })
</script>

方式二:过滤器方式(局部)

<body>
    <div id="root">
        //不包含参数的过滤器
        <h3>现在是:{{time | timeFormater}}</h3>
---------------------------------------
            //有参数的过滤器
        <h3>现在是{{time | timeFormater('YYYY_MM_DD')}}</h3>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
         el:'#root',
         data:{
            time:1621561277603
        },
        filters:{
            timeFormater(value,str='YYYY-MM-DD HH:mm:ss'){   //如果传递的是不包含参数的使用后边的参数,如果传递的包含参数则使用传递的
                 return dayjs(value).format(str);   //format计划,设计
            }
        }
    --------------------------------------------
        filters:{
            timerFormater(value){
                return dayjs(value).format('yyyy年mm月dd日 hh:mm:ss')
            }
        }
    })
</script>

多个过滤器联动(局部)

<body>
    <div id="root">
        //不包含参数的过滤器
        <h3>现在是:{{time | timeFormater}}</h3>
---------------------------------------
            //有参数的过滤器
        <h3>现在是{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
         el:'#root',
         data:{
            time:1621561277603
        },
        filters:{
            timeFormater(value,str='YYYY-MM-DD HH:mm:ss'){   //如果传递的是不包含参数的使用后边的参数,如果传递的包含参数则使用传递的
                 return dayjs(value).format(str);
            },
            mySiice(value){
                return value.slice(0,4)  //从得到的值从截取四个长度
            }
        } 
    })
</script>

全局过滤器:

<body>
    <div id="root">
        //不包含参数的过滤器
        <h3>现在是:{{time | timeFormater}}</h3>
---------------------------------------
            //有参数的过滤器
        <h3>现在是{{time | timeFormater('YYYY_MM_DD')}}</h3>
    </div>

//模拟使用全局过滤器
    <div id='root2'>
        <h2>{{msg | mySlice}}</h2>    
    </div>
</body>
<script>
    Vue.config.productionTip=false;
//声明全局过滤器
    Vue.filter('mySlice',function(value){
        return value.slice(0,4)
    })
    const vm = new Vue({
         el:'#root',
         data:{
            time:1621561277603
        },
        filters:{
            timeFormater(value,str='YYYY-MM-DD HH:mm:ss'){   //如果传递的是不包含参数的使用后边的参数,如果传递的包含参数则使用传递的
                 return dayjs(value).format(str);
            },
            mySlice(value){
                return value.slice(0,4)
            }
        }
    })
    new Vue({
        el:'#root2',
        data:{
            msg:'hello,word'
        },
        mySiice(value){
           return value.slice(0,4)  //从得到的值从截取四个长度
        }
    })
</script>

 过滤器小结:

定义:对要显示的数据进行特定的格式化后再显示(使用一些简单的处理)。

语法:

        (1)注册过滤器:Vue.filter(name,callback)new Vue { filters:{  }  }

            (2)使用过滤器:{{xxx  |  过滤器名称}或者  v-bind: 属性=" xxx  |   过滤器名称  "

    两种用法:    一、 用在差值语法中;                    二、   v-bind中

 备注:

        (1)过滤器可以接收额外参数、多个过滤器可以串联;

        (2)并不会改变原来数据,而是产生新的对应的数据;

Vue——内置指令

我们之前学过的指令:

        v-bind:单向数据绑定,可简写"";

        v-model: 双向数据绑定;

        v-for:遍历数组/对象/字符串;

        v-on:绑定事件监听,可简写为:@;

        v-if:条件渲染(动态控制节点是否存在;)

        v-else: 条件渲染(动态控制节点是否存在)

        v-show:条件渲染(动态控制节点是否存在)

v-text指令:

<body>
    <div id= "root">
        <div>{{name}}</div>
        <div v-text="name">被替换</div>   //v-text中的内容会替换到节点中内容
    </div>
</body>
<script>
    Vue.config.productionTip='false';
    const vm = new Vue({
        el:'#root',
        data:{
            name:'尚硅谷',
            str:'你好啊'
        }
    })
</script>

1、作用:向其所在的节点中渲染文本的内容。

2、与差值语法不同的是:v-text会替换到节点中的内容;差值语法{{ }}不会;

内置指令——v-html

<body>
    <div id="root">
        <div v-html="str"><>
        <div v-html="str2"></div>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
            name:'尚硅谷',
            str2:'<h3>你好</h3>', 
        }
    })
</script>

小结:

v-html指令:

        1、作用:向指定的节点中渲染包含HTML结构的内容;

        2、与差值语法区别:

                        (1)v-html会替换掉节点中所有的内容,{{  }}不会;

                        (2)v-html可以识别HTML结构;

        3、注意:

        (1)在网站上动态渲染任意HTML是非常危险的,容易被XSS共计;

        (2)一定要在可信的内容上使用v-html(永远不要用在用户提交的内容上)

 v-clock指令

五秒钟之前不显示结构,五秒钟后显示调用Vue.js 完成后的样式。

<head>
    <style>
        [v-cloak]{  //属性选择器,选择所有的v-cloak属性
            display:none
        }
    </style>
</head>
<body>
    <div id="root">
        <h2 v-clock>{{name}}</h2>    
    </div>
    <script type="text/javascript" src="https:www.baidu.com/resours/5s/vue.js">五秒钟后执</script>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root';
        data:{
            name:'尚硅谷'
        }
    })
</script>

小结:

v-cloak指令(没有值):

        1、本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删除v-cloak属性;

        2、使用css配合v-cloak可以解决网速慢时页面展示{{  **}}的问题;

v-once指令:

小结:

        (1)v-once所在节点在初次动态渲染后,就视为静态内容了。

        (2)以后的数据的改变不会引起v-once所在结构的更新,可以用于优化性能

<body>
    <div id="root">
        <h2 v-once>初始化值{{n}}</h2>
        <h2>初始值是:{{n}}</h2>
        <button @click="add">点击加1</button>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
            n:1
        },
        methods:{
            add(){
                return this.n++;
            }
        }
    })
</script>

v-pre指令:

<body>
    <div id="root">
        <h2 v-pre>vue很简单</h2>
        <button>使用v-pre后跳过h2的编译过程</button>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
        n:1;
        }
    })
</script>

小结:

v-pre指令:(1)可以跳过所在节点的编译过程; 

                (2)可利用它跳过:没有使用指令语法、没有使用差值语法的节点,会加快编译;

 vue自定义属性

(自定义指令明不需要加“v-”)

方式一:函数式

<body>
    <div id="root">
        <h2>{{name}}</h2>
        <h2>当前值是:<span v-text='n'></span></h2>
        <h2>放大十倍:<span v-big='n'></span></h2>
        <button @click="n++">点击加1</button>
    </div>
</body>
<script>
    Vue.config.productionTip=false
    onst vm = new Vue({
        el:'#root',
        data:{
        name:'尚硅谷',
        n:1
        },
        directives:{
            big(element,binding){
                console.log('big');
                element.innerText = binding.value *10;
            }
        }
    })
</script>

big函数何时被调用时何时被调用?

(1)指令与元素成功绑定时(一上来);

(2)指令所在的模板被重新解析时。

方式二:对象式

<body>
    <div id ="root">
        <h2>{{name}}</h2>
        <h2>当前n的值是:<span v-text="n"></span></h2>
        <h2>放大后n的值是:<span v-big="n"></span></h2>
        <button>点击增加</button>
        <input type = "text" v-fbind:value="n">
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm= new Vue({
        el:'#root',
        data:{
            name:'尚硅谷',
            n:1
        },
        directives:{
            big:(element,binding){    //简写方式,相当于只执行了指令与元素成功绑定的步骤,和,指令所在被重新解析时;这两
                element.innerText = binding.value*10;
            },
            fbind:{      //对象方式调用
                bind(element,binding){       //指令与元素成功绑定时(一上来);
                    element.value=binding.value;
                },
                inserted(element,binding){     //指令所在元素被插入页面时;
                    element.focus();
                },
                update(element,binding){      //指令所在的模板被重新解析时;
                    element.value=binding.value;
                }
            }
        }
    })
</script>

Vue——自定义语法小结:

一、定义语法

(1)局部指令

    对象式:    new Vue({

        directives:{"指令名字":"配置对象"}         

})

函数式:

        new Vue({

        directives("指令名:回调函数"){

        }        

  })

(2)全局指令

Vue.directive(指令名,配置对象)

或:

Vue.directive(指令名,回调函数)

二、配置对象中常用的3个回调

        (1)bind:指令与元素成功绑定时调用;

        (2)inserted:指令所在元素被插入页面时调用        

        (3)update:指令所在模板结构贝重新解析时调用;

三、备注

指令定义时不加"v-",但使用时要加"v-"

指令明如果是多个单词,要使用kebab-case命名方式。

自定义指令this指向问题:this指向的是window

自定义指令多个单词组成的用"-"分隔,同时要用完全写法;

<body>
    <div id="root">
        <h2>当前的n的值是:<span v-text='n'></span></h2>
        <h2>放大十倍后是:<span v-big-number="n"></span></h2>
        <button @click="n++"></button>
        <br/>
        <input type='text' v-fbind:value="v">
    </div>
</body>
<script>
    Vue.config.productionTip=flase;
    const vm = new Vue({
        el:"#root",
        data:{
            name='尚硅谷',
            n:1
        },
        directives:{
            'big-nameber'(element,binding){  
  //如果自定义名字有多个单词组成,用“-”符号隔开,则如要原写法;
                element.innerText = binding.value * 10;
            },
        fbind:{
            bind(element,binding){
                    console.log("fbind-bind",this)
                    element.value = binding.value;
                },
            inserted(element,binding){
                    console.log("fbind-inserted",this);
                    element.focus();
                },
            update(){
                    console.log("fbind-update",this) 
     //上述三个自定义指令中this指window
                    element.value=binding.value;
                } 
            }
        }
    })
</script>

定义全局指令时:

<body>
    <div id="root">
        <h2>当前的n的值是:<span v-text='n'></span></h2>
        <h2>放大十倍后是:<span v-big-number="n"></span></h2>
        <button @click="n++"></button>
        <br/>
        <input type='text' v-fbind:value="v">
    </div>
</body>
<script>
    Vue.config.productionTip=flase;
    Vue.directive('fbind',{
            bind(element,binding){
                    console.log("fbind-bind",this)
                    element.value = binding.value;
                },
            inserted(element,binding){
                    console.log("fbind-inserted",this);
                    element.focus();
                },
            update(){
                    console.log("fbind-update",this) 
     //上述三个自定义指令中this指window
                    element.value=binding.value;
                } 
    })
    const vm = new Vue({
        el:'#root',
        data:{
            name:'尚硅谷',   
        }
    })
</script>

Vue——生命周期

引出:生命周期

小结:

(1)生命周期又称为:生命周期回调函数、生命周期函数、生命周期钩子;

(2)作用:Vue在关键时刻帮我们调用一些特殊名称的函数

(3)生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的;

(4)生命周期函数中的this指向的是Vm或组件实例对象

<body>
    <div id="root">
        <h2 v-if="a">你好</h2>
        <h2 :style="{opacity}">欢迎学习Vue</h2>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'#root',
        data:{
            a:false,
            opacity:1
        }, 

        //Vue完成模板的解析后并把初始的真是DOM元素放入界面后(挂载完毕)调用mounted
        mounted(){
            console.log("执行了生命周期函数");
            setInterval(()=>{
                this.opacity -=0.01
                if(this.opacity <=0) this.opacity=1
            },1000)
        },
    })
</script>

 Vue——生命周期挂载流程

(1组)创建(beforeCreate  、create)

(2组)挂载(beforeMounted、mounted):发送Ajax请求、启动定时器、绑定自定义事件等【初始化操作】

(3组)更新(beforeUpdate、update)

(4组)销毁(beforeDestory、destory):清除定时器、解绑自定义事件、取消订阅等【收尾工作】

 

 使用清除定时器方式

<body>
    <div id="root">
        <h2 :style="{opacity}">欢迎学习,字体颜色变换</h2>
        <button @click="stop">点击停止变化</button>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm = new Vue({
        el:'root',
        data:{
            opacity:1
        },
        methods:{
            stop(){
                clearInterval(this.timer);
            }
        },
        mounted(){
            console.log('mounted',this)
           this.timer = setInterval(()=>{
                this.opacity -=0.01
                if(this.opacity) <=0 this.opacity=1
            },15)
        }
    })
</script>

使用销毁声明周期方式

<body>
    <div id="root">
        <h2 :style="{opacity}">欢迎学习,字体颜色变换</h2>
        <button @click="stop">点击停止变化</button>
    </div>
</body>
<script>
    Vue.config.productiontip=false;
    const vm = new Vue({
        el:'#root',
        data:{
           opacity:1
        },
        methods:{
            stop(){
                this.$destroy()  //点击销毁生命周期
            }
        },
        mounted(){    //生命周期——挂载
            console.log('mounted',this)
            this.timer = setInterval(()=>{
                console.log('setInterval')
                this.opacity -=0.01
                if(this.opacity <=0) this.opacity =1
            },15)
        },
        beforeDestory(){    //生命周期——销毁之前
            console.log("销毁之前")
            clearInterval(this.timer)
        }
    })
</script>

  小结:

 一、常用的生命周期钩子:

        (1)mounted:发送Ajax请求,启动定时器、绑定自定义事件、订阅消息等【初始化操作】

        (2)beforedestroy:清楚定时器、解绑自定义事件、取消订阅消息等【收尾工作】

二、关于销毁Vue实例:

        (1)、销毁后借助Vue开发者工具看不到任何消息;

        (2)、销毁后自定义事件会失效,但看原生DOM事件依然有效;

        (3)、一般不会再beforeDestroy操作数据,因为即使操作数据,也不会再触发更多新流程了。

Vue——组件

一、对组件的理解

定义:实现应用中局部功能代码和资源集合

二、非单文件组件

创建局部组件:

<body>
    <div id="root">
        <h1></h1>
//第三步:编写组件标签
        <hr/>
            <xuexiao></xuexiao>
        <hr/>
            <xuesheng></xuesheng>
    </div>

    <div id="root2">
        <hello></hello>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
第一步:创建组件
    const schools = Vue.extend({      //组件定义不能有el配置项,最所有组件都要被一个vm管理
        template:`
            <div>
                <h2>学校名称:{{schoolName}}</h2>
                <h2>学校地址:{{address}}</h2>
                <button @click="al">点击弹出名称</button>
            </div>
        `,
        data(){
            return{
                schoolName:'尚硅谷',
                address:'北京'
            }
        }
    }),

    const students = Vue.extend({
        template:`{
            <h2>学生名字{{studentName}}</h2>
            <h2>学生年龄{{age}}</h2>
        }`
        data(){
            return{
                studentName:'小红',
                age:'18'
            }
        }
    }),
    const vm = new Vue({
        el:'#root',
第二步:注册组件
        components:{      //注册组件们
            xuexiao : schools,     //key:value  定义最终的组件名字
            xuesheng : students
        }        
    })
<script>

创建全局组件:

<body>
    <div id="root2">
        <hel></hel>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const hello = Vue.extend({   //第一步创建组件
        template:`
            <div>
                <h2>你好,注册全局组件{{name}}</h2>
            </div>
        `,
        
        data(){
            return{
            name:'Tom',
            }
        }
    }),
    Vue.component("hel",hello)

    const vm = new Vue({
        el:'#root2',
    })
</script>

小结:

Vue中使用组件的三个步骤:

        (1)定义组件;

 

        (2)注册组件;

全局注册:                                                局部注册:

        

        (3)使用组件(写组件的标签)

(一)、如果定义一个组件:

        使用Vue.extend(options组件名)创建,其中optionsnew Vue(options)时传入的那个options几乎一样,但也有点区别:

        区别如下

        1、el配置不要写——最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。

        2、data必须写成函数——避免组件被复用时,数据存在引用关系。

备注:使用template可以配置组件结构。

二、如果注册组件: 

(1)局部组件:靠new Vue的时候传入components选项;

(2)全局注册:靠Vue.component(“组件名”,组件)

 三、编写组件标签:

        1、<school></school>

定义组件的几个注意点:

<body>
    <div id="root">
        <h2>{{msg}}</h2>
//编写组件标签
     //组件标签方式一
        <xuexiao><xuexiao>
     //组件标签写法方式二
        <xuexioa/>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
//定义组件
    const s = Vue.extend({
        name:'vue开发者工具',
        template:`
            <div>
                <span>定义组件{{name}}</span>
            </div>
        `,
        data(){
            return {
                name:'组件的参数'
            }
        }
    })
    const vm = new Vue({
        el:'#root',
        data:{
            msg:'欢迎学习Vue'
        },
//注册组件
        components:{
            xuexiao:s   //接收从组件传递的值
        }
    })
</script>

一、关于组件名——一个单词组成

        第一种写法(首字母小写):school

        第二种写法(首字母大写):School

        关于组件名——多个单词组成:

        第一种写法(kebab-case命名):my-school

        第二种写法(CameCase命名):MySchool(需要Vue脚手架支持

备注:(1)组件命名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。

            (2)可以使用name配置项指定组件在开发者工具中呈现的名字。

二、关于组件标签:

        第一种写法:<school></school>

        第二种写法:<school/>

备注:不使用脚手架时,第二种方式可能会导致后序组件不能渲染。

三、一个简写方式:

const school = Vue.extend(options)可简写为:const school = options

 Vue——组件的嵌套

<body>
    <div id="root">
        <school></school>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const student = Vue.extend({
        name:'student',
        template:`
            <div>
                <h2>姓名{{name}}</h2>
                <h2>年龄{{age}}</h2>
            </div>
        `,
        data(){
           return{
                name:'张三',
                age:25
            }    
            
        }
    }),
    const school= Vue.extend({
        name:'school',
        template:`
            <div>
                <h2>学校姓名{{name}}</h2>
                <h2>学生数量{{number}}</h2>
                <student></student>
            </div>
        `,
        data(){
            return{
                name:'尚硅谷',
                number:100
            }
        },
        components:{
            student
        }
    }),
    new Vue({
        el:'#root',
        components:{
            school;
        }
    })
</script>

 App合并

<body>
    <div id="root">
        <app></app>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const student = Vue.extend({
        name:'Student',
        template:`
            <div>
                <h2>学生姓名{{name}}</h2>
            </div>
        `,
        data(){
            return{
                name:'张三'
            }
        }
    }),
    const school = Vue.extend({
        name:'School',
        template:`
          <div>
            <h2>学校名称:{{name}}</h2>
            <h2>学校地址:{{address}}</h2>
            <student></student>
          </div>
        `,
        components:{   //注册学生组件
            student
         }
        data(){
            return{
                name:'尚硅谷',
                address:'北京'
            }
        }
    }),
    const app = Vue.extend({
         name:'App',
         template:`
            <div>
                <school></school>
            </div>
        `,
         components:{   //注册学校组件
            school
         }
    }),
    const vm = new Vue({
        el:'#root',
        components:{
           app
        }
    })
</script>

Vue——VueComponent构造函数

<body>
    <div id="root">
        <school></school>
        <hello></hello>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const school = Vue.extend({
        name:'school',
        template:`
            <div>
                <h2>学校名称{{name}}</h2>
                <button @click='showName'>点击弹出名称</button>
            </div>
        `,
        data(){
            return{
                name:'尚硅谷'
            }
        },
        methods:{   //定义一个方法,弹出当前对象,当前对象this指向VueComponent
            showName(){
            alert(this.name);
            }
        }
    }),
    const hello = Vue.extend({
        name:'hello',
        template:`
            <div>
                <h3>与school同级的对象{{name}}</h3>
            </div>
        `,
        data(){
           return{
            name:'构造函数';
            }
        },
    })
    const vm = new Vue({
        el:'#root',
        data:{
            components:{
                school;
                hello;
            }
        }
    })
</script>

 关于VueComponent小结:

1、school组件本质是一个名为VueComponent的构造函数,且不是程序员我们自己定义的,是Vue.extend生成的; 

2、我们只需要写<school></school>或者<school/>,Vue解析时就会帮我们创建一个school组件的实例对象;

3、特别注意:每次调用Vue.extend,返回的都是一个新的VueComponent。而不是使用同一个;

4、关于this只想问题:

        (1)组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数、它们的this指向的均是【VueComponent实例的对象】

        (2)newVue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数、它们的this指向的都是【Vue实例对象】

5、VueComponent的实例对象,简称为“VC”(组件实例对象)。Vue实例对象简称:vm

        

Vue实例和VC组件实例

因为组件时可复用的Vue实例,所以它们与new vue接收相同的选项,例如data、computed、watch、methods以及生命周期钩子等。仅有的例外是像el这样的根实例(vm)特有的选项,一个组件的data选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立拷贝

<body>
    <div id="root">
        <school></school>    //创建组件标签
    </div>
</body>
<script>
    Vue.config.productionTip= false;
    Vue.prototype.x=99
    const school=Vue.extend({     //创建组件
        name:'school',
        template:`
            <div>
                <h2>学校名称{{name}}</h2>
                <h2>学校地址{{address}}</h2>
            </div>
        `,
         data(){
            return {
                name:'尚硅谷',
                address:'北京'
            }
        },
        methods:{
            showX(){
                console.log(this.x)
            }
        }
    })
    const vm = new Vue({     //创建vm实例
        el:'#root',
        data:{
            msg:'你好'
        },
        components:{school}   //注册组件
    })
</script>

一个重要的内置关系(原型链)

VueComponent.prototype === Vue.prototype

为什么要有这个关系:让组件实例对象(vc)可以访问到Vue原型上的属性,方法(依据原型链),如果都没找到返回null。

 Vue——单文件组件

一、声明组件

<template>
    <div class = "demo">
        <h2>学校名称{{name}}</h2>
        <h2>学校地址{{address}}</h2>
        <button @click="showName">点击提示学校名称</button>
    </div>
</template>
<script>
    export default{
        name:'school',
        data(){
            return{
            school:'尚硅谷',
            address:'北京昌平'
            }
        }.
        methods:{
            showName(){
                alert(this.schoolName)
            }
        }, 
    }
<script>
<style>
    .deom{
        background-color:pink;
    }
</style>
<template>
    <div>
        <h2>学生{{name}}</h2>
        <h2>年龄{{age}}</h2>
    </div>
</template>
<script>
    export default{
        name:'Student',
        data(){
            return{
                name:'张三',
                age:18
            }
        }
    }
</script>
<style></style>

二、合并组件(App)

<template>
    <div>
        <School></School>
        <Student></Student>
    </div>
</template>
<script>
//引入组件
    import School from './School'
    import Student from './Student'
    export default{
        name:'App',
        components:{
            School,
            Student
        }
    }
</script>

三、引入合并好的组件,实例化Vue实例(main.js)

import App from './App.Vue'
new Vue({
    el:'#root',
    template:`<App><App>`,
    components:{
    App
    },
})

四、创建页面(index.html)引入main.js

<html>
<head>
    <title>Document</title>
</head>
<body>
    <div id="root"></div>
    <script type='text/javascript' src='../js/vue.js'></script>
    <script type="text/javascript" src="./main.js"></script>
</body>
</html>

Vue——创建Vue脚手架:

结构:

Vue——render函数

在main.js文件中:

一、引入的Vue是残缺的时,需要使用函数render:(  ){  return ***}

import引入的Vue文件如果是ES6模式引入,默认指向的是vue.runtime.esm.js

//引入Vue
import Vue from 'vue'
//引入App组件,它是所有组件的父组件
//import App from './App.vue'
Vue.config.productionTip = false;
//创建Vue实例对象——vm
new Vue({
    el:'#app',
    render(createElement){
        return createElement('h1','创建的是<h1></h1>标签')
    }
----------------------------------
    render:h =>h(App) //参数是一个组件时,直接写组件名称
})

二、引入的Vue是完整的时:

<body>
    <div id="root">

    </div>
</body>
<script>
    Vue.config.productionTip =false;
    new Vue({
        el:'#root',
        <template>
        <h1>你好,引入的时完整版Vue</h1>
        </template>
    })
</script>

小结:

1、vue.js与vue.runtime.xxx.js的区别

        (1)vue.js是完整版的Vue,包含:核心功能+模板解析器。

        (2)vue.runtime.xxx.js是运行时的vue,只包含:核心功能;没有模板解析器。

2、因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收收到的createElement函数去指定具体内容

 Vue——脚手架修改默认配置

小结:(1)使用vue  inspect >output.js可以查看Vue脚手架的默认配置

       (2) 使用vue.config.js可以对脚手架进行个性化定制;

Vue——ref属性(School.vue)

<template>
    <h2 v-text="msg" ref="title"><>
    <button ref="btn" @click="showDOM">点击输出全部DOM元素</button>
    <School ref="sch">
</template>
<script>
    import School from './components/School'
    export default{
    name:'App',  //组件名
    components:{School}   //组件集
    data(){
        return{
           msg:'欢迎学习Vue'
            }
        },
        methods:{
            showDOM(){    //点击输出真是DOM元素,通过ref操作
                console.log(this.$refs.title)
                console.log(this.$refs.btn)
                console.log(this.$refs.sch)
            }
        }
    }
</script>
<style></style>

ref属性小结:

(1)被用来给元素或者子组件注册引用信息(id替代者)

(2)应用在HTML标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(VC)

(3)使用方式:

打标识方式<h1 ref="xxx"></h1><School ref="xxx"></School>

获取标识:this.$refs.xxx

 Vue——props配置

配置组件:

接收到的props是不允许修改,且优先使用props传递的值。

(Student.vue)

<template>
    <div>
        <h1>{{msg}}</h1>
        <h2>学生姓名{{name}}<h2>
        <h2>学生性别{{sex}}</h2>
        <h2>学生年龄{{age}}</h2>
        <button @click="updataAge">点击年龄加加</button>
    </div>
</template>
<script>
    export default{
        name:'Student',
        data(){
            console.log(this)
            return {
                msg:'我是一个学生',
                //this指向的值接收过来的数据
                MyAge:this.age     //修改数据,把props传递的数据复制一个放入data中
            }
        },
        methods:{
            updateAge(){
                this.myAge++
            }
        },
        props:['name','age','sex']  //简单声明接收
----------------------------------------
        props:{
            name:String,   //接收同时对数据进行类型限制
            age:Number,
            sex:String
        }
-------------------------------------------
        props:{     //接收同时对数据进行类型限制+默认值指定+必要性限制
            name:{
                type:String,
                required:true,
                
            },
            age:{
                type:Number,
                default:25
            }
            sex:{
                type:String
                required:true
            }
        }
    }
</script>

收集全部组件(app.vue)

<template>
    <div>
        <student name="张三" sex="男" :age='18+1'>   //传递数据
    </div>
</template>
<script>
    import Student from "./components/Student"
    export default{
        name:'App',
        components:{Student}
    }
</script>

小结:功能是让组件接收从外部传过来的数据

(1)传递数据:<Demo name="***">

(2)接收数据:

        第一种方式:只接受props:['name']

        第二种:限制类型props:{

                                        name;String

                                        }

        第三种(限制类型、限制必要性、指定默认值)

        props:{

              name:{

              type:String,

                required:true,

                default:'张三'  

                }

        }

备注props是只读的,Vue底层会检测对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么需要复制props内容中的一个数据到data中,然后去修改data中的数据

 Vue——mixin混入(混合文件名.js)

 创建混合

export const hunhe={
    methods:{
        showName(){
            alert(this.name)
        }
    },
    mounted(){   //挂载是输入你好
        console.log("你好啊")
    },
}
//引用混合的都会有这两个数据
export const hunhe2={
    data(){
        return {
        x:100,
        y:200
        }
    }
}

引入局部混合文件 

注:当引入混合文件中数据和源文件数据冲突时,以源文件数据为准;都出现挂载时,全部执行。

<template>
    <div>
        <h2 @click="showName">学校名称{{name}}</h2>
        <h2>学校地址{{address}}</h2>
    </div>
</template>
<script>
//引入混合文件
    import {hunhe,hunhe2} from './mixin'
    export default{
        name:'',
        data(){
            return {
            name:'尚硅谷',
            address:'北京',
            x:666
            }
        },
        mixin:[hunhe,hunhe2],
        mounted(){
            console.log("你好!!")
        }
    }
<script>

全局混合:

import Vue from 'vue'
import App from './App.vue'
import {hunhe,hunhe2} from './mixin'
Vue.config.productionTip = false;
Vue.mixin(hunhe)
Vue.mixin(hunhe2)
new Vue({
    el:'',
    render:h=>h(App)    //render使用残缺Vue时,使用
})

mixin(混入)小结:

功能:可以吧多个组件共用的配置提取成一个混入的对象;

使用方法:第一步定义混合,例如:{ data(){***}

                                                                        methods:{**}

                                                                                }

第二步使用混入:

(1)全局混入:Vue.mixin(***)

(2)局部混入:mixin:[ ' *** ' ]

Vue——插件

定义插件(plugins.js):

export default{
    install(Vue){
        Vue.filter("mySlice",function(value){   //定义全局过滤器
            return value.slice(0,4)
        }),
        Vue.directive('fbind',{     //定义全局指定
            bind(element,binding){
                element.value=binding.value
            },
            inserted(element,binding){
                element.focus()
            },
            update(element,binding){
                element.value=binding.value
            }
        }),
        Vue.mixin({   //定义全局混入
            data(){
                return {
                x:100,
                y:100
                }
            }
        })
在Vue原型对象上添加一个方法(vm和VC都能用)
        Vue.prototype.hello = ()=>{alert('你好!!')}
    }
}

应用(使用)插件(main.js):

import Vue from 'vue'
import App from './App.vue'
import plugins from './plugins'
Vue.config.productionTip= false
Vue.use(plugins)
new Vue({
    el:'#App',
    render h=>h(App)
})

组件中使用插件(Student.vue): 

<template>
    <div>
        <h2>学生姓名{{name}}</h2>
        <h2>学生性别{{sex}}</h2>
    </div>
</template>
<script>
    export default{
        name:'Student',
        data(){
            return {
                name:'张三',
                sex:'男'
            }
        },
    }
</script>

插件小结:

功能:用于增强Vue。

本质:包含install方法的对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。

定义插件:

        对象.install = function(Vue,options){

                //添加全局过滤器

                Vue.filter(***)

        }

        //添加全局指令

        Vue.directive(***)

        //配置全局混入

        Vue.mixin(***)

        //添加实例方法

        Vue.prototype.$myMethod = function(){***}

        Vue.prototype.$myProperty = ***

Vue——scoped样式

作用:让样式在局部生效,防止冲突。

写法:<style scoped>(style后边可以跟着lang="less"或者"css"样式,但是可能需要安装less-loader)

 当两个组件样式冲突时,以引入组件的最后的那个顺序为准:

(App.vue)合并组件中

<template>
    <div>
        <School/>
        <Student/>
    </div>
</template>
<script>
    import Student from './components/Student'
    import School from './components/School'
    export default{
        name:'App',
        components:{School,Student}
    }
</script>

分组件(School.vue)

scoped:使属性仅在局部有效。

<template>
    <div class="demo">
        <h2>学校名称:{{name}}</h2>
        <h2>学校地址:{{address}}</h2>
    </div>
</template>
<script>
    export default {
        name:'School',
        data(){
            return{
                name:'尚硅谷',
                address:'北京'
            }
        }
    }
</script>
<style scoped>
    .demo{
        background-color:pink;
    }
</style>

 style后边可以跟着lang="less"或者"css"样式,但是可能需要安装less-loader:

<template>
    <div class="demo">
        <h2>学生姓名:{{name}}</h2>
        <h2>学生年龄:{{age}}</h2>
    </div>
</template>
<script>
    name:'Student',
    data(){
        name:'张三',
        age:25
    }
</script>
<style lang=less scoped>
    .demo{
        background: blue;
        .atguigu{
            font-size:25px;
        }
    }
</style>

 Vue—— Todo-list案例

 步骤一:实现静态组件:抽取组件,使用组件实现静态页面效果。

步骤二:展示动态数据:

        (1)数据的类型,名称是什么。

        (2)数据保存在哪个组件。

步骤三:交互——从绑定事件监听开始。·······

静态页面创建

初始化列表:

(MyList.vue)

<template>
    <ul class ="todo-main">
        <MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj"/>
    </ul>
</template>
<script>
    import MyItem from './MyItem'
    export default {
        name:'MyList',
        components:{MyItem},

    }
</script>
<style>
</style>

 列表组件:(Myitem.vue) 

<template>
    <li>
        <label>
            <input type="checkbox" :checked="todo.done">
            <span>{{todo.title}}</span>
        </label>
    </li>
</template>
<script>
    export default{
        name:'MyItem',
        props:['todo'],
    }
</script>
<style></style>

获取添加数据(Myheader.vue)

<template>
    <div class ="todo-header">
        <input type="text" placeholder="请输入名称,按回车确认" v-model="title" @keyup.enter='add'/>
    </div>
</template>
<script>
    import {nanoid} from 'nanoid'
    export default{
        name:'MyHeader',
        props:["addTodo"],
        data(){
            return{
                title:''
            }
        }
        methods:{
            add(){
            //效验数据
                if(!this.title.trim()) return alert("请输入数据")
            将用户的输入包装成一个todo对象
                const todoObj={id:nanoid(),title:this.title,done:false}
        通知App组件去添加一个todo对象
                this.addTodo(todoObj)
                this.title=''
            }
        }
    }
</script>
<style>

<style>

组件集合(App.vue):

<template>
    <div id="root">
        <div class="todo-container">
            <div class="todo-wrap">
                <MyHeader :addTodo="addTodo"/>
                <MyList :todos="todos/">
                <MyFooter/>
            </div>
        </div>
    </div>
</template>
<script>
    import MyHeader from './components/MyHeader'
    import MyList from './components/MyList'
    import MyFooter from './components/MyFooter.vue'
    export default{
        name:'App',
        components:{MyHeader,MyList,MyFooter},
        data() {
            return{
                todos:[
                    {id:'001',title:'吃饭',done:true},
                    {id:'002',title:'看书',done:false},
                    {id:'003',title:'打代码',done:true}
                ] 
            }
        },
        methods:{
            addTodo(todoObj){
                this.todos.unshift(todoObj)
            }
        },
    }
</script>
<style></style>

  

 总结:TodoList案例

一、组件化编码流程:

        

本地存储:

Window.sessionStorageWindow.localStorage属性 :

Window.sessionStorage大小约为5MB;

Window.localStorage大小约为20MB;

(1、存储数据:

sessionStorage.setItem(key,value)

(2)、获取数据

sessionStorage.getItem(key,value)

(3)、删除数据

sessionStorage.removeItem(key,value)

(4)、删除所有数据

sessionStorage.clear()

Vue——自定义事件绑定

学生组件

<template>
    <div class="student">
        <h2>学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2>
        <button @click="sendStudentName">把学生名给App组件</button>
    </div>
</template>
<script>
    export default{
        name:'Student',
        data(){
            return{
                name:'张三',
                sex:'男'
            }
        },
        methods:{
            sendStudentName(){
        
                this.$emit("atguigu",this.name)   触发App组件实例身上的'atguigu'事件
            }
        }
    }
</script>
<style lang="less" scoped>
    .demo{
        background-color:'pink';
        .atguigu{
            font-size:40px;
        }
     }
</style>

学校组件:

<template>
    <div class="school">
        <h2>学校{{name}}</h2>
        <h2>学校地址{{address}}</h2>
        <button @click="sendSchoolName">点击把学校名称给App</button>
    </div>
</template>
<script>
    export default{
        name:'School',
        props:['getSchoolName'],   //接收从App组件中传过来的数据
        data(){
            name:'尚硅谷',
            address:'北京'
        },
        methods:{
            sendSchoolName(){
                this.getSchoolName(this.name)
            }
        }
    }
</script>
<style lang="less">
    .demo{
        background-color:blue;
        .atguigu{
            font-size:40px;    
        }
     }
</style>

App.vue组件

<template>
    <div class="app">
        <h1>{{msg}}</h1>
     通过父组件给子组件传递函数类型的props实现:子给父传递数据
         <School :getSchoolName="getSchoolName"/>

      通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一个自定义写法:使用@或v-on)
         <Student v-on:atguigu="getStudentName"/>

    通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种自定义写法,使用ref)
        <Student ref="stu"/>
    </div>
</template>
<script>
    import Student from"./components/Student"
    import School from './components/School'
    export default{
        name:'App',
        data(){
            return{
                msg:'你好啊'
            }
        },
        methods:{
            getSchoolNmae(name){
                console.log("传递参数,学校名称",name)
            },
            getStudentName(name){
                console.log("触发了事件",name)
            }
        },
        mounted(){
        //挂载自定义事件
            this.$refs.stu.$on("atguigu",this.getStudentName)  
        //只执行一次
            this.$refs.stu.$once("atguigu",this.getStudentName)
        }
    }
</script>
<style></style>

 Vue——自定义事件解绑

 student.vue组件:

<template>
    <div class="student">
        <h2>学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2>
        <button @click="sendStudentName">把学生名传递到App</button>
        <button @click="unbind">解绑指定事件</button>
        <button @click="xiaohui">点击销毁当前Student组件实例</button>
    </div>
</template>
<script>
    export default{
        name:'Student',
        data(){
            return {
                name:'张三',
                sex:'男'
            }
        },
        methods:{
            sendStudentName(){
                this.$emit("atguigu",this.name)
                this.$emit("demo")
            }
        },
        unbind(){
            this.$off('atguigu')   //解绑一个自定义事件
            this.$off(['atguigu','demo'])   //解绑多个自定义事件
            this.$off()    //解绑多个自定义事件
        },
        xiaohui(){
            this.destroy()  //销毁了当前Student组件的实例,销毁后所有的Student实例的自定义事件都失效
         }
        
    }
</script>
<style></style>

App.vue组件:

<template>
    <div class="app">
        <h1>{{msg}}</h1>
        <School :getSchoolName="getSchoolName"></School>
        <Student @atguigu="getStudentName" @demo="m1"></Student>
    </div>
</template>
<script>
    import {Student} from './component/Student'
    import {School} from './component/School'
    export default{
        name:'App',
        components:{School,Student}
        data(){
            return{
                msg:'你好啊'
            }
        },
        methods:{
            getSchoolName(name){
                console.log("App收到了学校的名",name)
            },
            getStudentName(name){
                console.log("App收到了学生名字",name)
            },
            m1(){
                console.log("m1事件被调用了");
            }
        },
     //   mounted(){
      //      this.$refs.student.$on('atguigu',this.getStudentName)  //绑定自定义事件
      //  }
    }
</script>
<style></style>

Vue——自定义事件总结

一、一种组件间通信的方式,适用于:子组件===》父组件

二、使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件回调在A中);

三、绑定自定义事件:

        (1)第一种方式,在父组件中:

         (2)第二种方式,在父组件中:

   

         (3)若想让自定义事件只能触发一次,可以使用"once"修饰符,或者$once方法;

四、触发自定义事件:

 五、解绑自定义事件:

 六、组件上可以也可以绑定原生DOM事件,需要使用“native”修饰符。

七、注意:通过绑定自定义事件时,回调要么配置在methods中,或者用箭头函数,否则this指向会出现问题。

<template>
    <div class="app">
        <h1>{{msg}} 学生姓名是:{{studentName}}</h1>
        <Student ref="student"/>
    </div>
</template>
<script>
    import Student from './components/Student'
    export default {
       name:'App',
       data(){
          return {
            msg:'你好啊',
            studentName:''
            }
        },
        methods:{
            getStudentName(name){
                console.log("App收到了学生名字",name)
                this.studentName=name
            },
            m1(){
                console.log("demo事件被触发了")
            }
        },
         mounted(){
            this.$refs.student.$on('atguigu',this.getStudentName)   //绑定自定义事件
        }
    }
</script>
<style></style>

TodoList案例自定义事件:

<template></template>

Vue——全局事件总线,任意组件间通信

 创建全局事件总线:

import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip=false;
new Vue({
    el:'',
    render: h=>h(App),
    beforeCreate(){
        Vue.prototype.$bus=this   //安装全局事件总线
    },
})

兄弟组件一传递数据:

<template>
    <div class="student">
        <h2>学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2>
        <button @click='sendStudentName'>点击接收School组件信息</button>
    </div>
</template>
<script>
    export default{
        name:'Student',
        data(){
            return {
                name:'张三',
                sex:'男',
            }
        },
        methods(){
            sendStudentName(){   
                this.$bus.$emit('hello',this.name)   //应用自定义事件
            }
        }
    }
</script>
<style><style>

兄弟组件——接收数据:

<template>
    <div class="school">
        <h2>学校{{name}}</h2>
        <h2>学校地址{{address}}</h2>
    </div>
</template>
<script>
    export default{
        name:'School',
        data(){
            return{
                name:'尚硅谷',
                address:'北京'
            }
        },
        mounted() {
            this.$bus.$on('hello',(data)=>{    //设置自定义事件
                console.log("我是School组件,Student组件收到了数据",data)
            })
        },
        beforeDestory(){
            this.$bus.$off('hello')  //解绑自定义事件
        }
    }
</script>
<style></style>

小结:

一、一种组件间通信的方式,适用于任意组件间通信。

二、安装全局事件总线:

三、使用事件总线:

        (1)接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件回调留在A组件自身。

写法一:

写法二:

         (2)提供数据:

 四、最好在beforeDestroy钩子中,用$off解绑当前组件所用的事件。

 TodoList案例——事件总线写法

(main.js)创建全局事件总线

import Vue from 'Vue'
import App from './App.vue'
Vue.config.productionTip=false;
new Vue({
    el:'#app',
    render:h=>(App),
    beforeCreate(){
        Vue.prototype.$bus=this
    },
})

App.vue创建事件,接收数据

<template></template>
<script>
    import MyHeader from './components/MyHeader'
    import MyList from './components/MyList'
    import MyFooter from './components/MyFooter'
    export default {
        name:'App',
        components:{MyHeader,MyList,MyFooter}
        data(){},
        methods:{}
        watch:{},
        mounted(){   //挂载时,绑定全局事件总线
            this.$bus.$on('checkTodo',this.checkTodo)
            this.$bus.$on('deleteTodo',this.deleteTodo)
        },
        beforeDestroy() {    //销毁事件时,解绑全局事件
            this.$bus.$off('checkTodo')
            this.$bus.$off('deleteTodo')
        }
    }
</script>
<style></style>

MyItem.vue触发事件,传递数据

<template></template>
<script>
    export default{
        name:'MyItem',
        props:['todo'],
        methods:{
            handleCheck(id){
                this.$bus.$emit('checkTodo',id)
            },
            handleDelete(id){
                if(confirm("确认删除吗")){
                    this.$bus.$emit('deleteTodo',id)
                }
            }
        }
    }
</script>
<style></style>

Vue——消息订阅与发布

School.vue,接收数据,订阅消息

<template>
    <div class="school">
        <h2>学校名称:{{name}}</h2>
        <h2>学校地址:{{address}}</h2>
    </div>
</template>
<script>
    import pubsub from 'pubsub-js'
    export default{
        name:'School',
        data(){
            return {
                name:'尚硅谷',
                address:'北京',
            }
        },
        mounted(){                             (消息名,数据)
          this pubId=pubsub.subscribe('hello',(msgName,data)=>{
                 console.log("有人发布了hello消息,执行会滴函数hello")
            })
        },
        beforeDestroy(){
            pubsub.unsubscribe(this.pubId)
        }
    }
</script>
<style></style>

student.vue发送数据

<template>
    <div>学生姓名:{{name}}</div>
    <div>学生性别:{{sex}}</div>
    <button @click="sendStudentName">把学生名发送给School组件</button>
</template>
<script>
    import pubsub from 'pubsub-js'
    export default{
        name:'Student',
        data(){
            return {
                name:'张三',
                sex:'男'
            }
        },
        methods:{
            sendStudentName(){
                pubsub.publish('hello',"发送数据给School")
            }
        }
    }
</script>
<style></style>

消息订阅与发布(pubsub)

小结:

1、安装pubsub:

2、引入pubsub: 

3、接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件中

 

 写法二:

 4、提供数据:

 5、最好在beforeDestroy钩子中,用

 TodoList案例优化——消息订阅方式

App.vue

import MyList from './components/MyList'
import MyFooter from './components/Footer'
export default{
    name:'App',
    components:{MyHeader,MyList,MyFooter},
    data(){},
    methods:{},
    watch:{},
    mounted(){
        this.$bus.$on('checkTodo',this.checkTodo)
        this.pubId=pubsub.subscribe('deleteTodo',this.deleteTodo)
    },
    beforeDestroy(){
        this.$bus.$off('checkTodo')
        pubsub.unsubscribe(this.pubId)
    }
}

MyItem.vue

import pubsub from 'pubsub-js'
export default{
    name:'MyItem',
    props:['todo'],
    methods:{
        handleCheck(id){
            this.$bus.$emit('checkTodo',id)
        }
    },
    handleDelete(id){
        if(confirm('确定删除吗')){
            pubsub.publish('deleteTodo',id)
        }
    }
}

 TodoList案例优化——添加编辑功能

MyItem.vue

<template>
    <li>
        <label>
            <input type='checkbox' :checked="todo.done" @change="handleCheck(todo.id)">
            <span v-show="!todo.isEdit">{{todo.title}}</span>
            <input 
                type="text" 
                v-show="todo.isEdit"
                :value="todo.title" 
                @blur="handleBlur(todo)">
        </label>
        <button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
        <button v-show="!todo.isEdit" class="btn btn-edit" @click="handleEdit(todo)">编辑</button>
    </li>
</template>
<script>
    import pubsub from "pubsub-js"
    export default{
        name:'MyItem',
        props:['todo'],
        methods:{
            handleCheck(id){},
            handleDelete(id){},
            handleEdit(todo,$event){
                if(todo.hasOwnProperty('isEdit')){
                    todo.isEdit =true
                }
                else{
                    this.$set(todo,'isEdit',true)
                }   
            },
            //失去焦点回调,(真正执行修改逻辑)
            handleBlur(todo,e){
                todo.isEdit=false
                if(!e.target.value.trim()) return("输入不能为空")
                this.$bus.$emit('updataTodo',todo.id,e.target.value)
                 
            }
        }
    }
</script>
<style></style>

App.vue文件中

<template></template>
<script>
    import MyHeader from './components/MyHeader'
    import MyList from './components/MyList'
    import MyFooter from './components/MyFooter'
    export default{
        name:'App',
        components:{MyHeader,MyList,MyFooter}
        data(){},
        methods:{
            addTodo(todoObj){},
            checkTodo(id){
                this.todos.forEach((todo)=>{
                    if(todo.id=id) todo.done=!todo.done
                })
            },
            updataTodo(id,title){
                this.todos.forEach((todo)=>{
                    if(todo.id=id) todo.title=title
                })
            },
            deleteTodo(_,id)}{},
            checkAllTodo(done){},
            clearAllTodo(){}
        },
        mounted(){
            this.$bus.$on('checkTodo',this.checkTodo)
            this.$bus.$on('updataTodo',this.updataTodo)
            this.pubId=pubsub.subscribe('deleteTodo',this.deleteTodo)
        },
        beforeDestroy(){
            this.$bus.$off('checkTodo')
            this.$bus.$off('updataTodo')
            pubsub.unsubscribe(this.pubId)
        }
    }
</script>
<style></style>

Vue——$nextTick 

MyItem.vue

点击自动获取焦点:

<template>
    <li>
        <label>
            <input type='checkbox' :checked="todo.done" @change="handleCheck(todo.id)">
            <span v-show="!todo.isEdit">{{todo.title}}</span>
            <input 
                type="text" 
                v-show="todo.isEdit"
                :value="todo.title" 
                ref="inputTitle"
                @blur="handleBlur(todo)">
        </label>
        <button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
        <button v-show="!todo.isEdit" class="btn btn-edit" @click="handleEdit(todo)">编辑</button>
    </li>
</template>
<script>
    import pubsub from "pubsub-js"
    export default{
        name:'MyItem',
        props:['todo'],
        methods:{
            handleCheck(id){},
            handleDelete(id){},
            handleEdit(todo,$event){
                if(todo.hasOwnProperty('isEdit')){
                    todo.isEdit =true
                }
                else{
                    this.$set(todo,'isEdit',true)
                },
    方式一:---------------------------------------------
                this.$nextTick(function(){
                    this.$refs.$inputTitle.focus()
                })
    方式二:----------------------------------------------
                setTimeout({
                    this.$refs.$inputTitle.focus()
                },10)
            },
            //失去焦点回调,(真正执行修改逻辑)
            handleBlur(todo,e){
                todo.isEdit=false
                if(!e.target.value.trim()) return("输入不能为空")
                this.$bus.$emit('updataTodo',todo.id,e.target.value)
                this.$refs.inputTitle.focus()
            }
        }
    }
</script>
<style></style>

 nextTick小结:

(1)、语法:this.%nextTick(“回调函数”)

(2)、作用:在下一次DOM更新结束后,执行其指定的回调;

(3)、什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。

 Vue——动画与过度

子组件:

<template>
    <div>
        <button @click="isShow = !isShow">显示/隐藏</button>
        <transition appear>  //如果transition有名称,则,调用时需要加上名,加上appear可以出现进入动画
            <h1 v-show="isShow">你好啊</h1>
        </transition>
    </div>
</template>
<script>
    export default{
        name:'Test',
        data(){
            return{
                isShow:true
            }
        }
    }
</script>
<style scoped>
   h1{
        background-color:pink;
    }
    .v-enter-active{
        animation:donghua 1s linear;
    }
    .v-leave-active{
        animation:donghua 1s linear reverse; 
    }
    @keyframes donghua{
        from{
            transfrom:translateX(-100px);
        }
        to{
            transfrom:translateX(0px)
        }
    }
</style>

父组件:

<template>
    <div>
        <Text/>
    </div>
</template>
<script>
    import Test from './conponents/Test'
    export default{
         name:'App',
         components:{Test}
    }
</script>
<style>
</style>

过渡效果

子组件:

<template>
    <div>
        <button @click="isShow = !isShow>显示隐藏</button>
        <transition name="hello" appear>
            <h2 v-show="isShow"></h2>
        </transition>
    </div>
</template>
<script>
    export default{
        name:'Test2',
        data(){
            return{
                isShow=true;
            }
        }
    }
</script>
<style>
    h2{
        background-color:pink;
        transition:1s linear;
    }
   //进入的起点;离开的终点
    .hello-enter,.hello-leave-to{
        transform:translateX(-100px);
    }

    //进入的过程中,离开的过程中
    .hello-enter-active,.hello-leave-active{
        transition:1s linear;
    }

    //进入的终点;离开的起点
    .hello-enter-to,.hello-leave{
         transform:translateX(0px);
    }
</style>

父组件:

<template>
    <div>
        <Test/>
        <Test2/>
    </div>
</template>
<script>
    import Test from './components/Test'
    import Test2 from './components/Test2'
    export default{
        name:'App',
        components:{
            Test,
            Test2
        }
    }
</script>
<style></style>

多个元素过渡:

利用<transition-group></transition-group>

集成第三方库,创建动画:

动画小结:

<template>
    <ul>
        <transition-group name="todo" appear>
            <MyItem>
                v-for="todoObj in todos"
                :key="todoObj.id"
                :todo="todoObj"
            </MyItem>
        </transition-group>
    </ul>
</template>
<script>
    import MyItem from './MyItem'
    export default{
         name:'MyList',
         components:{MyItem},
        props:['todos']
    }
</script>
<style>
    .todo-enter-active{
        animation:donghua 1s linear;
    }
    .todo-leave-active{
        animation:donghua 1s linear reverse; 
    }
    @keyframes donghua{
        from{
            transfrom:translateX(-100px);
        }
        to{
            transfrom:translateX(0px)
        }
    }
</style>

Vue封装过渡与动画:

1、作用:在插入、更新或移除DOM元素时,在合适的时候给元素添加样式类名。

2、如图:

 写法:

        (1)准备好样式:

                元素进入的样式:1、v-enter:进入的起点

                                                2、v-enter-active:进入的过程中

                                                3、v-enter-to:进入终点

                元素离开样式:

                                                1、v-leave:离开的起点;

                                                2、v-leave-active:离开过程中

                                                3、v-leave-to:离开的终点

3、使用<transition>包裹要过渡的元素,并配置name属性:

<transition>
    <h1 v-show="isShow">你好啊</h1>
</transition>

配置代理——方式一

脚手架中,创建代理服务器:

module.exports={
    pages:{
        index:{
            entry:'src/main.js'
        },
    },
    lintOnSave:false,
开启代理服务器
    devServer:{
        proxy:'http://localhost:5000'
    }
}

 这样配置代理方式两点不足:(1)一次只能配置一个搭理服务器;

(2)如果在本文件中有和请求同名字的,则执行本文件中的,不执行服务器中的;

App.vue组件

<template>
    <div>
        <button @click="getStudents">获取学生信息</button>
    </div>
</template>
<script>
    import axios from 'axios'
    export default{
        name:'App',
        methods:{
            getStudents(){
                axios.get('https://localhost:8080/student').then(
                    response=>{
                        console.log('请求成功',response.data)
                    }
                    error=>{
                        console.log("请求失败",error.message)
                    }
                )
            }
        }
    }
</script>

方式一小结:

在脚手架文件中(vue.config.js)添加如下配置:

优点:配置简单,请求资源时直接发给前端(8080)即可。

缺点:不能配置多个代理,不能灵活控制请求是否走代理。

工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器(优先匹配前端资源)

配置代理方式二:

Vue.config.js在脚手架中,配置

module.exports={
    pages:{
        index:{
            entry:'src/main.js',
        },
    },
    lintOnSave:false,
    devServer:{
        proxy:{
           '/atguigu':{
                target:'http://localhost:5000',
                pathRewrite:{'^/atguigu':''}
                ws:true,    //用于支持websocket
                changeOrigin:true   //是否传递真实服务器端口
            },
            '/demo':{
                target:'http://localhost:5001',
                pathRewrite:{'^/demo':''}
            }
        }
    }
}

(changeOrigin:true / false:用于控制请求头中的host值)

同时配置多个代理服务器:

<template>
    <div>
        <button @click="getCars">点击获取汽车信息</button>
        <button @click="getStudents">获取学生信息</button>
    </div>
</template>
<script>
    import axios from 'axios'
    export default {
        name:'App',
        methods:{
            getStudents(){
                axios.get('http://localhost:8080/atguigu/students').then(
                    response=>{
                        console.log("请求成功",response.data)
                    },
                    error=>{
                        console.log("请求失败",error.message)
                    }
                )
            },
            getCars(){
                axios.get("http://localhost:8080/demo/car").then(
                    response=>{
                        console.log('',response.data)
                    },
                    error=>{
                        console.log("请求失败了",error.message)
                    }
                )
            }
        }
    }
</script>
<style></style>

方式二小结:

github案例

 html引入第三方库

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="icon" href="<%=BASE_URL %>favicon.ico">
    <link rel="stylesheet" href="<%= BASE_URL %> css/bootstarp.css">
    <title><%=htmlWebpackPlugin.options.title %></title>
</head>
<body>
    <noscript>
        <strong>当浏览器不支持js时执行</strong>
    </noscript>
    <div id="app"></div>
</body>
</html>

App组件

<template>
      <div class='container'>
         <Search/>
         <List/>
      </div>
</template>
<script>
    import Search from './components/Search.vue'
    import List from './components/List.vue'
    export default{
        name:'App',
        components:{Search,List}
    }
<script>
<style></style>

子组件:Search.vue

<template>
    <section class="jumbotron">
        <h3 class="jumbotron-heading"></h3>
        <div>
            <input type="text" placeholder="enter the name you search" v-model="keywords"/> $nbsp;
            <button @click="searchUsers">search</button>
        </div>
    </section>
</template>
<script>
    export default{
        name:'Search',
        data(){
            return{
                keyWord:''
            }
        },
        methods:{
            searchUsers(){
                this.$bus.$emit('userList',{isFirst:false,isLoading:true,errMsg:'',users:[]})
                axios.get(`https://api.github.com/search/users?q=${this.keyWord}`).then(
                    response=>{
                       console.log("请求成功")
                       this.$bus.$emit("userList",{isLoading:false,errMsg:'',users:response.data.item})
                    },
                    error=>{
                        console.log("请求失败",isLoading:false,errMsg:error.message,user:[])
                    }
                )
            },
        },
    }
</script>
<style></style>

子组件List.vue

<template>
    <div class="row">
        <div class="card" v-for="user in users" :key="user.login">
            <a :href="user.html_url" target="_blank">
                <img :src="user.avatar_url" style="width:100px">
            </a>
            <p class="card-text">{{user.login}}</p>
        </div>
        <h1 v-show="isFirst">欢迎使用</h1>
        <h1 v-show="isLoading">加载中</h1>
        <h1 v-show="errMas">{{errMas}}</h1>
    </div>
</template>
<script>
    export default{
        name:'List',
        data(){
            return {
                info:{
                    isFirst:true,
                    isLoading:false,
                    errMas:'',
                    users:[]
                }
            }
        },
        mounted(){                    (形参)
            this.$bus.$on("userList",(dataObj)=>{
                this.info={...this.info,...dataObj}
                      (上边的info中的参数)   
                console.log(this)
            })
        },-
    }
</script>
<style>

</style>

 Vue——resource

main.js

import Vue from 'vue'
import App from './App.vue'
import vueResource from 'vue-resource'
Vue.config.productionTip=false
Vue.use(vueResource)
new Vue({
    el:'',
    render:h=>h(App),
    beforeCreate(){
        Vue.prototype.$bus=this
    },
})

Search.vue

<template>
    <section class="jumbotron">
        <h3 class="jumbotron-heading"></h3>
        <div>
            <input type="text" placeholder="enter the name you search" v-model="keywords"/> $nbsp;
            <button @click="searchUsers">search</button>
        </div>
    </section>
</template>
<script>
    import axios from 'axios'
    export default{
        name:'Search',
        data(){
            return{
                keyWord:''
            }
        },
        methods:{
            searchUsers(){
                this.$bus.$emit('userList',{isFirst:false,isLoading:true,errMsg:'',users:[]})
                this.$http.get(`https://api.github.com/search/users?q=${this.keyWord}`).then(
                    response=>{
                       console.log("请求成功")
                       this.$bus.$emit("userList",{isLoading:false,errMsg:'',users:response.data.item})
                    },
                    error=>{
                        console.log("请求失败",isLoading:false,errMsg:error.message,user:[])
                    }
                )
            },
        },
    }
</script>
<style></style>

 Vue——默认插槽

子组件category.vue

<tmeplate>
    <div class="category">
        <h3>{{title}}</h3>
        <slot></slot>  //定义一个插槽;等组件使用者向里边填充
    </div>
</template>
<script>
    export default{
        name:'Category',
        props:['title']
    }
</script>
<style></style>

App.vue父组件

<template>
    <div class="container">
        <Category title="实物">
            <img src="https://*****.jpg" alt="">
        </Category>
        <Category title="游戏"">
            <ul>
                <li v-for="(item,index) in games" :key="index">{{item}}</li>
            </ul>
        </Category>
    </div>
</template>
<script>
    import Category from './components/Category'
    export default{
        name:'App',
        components:{Category}
        data(){
            return{
                foots:['牛肉','羊肉',],
                games:['打代码','看书']
            }
        }
    }
</script>
<style></style>

 Vue——具名插槽

<template>
    <div class="container">
        <Category title="实物">
            <img slot="center" src="https://*****.jpg" alt="">
            <a slot="foot" href="http://www.***.com">更多美食</a>
        </Category>
        <Category title="游戏">
            <ul slot="center">
                <li v-for="(item,index) in listData" :key="index">{{item}}</li>
            </ul>
            <template v-slot:foot> //最新写法,但是只能放在template标签中
                <div class="foot">
                    <a href="http://***">单机游戏</a>
                    <a href="http://***">网络游戏</a>
                </div>
                <h2>使用template可以包裹放入同一个组件中</h2>
            </template>
        </Category>
    </div>
</template>
<script>
    import Category from './components/Category'
    export default{
        name:'App',
        components:{Category}
        data(){
            return{
                foots:['牛肉','羊肉',],
                games:['打代码','看书']
            }
        }
    }
</script>
<style></style>

Category.vue组件

<tmeplate>
    <div class="category">
        <h3>{{title}}</h3>
        <slot name="center"></slot>  //定义一个具有名字插槽;等组件使用者向里边填充
        <slot name="foot"></slot>        //定义一个具有名字插槽;等组件使用者向里边填充
    </div>
</template>
<script>
    export default{
        name:'Category',
        props:['title']
    }
</script>
<style></style

Vue—— 作用域插槽,

App.vue组件:

<template>
    <div class="container">
        <Category title="美食">
            <template scope="atguigu">
                <ul>
                    <li v-for="(g,index) in atguigu.game":key="index">{{g}}</li>
                </ul>
            </template>
        </Category>
        
        <Category title="游戏">
            <template scope="{games}">
                <ol>
                    <li v-for="(g,index) in games":key="index">{{g}}</li>
                </ol>
            </template>
        </Category>
    </div>
</template>
<script>
    import Category from './components/Category'
    export default{
        name:'App',
        components:{Category},
    }
</script>
<style></style>

Category.vue组件

<template>
    <div class="category">
        <h3>{{title}}</h3>
        <slot :games="games" msg="hello">默认的内容,如果没有传递过来插槽则显示</slot>
    </div>
</template>
<script>
    export default{
        name:'Category',
        props:['title']
        data(){
            return {
                game:['红警','原神','打代码']
            }
        }
    }
</script>
<style></style>

插槽小结:

一、作用:让父组件可以向子组件指定位置插入html结构,也是一种组件通信方式,适用于父组件===》子组件。

二、分类:默认插槽、具名插槽、作用域插槽。

三、使用方式:

        1、默认插槽:

         2、具名插槽:

         3、作用域插槽:

 

 Vue——vuex

一、概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue中应用多个组件的共享状态进行集中式的管理(读写),也是一种组件间通信的方式,且适用于任意组件间通信、

二、GitHub地址:

什么时候使用Vuex :(1)多个组件依赖于统一状态;(2)来自不同组件的行为需要变更同一状态

 Vue——点击加案例(一般写法)

<template>
    <div>
        <h1>当前和是{{sum}}</h1>
        <select v-model="n">
            <option :value="1">1</option>
            <option :value="2">2</option>
            <option :value="3">3</option>
        </select>
        <button @click="increment">+</button>
        <button @click="decrement">-</button>
        <button @click="incrementOdd">当前求和为奇数再加一</button>
        <button @click="incrementWait">等一等再加</button>
    </div>
</template>
<script>
    export default{
        name:'Count',
        data(){
            return{
                n:1,
                sum:0
            }
        },
        methods:{
            increment(){
                this.sum+=this.n;
            },
            decrement(){
                this.sum-=this.n;
            },
            incrementOdd(){
                if(this.sum % 2){
                    this.sum+=this.n;
                }
            },
            incrementWait(){
                setTimeout({
                    this.sum+=this.n;
                },1000)
            },
        }
    }
</script>
<sty></style>

分析Vuex的原理

 Vue——搭建环境并使用vuex

 步骤:

index.js

//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vues'
//应用Vuex插件
Vue.use(Vuex)
//准备actions对象——响应组件中用户的动作
const actions={}
//准备mutations对象修改state中的数据
const mutations={}
//准备state对象——保存具体的数据
const state={}
//创建并暴露store
export default new Vuex.Store({
    actions,
    mutations,
    state
})

main.js中创建vm时传入store配置项

import Vue from 'vue'
import App from './App.vue'
import vueResource from 'vue-resource'
//引入store
import store from './store'
Vue.config.producation=flase
Vue.use(vueResource)
//创建vm
new Vue({
    el:'#app',
    render:h=>h(App),
    store,
    beforeCreate(){
        Vue.prototype.$bus = this
    }
})

 Vue——点击加案例(Vuex写法)

 Count.vue组件

<template>
    <div>
        <h1>当前求和为:{{$store.state.sum}}</h1>
        <select v-model.number='n'>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
        </select>
        <button @click="increment">+</button>
        <button @click="decrement">-</button>
        <button @click="incrementOdd">当前求和为奇数再加</button>
        <button @click="incrementWait">等一等再加</button>
    </div>
</template>
<script>
    export default{
        name:'Count',
        data(){
            return {
                n:1
            }
        },
        methods:{
            increment(){
                this.$store.commit('jia',this.n)   //不用经过处理的数据,直接跳过action
            },
            decrement(){
                this.$store.commit('jian',this.n)   //不用经过处理的数据,直接跳过action
            },
            incrementOdd(){
                this.$store.dispatch('jiaOdd',this.n)
            },
            incrementWait(){
                this.$store.dispatch('jiaWait',this.n)
            },
        },
        mounted(){

        }
    }
</script>
<style></style>

 index.js:

import Vue from 'vue'
import Vuex from 'vues'
Vue.use(Vuex)
const actions = {      //准备action——用于响应组件中的动作
    jia(context,value){       //函数的简写:jia:function(){}  ; context译为上下文
        console.log('actions中的jia被调用了')
        context.commit('JIA',value)
    },
    jian(context,value){
        console.log('actions中的jian被调用了')
        context.commit('JIAN',value)
    },
    jiaOdd(context,value){
        console.log('actions中的jiaOdd被调用了')
        if(context.state.sum % 2){
            context.commit('JIA',value)
        }
    },
    jiaWait(context,value){
        console.log("actions中的jiaOdd被调用了")
        setTimeout(()=>{
            context.commit('JIA',value)
        },1000)
    }
},
const mutations={
    JIA(state,value){
        console.log('mutations中的JIA被调用了')
        state.sum+=value
    },
    JIAN(state,value){
        console.log('mutations中的JIA被调用了')
        state.sum-=value
    },
},
//初始化数据
const state={
    sum:0
},

//创建并暴露store
export default new Vues.Store({
    actions,
    mutations,
    state,
})

 小结:

(1)组件中读取Vuex中的数据: 

(2)组件中修改vuex中的数据:

 备注:

Vue——getters配置项

一、概念:当state中的数据需要经过加工后再使用时,可以使用getters加工;

index.js文件中

import Vue from 'vue'
import Vuex from 'vues'
Vue.use(Vuex)
................
const actions={}
const mutations={}
const state={
    sum=0
}
......
const getters={
    bigSum(state){
        return state.sum*10
    }
}
export default new Vuex.Store({
    actions,
    mutations,
    state,
    getters
})

Count.vue组件中

<template>
    <div>
        <h1>当前值和为:{{$store.state.sum}}</h1>
        <h3>当前求和放大十倍为:{{$store.getters.bigSum}}</h3>
        .......
    </div>
</template>
<script>
    export default{
        name:'Count',
        .......
        methods:{
            increment(){
                this.$store.commit('jia',this.n)   //不用经过处理的数据,直接跳过action
            },
            decrement(){
                this.$store.commit('jian',this.n)   //不用经过处理的数据,直接跳过action
            },
            incrementOdd(){
                this.$store.dispatch('jiaOdd',this.n)
            },
            incrementWait(){
                this.$store.dispatch('jiaWait',this.n)
            },
        },
        mounted(){
            console.log('Count',this.$store)
        }
    }
</script>
<style></style>

    Vue——mapState和mapGetters优化computed计算属性

"...":es6把...后边的展开。

<template>
    <div>
        <h1>当前值和为:{{$store.state.sum}}</h1>
        <h3>当前求和放大十倍为:{{$store.getters.bigSum}}</h3>
        .......
    </div>
</template>
<script>
    import  {mapState,mapGetters} from "vues"
    export default{
        name:'Count',
        data(){},
        computed:{
    靠程序员自己写计算属性
            sum(){
                return this.$store.state.sum
            },
            school(){
                return this.$store.state.school
            },
            subject(){
                return this.$store.state.subject
            },
            --------------------------------
           借助mapState生成计算器,从state中读取数据:对象写法
            ...mapState({sum:'sum',school:'school',subject:'subject'})
            数组写法,当属性名和计算时名相同时
            ...masState(['sum','school','subject'])


            借助mapGetters生成计算器,从getters中读取属性:对象写法
            ...mapGetter({bigSum:'bigSum'})
            数组写法,当属性名和计算时名相同时
            ...mapGetter(['bigSum'])
        },
        methods:{}
    }
</script>
<style></style>

小结:

 Vue——mapMutations与mapActions优化methods方法

Count.vue组件:

mapMutations生成对应方法:

<template>
    <div>
        <h1>当前值和为:{{$store.state.sum}}</h1>
        <h3>当前求和放大十倍为:{{$store.getters.bigSum}}</h3>
        .......
        <button @click="increment(n)">+</button>
        <button @click="decrement(n)">-</button>
        <button @click="incrementOdd(n)">当前求和为奇数再加</button>
        <button @click="incrementWait(n)">等一等再加</button>
    </div>
</template>
<script>
    import  {mapMutations} from "vues"
    export default{
        name:'Count',
        data(){},
        computed:{}
        methods:{
      //靠程序员自己写计算属性 
            increment(){
                this.$store.commit('JIA',this.n)
            },
            decrement(){
                this.$store.commit('JIAN',this.n)
            }
        -------------------------------
        //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations:对象写法
            ...mapMutations({increment:'JIA',decrement:'JIAN'}),
    
          //借助mapMutations生成对应的方法,方法会调用commit去联系mutations:数组写法
            ...mapMutations({'JIA','JIAN'})
        }
    }
</script>
<style></style>

mapActions生成对应方法:

<template>
    <div>
        <h1>当前值和为:{{$store.state.sum}}</h1>
        <h3>当前求和放大十倍为:{{$store.getters.bigSum}}</h3>
        .......
        <button @click="increment(n)">+</button>
        <button @click="decrement(n)">-</button>
        <button @click="incrementOdd(n)">当前求和为奇数再加</button>
        <button @click="incrementWait(n)">等一等再加</button>
    </div>
</template>
<script>
    import  {mapActions} from "vues"
    export default{
        name:'Count',
        data(){},
        computed:{}
        methods:{
      //靠程序员自己写计算属性 
            increment(){
                this.$store.dispatch('JIA',this.n)
            },
            decrement(){
                this.$store.dispatch('JIAN',this.n)
            }
        -------------------------------
        //借助mapMutations生成对应的方法,方法中会调用dispatch去联系actions:对象写法
            ...mapActions({increment:'JIA',decrement:'JIAN'}),
    
          //借助mapMutations生成对应的方法,方法会调用dispatch去联系actions:数组写法
            ...mapActions({'JIA','JIAN'})  
        
            
        }
    }
</script>
<style></style>

小结:

 注意:使用

 如果需要传递参数,在模板中绑定事件时,就需要传递阐参数,否则参数是默认事件对象(单击,鼠标移动...)

 Vue——多组件共享

 person.vue

<template>
    <h2>人员列表组件</h2>
    <h3>Count组件的和为:{{sum}}</h3>
    <div>
        <input type = 'text' placeholder="请输入姓名" v-model="name">
        <button @click="add">添加</button>
        <ul>
            <li v-for"p in personList" :key="p.id">{p.name}</li>
        </ul>
    </div>
</template>
<script>
    import {nanoid} from 'nanoid'
     export default{
        name:'Person',
        computed:{
            personList(){    //程序员自己写代码,计算属性
                return this.$store.state.personList
            },
            sum(){
                return this.$store.state.sum
            }
        },
        data(){
            return{
                name:''
            }
        },
        methods:{
            add(){
                const personOjb = {id:nanoid(),name:this.name}
                this.$store.commit('ADD_PERSon',personObj)
                this.name=""
            }
        }
     }
-------------------------------------
    import {mapState} from 'vuex'
    export default{
        name:'Person',
        computed:{   //通过引入vuex的mapState计算属性
            ...mapState(['personList'])          数组方式
        }
    }
</script>
<style></style>

 Count.vue组件

<template>
    <div>
        <h1>当前求和为:{{$store.state.sum}}</h1>
        <h3>当前值放大十倍是:{{bigSum}}</h3>
        <h3>我在{{school}},学习{{subject}}</h3>
        <h3>person组件的总人数是:{{personList.length}}</h3>
        <select v-model.number='n'>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
        </select>
        <button @click="increment">+</button>
        <button @click="decrement">-</button>
        <button @click="incrementOdd">当前求和为奇数再加</button>
        <button @click="incrementWait">等一等再加</button>
    </div>
</template>
<script>
    import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
    export default{
        name:'Count',
        data(){
            return{
                n:1,
            }
        },
        computed:{
            ...mapState(['sum','school','subject','personList']),
            ...mapGetters(['bigSum'])
        }
        methods{
            ...mapMutations({increment:'JIA',decrement:'JIAN'}),
            ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
        }
    }
</script>
<style></style>

index.js中配置数据

import Vue from 'vue'
import Vuex from 'vux'
Vue.use(Vuex)
const actions={}
const mutations={
    ......
    ADD_PERSON(state,personObj){
        console.log('mutations中的ADD_PERSON被调用了')
        state.personList.unshift()
    }
}
const state={
    sum:0,
    school:'尚硅谷',
    subject:'前端',
    personList:[
        {id:'001',name:'张三'}
    ]
}
const getters={}
export default{
    actions,
    mutations,
    state,
    getters
}

Vue——vuex模板化+namespace

小结:

 

Vue——路由(vue-router)

 一、定义:是vue的一个插件库,专门用来实现SPA应用。

二、对SPA应用的理解:

1、单页Web应用(SPA)

2、整个应用只有一个完整的页面(index.html)

3、点击页面中的导航链接不会刷新页面,只会做页面的据不更新。

4、数据需要通过Ajax获取。

三、路由的理解

1、什么是路由?

        (1)一个路由就是一组映射关系(key-value)

        (2)key为路径,value可能是function或者component

2、路由分类:

        (1)后端路由:

                理解:value是function,用于处理客户端提交的请求。

               工作过程:服务器接收到一个请求时,根据请求路径找到匹配的函数来处理请求,返回相应数据。

        (2)前端路由:

        理解:value是component,用于展示页面内容。

        工作过程:当浏览器的路径改变时,对应的组件就会显示。

 基本路由切换案例

 Home.vue组件

<template>
    <h2>我是HOME内容</h2>
</template>
<script>
    export default{
        name:'Home'
    }
</script>

About.vue组件

<template>
    <h2>我是ABOUT内容</h2>
</template>
<script>
    export default{
        name:'About'
    }
</script>

 App.vue组件

<template>
    <div>
    .......
        <div class='row'>
            <div class="">
                <div class="list-group">
                    原始的html中我们使用a标签实现页面的跳转
                    <a class="list-group-item active" href="./about.html">About</a>
                    <a class="list-group-item" href="./home.html">Home</a>
            -----------------------------------------------
      //           Vue中借助router-link实现组件切换 
                    <router-link class="list-group-item" active-class="active" to="/about">About</router-link>
                    <router-link class="list-group-item" active-class="active" to="/home">Home</router-link>
                </div>
            </div>
            <div class="clo-xs-6">
                <div class="pannel">
                    <div class="pannel-body">
                        <router-view></router-view>   //路由器视图,指定组件呈现位置
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>
<><>

main.js

import Vue from 'vue'
import App from './App.vue'

引入VueRouter路由器
import VueRounter from 'vue-router'

引入路由器
import router from './router/index'  //index文件可以省略
Vue.config.productionTip=false;
Vue.use(VueRouter)
new Vue({
    el:'#app',
    render:h=>h(App),
    router:router
})

router文件夹中创建index.js,这个文件夹专门用来创建整个应用的路由器:

引入VueRouter
import VueRounter from 'vue-router'

引入路由组件
import About from './components/About'
import Home From './components/Home'
//创建并暴露一个人路由器
export default router = new VueRouter({
    routes:[   //路由器里边的路由
        {
            path:'/about',
            component:About
        },
        {
            path:'/home',
            component:Home
        }
    ]
})

小结:

1、安装vue-router,命令:npm i vue-router

2、应用插件:

3、编写router配置项:

 

Vue——使用路由(router)的几个注意点

路由中分为:路由组件、一般组件

根据使用方式区分:利用路由器来调用的组件为路由组件;通过我们自己用组件标签调用的为一般组件。

小结

1、路由组件通常存放在pages文件夹,一般组件通常存放在components文件夹。

2、通过切换,“隐藏了”的路由组件,默认是贝销毁的,需要使用时候再挂载。

3、每个组件都有自己的$route属性,里面存储着自己的路由信息。

4、整个应用只有一个$router,可以通过组件的$router属性获取到。

 Vue——嵌套(多级)路由

 Home组件

<template>
    <h2>Home组件内容</h2>
    <div>
        <ul class="nav nav-tabs">
            <li>
                <router-link class="list-group-item"active-class="active" to="/home/news">News</a>
            </li>
            <li>
                <router-link class="list-group-item"active-class="active" to="/home/message">Message</a>
            </li>
        </ul>
        
    </div>
</template>
<script>

</script>
<style></style>

message.vue组件

<template>
    <div>
        <ul class="nav nav-tabs">
            <li>
                <a href="/message1">message001</a> $nbsp;$nbsp;
            </li>
            <li>
                <a href="/message2">message002</a> $nbsp;$nbsp;
            </li>
            <li>
                <a href="/message3">message002</a> $nbsp;$nbsp;
            </li>
        </ul>
    </div>
</template>
<script>
    export default{
        name:'Message'
        
    }
</script>
<style></style>

news.vue组件

<template>
    <ul>
        <li>new001</li>
        <li>new002</li>
        <li>new003</li>
    </ul>
<template>
<script>
    export default{
        name:'News',

    }
</script>
<style></style>

index.js创建路由规则

import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'

export default new VueRouter({
    routes:[
        {
            path:'/about',
            component:About
        },
        {
            path:'/home',
            component:Home,
            children:[
                {
                path:'news',
                component:News,
                }
            ]
        }
    ]
})

小结:

1、多级路由规则,使用children配置项:

 2、跳转(要写完整路径)

 Vue——路由的传参

 Detail.vue组件

<template>
    <ul>
        <li>消息编号:{{$route.query.id}}</li>
        <li>消息标题{{$route.query.title}}</li>
    </ul>
</template>
<script>
    export default{
        name:'Detail',
        mounted(){
            console.log(this.$route)
        }
    }
</script>

message.vue组件

<template>
    <div>
        <ul>
            <li v-for="m in messageList" :key="m.id">
                //跳转路由并携带query参数,to的字符串写法:
                <router-link :to="`home/message/detail?id=${m,id}&title=${m.title}`"></router-link>&nbsp;&nbsp
                
                //跳转路由并携带query参数,to的对象写法
                <router-link :to="{
                    path:'/home/message/detail',
                    query:{
                        id:m.id,
                        title:m.title
                    }
                }">{{m.title}}</router-link>
            </li>
        </ul>
        <router-view></router-view>
    </div>
</template>
<script>
    export default{
        return{
            messageList:[
                {id:'001',title:'消息一'},
                {id:'002',title:'消息二'},
                {id:'003',title:'消息三'},
            ]
        }
    }
</script>
<style></style>

配置index.js路由规则

import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Detail from '../pages/Detail'
export default new VueRouter({
    routes:[
        {
            path:'/about',
            component:About
        },
        {
            path:'/home',
            component:Home,
            children:[
                {
                path:'news',
                component:News,
                children:[
                    path:'detail',
                    component:Detail
                 ]
                }
            ]
        }
    ]
})

小结:

  Vue——命名+-路由

 作用:可以简化路由的跳转。

如何使用

1、给路由命名:

 2、简化跳转:

Vue——路由的params参数

 1、配置路由,声明接收params参数

2、传递参数

  注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!

3、接收参数

Vue——路由的props配置

router文件夹中index.js配置规则

import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Detail from '../pages/Detail'
export default new VueRouter({
    routes:[
        {
            path:'/about',
            component:About
        },
        {
            path:'/home',
            component:Home,
            children:[
                {
                path:'news',
                component:News,
                children:[
                    name:"命名路由",
                    path:'detail/:id/:title',
                    component:Detail,
            ----------------------------------------
       props的第一种写法,值为对象,
        该对象中的所有的key-value都会以props的形式传给Detail组件(只能传递固定值)
                    props:{a:1,b:'zujian'}
            -----------------------------------
        props第二种写法,值为布尔值,
        如果为真,就会把该路由组件中收到的所有params参数,以props的形式传给Detail组件。
                    props:true
                 ]
                }
               ---------------------------------------
        props第三种写法,值为函数,
                props($route){
                    return {
                        id:$route.query.id,
                        title:$route.query.title
                    }
                }
            ]
        }
    ]
})

Detail.vue组件中

<template>
    <ul>
        <li>消息编号:{{id}}</li>
        <li>消息标题:{{title}}</li>
        <li>{{a}}</li>
        <li>{{b}}</li>
    </ul>
</template>
<script>
    export default{
        name:'Detail',
    -------------------------------第一种写法
        props:['a','b']
        computed:{
            id(){
                return this.$route.params.id
            },
            title(){
                return this.$route.params.title
            },
        },
        ---------------------------第二种写法
            props:['id','title']
        --------------------------------第三种写法
            props:['id','title']
    }
</script>
<style></style>

小结:

  Vue——router-link的replace属性

小结:

 Vue——编程时路由导航

 messageList组件

<template>
    <div>
        <ul>
            <li v-for="m in messageList" :key="m.id">
                <router-link :to="{
                    name:'',
                    query:{
                        id:m.id,
                        title:m.title
                    }
                }">{{m.title}}</router-link>
                <button @click='pushShow(m)'>push查看</button>
                <button @click='replaceShow(m)'>replace查看</button>
            </li>
        </ul>
    </div>
</template>
<script>
    export default{
        name:'Message',
        data(){ 
        },
        methods:{
            pushShow(){     //记录每次跳转的记录,回退逐个回退
                this.$router.push({
                    name:'xiangqing',
                    query:{
                        id:m.id,
                        title:m.title
                    }
                })
            },
            replaceShow(m){       //销毁上一次的记录,
                this.$router.replace({
                    name:'xiangqing',
                    query:{
                        id:m.id,
                        title:m.title
                    }
                })
            }
        }
    }
</script>
<style>

</style>
<template>
    <div class="col-xs-offset-2">
        <div class="page-header">
            <button @click="back">后退</button>
            <button @click="forward">前进</button>
            <button @click="go">根据数字正值前进,负值后退</button>
        </div>
    </div>
</template>
<script>
    export default{
        name:'Banner',
        methods:{
            back(){
                this.$router.back()
            }
            forward(){
                this.$router.forward()
            }
            go(){
                this.$router.go(2) //前进两步记录

            }
        }
    }
</script>
<style></style>

Vue——缓存路由组件

<template>
    <div>
        <h2>Home组件内容</h2>
        <div>
            <ul>
                <li>
                    <router-link class="list-group-item" active-class="active" to="/home/news">News</router-link>
                </li>
                <li>
                    <router-link class="list-group-item" active-class="active" to="/home/Message">Message</router-link>
                </li>
            </ul>
            <keep-alive include="News">     指定缓存的组件名
                <router-view></router-view>
            </keep-alive>
        </div>
    </div>
</template>
<script>
    export default{
        name:'Home'
     }
</script>
<style></style>

小结:

 当需要保持多个缓存组件时,可以在通过绑定include数组:

Vue——两个新的生命周期钩子

 1、作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。

2、具体名字:

        (1)activated路由组件被激活时触发

        (2)deactivated路由组件失活时触发

<template>
    <ul>
        <li :style="{opacity}">透明度变化动画</li>
        <li>new001</li>
        <li>new002</li>
        <li>new003</li>
    </ul>
<template>
<script>
    export default{
        name:'News',
        data(){
            return{
                opacity:1
            }
        },
        activated(){
            console.log("News组件被激活了")
            this.timer = setInterval(()=>{
                this.opacity-=0.01
                if(this.opacity <= 0) this.opacity=1
            },100)
        },
        deactivated(){
            console.log("News组件失活了")
            clearInterval(this.timer)
        }
    }
</script>
<style></style>

Vue——全局前置-路由守卫

 路由规则index.js文件

import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Detail from '../pages/Detail'
export default new VueRouter({
    routes:[
        {
            path:'/about',
            component:About
        },
        {
            path:'/home',
            component:Home,
            children:[
                {
                path:'news',
                component:News,
                children:[
                    path:'detail',
                    component:Detail

                    props($route){
                    return {
                        id:$route.query.id,
                        title:$route.query.title
                    }
                 ]
                }
            ]
        }
    ]
})
router.deforeEach((to,from,next)=>{  //全局前置路由守卫 ——初始化的时候被调用,每次路由切换之前被调用
    //to:前往的地址;
    //from:来自的地址;
    //next:是否允许放行
    if(to.path==='/home/news' || to.path==='/homemessage'){
        if(localStorage.getItem('school')==='atguigu'){
        next()
        }else{
            alert("学校名称不对,无权限")
        }
    }else{
        next()
    }
})

全局后置——路由守卫

import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Detail from '../pages/Detail'
export default new VueRouter({
    routes:[
        {
            path:'/about',
            component:About,
            meta:{title:'关于'}
        },
        {
            path:'/home',
            component:Home,
            meta:{title:'标题'}
            children:[
                {
                path:'news',
                component:News,
                meta:{isAuth:true}
                children:[
                    path:'detail',
                    component:Detail

                    props($route){
                    return {
                        id:$route.query.id,
                        title:$route.query.title
                    }
                 ]
                }
            ]
        }
    ]
})
router.deforeEach((to,from,next)=>{  全局前置路由守卫 ——初始化的时候被调用,每次路由切换之前被调用
    //to:前往的地址;
    //from:来自的地址;
    //next:是否允许放行
    if(to.meta.isAuth){   //判断是否需要鉴权
        if(localStorage.getItem('school')==='atguigu'){
        next()
        }else{
            alert("学校名称不对,无权限")
        }
    }else{
        next()
    }
})

全局后置路由守卫 ——初始化的时候被调用,每次路由切换之后被调用
router.afterEach((to,from)=>{
    console.log("后置路由守卫")
    if(to.meta.title){
        document.title=to.meta.title  //修改网页的title
    }else{
        document.title="默认标题"
    }
    
})

Vue——独享路由守卫

import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Detail from '../pages/Detail'
export default new VueRouter({
    routes:[
        {
            path:'/about',
            component:About,
            meta:{title:'关于'}
        },
        {
            path:'/home',
            component:Home,
            meta:{title:'标题'}
            children:[
                {
                path:'news',
                component:News,
                meta:{isAuth:true,}
     
                beforeEnter:()=>{        独享守卫
                   console.log("独享守卫",to,from)
                    if(to.meta.isAuth){
                        if(localStorage.getItem('school')==='atguigu'){
                           next()
                        }else{
                            alert("学校名不对,无权限")
                        }    
                    }else{
                        next
                    } 
                }
                children:[
                    path:'detail',
                    component:Detail

                    props($route){
                    return {
                        id:$route.query.id,
                        title:$route.query.title
                    }
                 ]
                }
            ]
        }
    ]
})
全局后置路由守卫 ——初始化的时候被调用,每次路由切换之后被调用
router.afterEach((to,from)=>{
    console.log("后置路由守卫")
    if(to.meta.title){
        document.title=to.meta.title  //修改网页的title
    }else{
        document.title="默认标题"
    }
    
})

 Vue——组件间守卫

import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Detail from '../pages/Detail'
export default new VueRouter({
    routes:[
        {
            path:'/about',
            component:About,
            meta:{isAuth:true,title:'关于'}
        },
        {
            path:'/home',
            component:Home,
            meta:{isAuth:true,title:'标题'}
            children:[
                {
                path:'news',
                component:News,
                meta:{isAuth:true}
                children:[
                    path:'detail',
                    component:Detail
                    props($route){
                    return {
                        id:$route.query.id,
                        title:$route.query.title
                    }
                 ]
                }
            ]
        }
    ]
})

About.vue组件 

<template>
    <h2>我是ABOUT内容</h2>
</template>
<script>
    export default{
        name:'About'
        mounted(){
            console.log('@@@',this.$route)
        },
        beforeRouteEnter(to,from,next){
            console.log("组件间路由守卫")
            if(to.meta.isAuth){
                if(localStorage.getItem('school')=="atguigu"){
                    next()
                }else{
                    alert("学校名称不对,无权限访问")
                }
            }else{
                next()
            }
        },
        beforeRouterLeave(to,from,next){
            next()
        }
    }
</script>

小结:路由守卫

1、作用:对路由进行权限控制

2、分类:全局守卫,独享守卫,组件守卫

3、全局守卫:

 4、独享守卫:

 5、组件内路由守卫

Vue——hash与history

Vue——UI组件库

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值