Vue笔记(B站视频)

ES6语法

**var:**没有作用域的概念(尽量不要用)

**let:**有作用域的概念,声明变量

**const:**声明常量

1、一旦给const修饰的标识符被赋值之后,不能修改

2、在使用const定义标识符,必须进行赋值

3、常量的含义是指向的对象不能修改,但是可以修改对象里的内容

ES6对象增强写法

<script>
    const name = 'aaa';
	const age = 18;
    const height = 183;
    const obj = {
        name,
        age,
        height,
    }
    
</script>

ES6方法增强写法

<script>
    //ES5
    getList: function(){
        ...
    }
    //ES6
    getList(){
        ...
    }
</script>

for循环的三种方式

<script>
  //1、原生方式
  for(let i = 0; i < this.books.length; i++){
    totalPrice += this.books[i].price * this.books[i].count;
  }
  //2、取下标
  for(let i in this.books){
    totalPrice += this.books[i].price * this.books[i].count;
  }
  //3、取对象
  for(let item of this.books){
    totalPrice += item.price *item.count;
  }
</script>

高级函数

filter

<script>
  const nums = [10, 20, 111, 123, 145];
  let newNums = nums.filter(function(n){
    return n < 100;
  })
  console.log(newNums); //[10, 20]
</script>

相当于遍历数组,之后又一个回调函数,这个回调函数返回的是布尔值,当为true的时候,就会把当前元素加入到新的数组内,false时,函数会过滤掉这次的元素。

map

<script>
	const nums = [10, 20, 30];
  
  let newNums = nums.map(function(n){
    return n*2;
  })
  console.log(newNums);//[20, 40, 60]
</script>

道理与filter相同,也是回调函数,之后利用每次的返回值,组成新的数组

reduce

<script>
	const nums = [10, 20, 30];
  let total = nums.reduce(function(preValue, n){
    return preValue + n;
  },0)
  console.log(total); //60
</script>

主要作用是对数组中所有内容进行汇总

reduce一共需要两个参数,一个是回调方法,另一个参数是对preValue进行初始化的值

以上的例子一共需要执行三次:

1、preValue = 0;n = 10;

2、preValue = 10;n = 20;

3、preValue = 30;n = 30;

preValue = 60;

例子:

需求:找出数组内小于100的元素,进行乘以二的操作,之后得到数组的相加的结果

<script>
	const nums = [10, 20, 111, 222, 444, 40, 50];
	let total = nums.filter(function(n){
    return n < 100;
  }).map(function(){
    return n * 2;
  }).reduce(function(preValue, n){
    return preValue + n;
  },0)
  //箭头函数
  let total = nums.filter(n => n < 100).map(n => n * 2).reduce((pre, n) => pre + n);
</script>

el属性:该属性决定了这个Vue对象挂载到哪一个元素上

data属性:该属性存储一些数据

<body>
    <div id="app">
        <h1>{{message}}</h1>
        <h2>{{name}}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',//用于挂载要管理的元素
            data: { //定义数据
                message: 'Hello, World!',
                name: '韩帅'
            }
        }) 
    </script>
</body>

列表展示

v-for:循环movies,进行遍历展示

<body>
    <div id="app">
        <li v-for="item in movies">{{item}}</li>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: 'Hello, World!',
                movies: ['王一','王二','王三']
            }
        })
    </script>
</body>

计数器

@click:语法糖

v-on:click=“counter–”:直接对属性进行操作

v-on:click=“add”:绑定点击事件,在Vue对象内定义methods属性

<body>
    <div id="app">
        <h2>当前计数:{{counter}}</h2>
        <!-- <button v-on:click="counter--">-</button> -->
        <!-- <button v-on:click="counter++">+</button> -->
        <button v-on:click="add">+</button>
        <button @click="sub">-</button>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                counter: 0
            },
            methods: {
                add: function(){
                    console.log("add被执行!");
                    this.counter++;
                },
                sub: function(){
                    console.log("sub被执行!");
                    this.counter--;
                },
            }
        })
    </script>
</body>

创建Vue实例传入的options

el:

  • 类型: String | HTMLElement
  • 作用: 决定之后Vue实力会管理哪一个DOM

data:

  • 类型: Object | Function(组件当中data必须是一个函数)
  • 作用: Vue实力对应的数据对象

methods:

  • 类型: {[key:string]:Function}
  • 作用:定义属于Vue的一些方法,可以在其他地方调用,也可以在指令中使用

函数:直接定义的叫做函数

方法:定义在类里面的叫做方法

基础语法

1、插值操作

Mustache语法(也就是双大括号)

可以做一些基本的表达式操作

<body>
    <div id="app">
        <h1>{{message}}</h1><!-- Hello, World! -->
        <h1>{{message}},可以加文本</h1><!-- Hello, World!,可以加文本 -->
        <h1>{{lastName + firstName}}</h1><!-- 韩帅 -->
        <h1>{{lastName +' '+ firstName}}</h1><!-- 韩 帅 -->
        <h1>{{lastName}}  {{firstName}}</h1><!-- 韩 帅 -->
        <h1>{{counter*2}}</h1><!-- 200 -->
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: 'Hello, World!',
                firstName: '帅',
                lastName: '韩',
                counter: 100
            }
        })
    </script>
</body>

**v-once:**vue为响应式编程,当值发生改变时页面会自动进行改变,使用v-once,就是不论值怎么改变,页面显示不变

<body>
    <div id="app">
        <h1>{{message}}</h1><!-- 会随着message的改变而改变 -->
        <h1 v-once>{{message}}</h1><!-- 不会随着message的改变而改变 -->
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: 'Hello, World!'
            }            
        })
    </script> 
</body>

**v-html:**渲染url地址

<body>
    <div id="app">
        <h1>{{url}}</h1><!-- <a href="http://www.baidu.com">百度一下</a> -->
        <h1 v-html="url">{{url}}</h1><!-- 百度一下 -->
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                url: '<a href="http://www.baidu.com">百度一下</a>'
            }
        })
    </script>
</body>

**v-text:**与双大括号作用相同,但是不灵活,不能做拼接,使用较少

<body>
    <div id="app">
        <h1>{{message}},cc</h1><!-- Hello, World!,cc -->
        <h1 v-text="message">,cc</h1><!-- Hello, World! --><!-- 会直接覆盖掉原来的,cc -->
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: 'Hello, World!',
            }
        })
    </script>
</body>

**v-pre:**相当于转义字符,就是让双大括号不进行解析

<body>
    <div id="app">
        <h1>{{message}}</h1><!-- Hello, World! -->
        <h1 v-pre>{{message}}</h1><!-- {{message}} -->
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: 'Hello, World!',
            }
        })
    </script>
</body>

**v-cloak:**页面解析的时候先解析div内的内容,这个时候代码卡住了,页面显示的就是message,vue的渲染并没有生效,加上v-cloak这个属性,并给他个none的样式,这样卡住的话就不会显示了,当vue去解析的时候,会自动去掉这个v-cloak属性。

 <head>
 	<style>
        [v-cloak] {
            display: none;
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>{{message}}</h1><!-- Hello, World! -->
        <h1 v-cloak>{{message}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        setTimeout(function(){
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'Hello, World!',
                }
            })
        }, 1000)
        
    </script>
</body>

2、动态绑定

1、基本使用

绑定主要是绑定属性

比如动态绑定a元素的href属性

比如动态绑定img元素的src属性

属性内不能直接用mustache语法

v-bind:src 语法糖写法 :src

<body>
    <div id="app">
        <!-- 错误的写法,这里不能用mustache语法 -->
        <!-- <img src="{{url}}"></img> -->
        <img v-bind:src="imgurl">
        <a v-bind:href="ahref">百度一下</a>
        <!-- 语法糖的写法 -->
        <img :src="imgurl">
        <a :href="ahref">百度一下</a>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: 'Hello, World!',
                imgurl: 'https://image.baidu.com/search/detail',
                ahref: 'http://www.baidu.com'
            }
        })
    </script>
</body>

2、动态绑定class

1、对象语法
<body>
    <div id="app">
       <!-- 直接通过style进行绑定class -->
        <h1 class="active">{{message}}</h1>
        <!-- 通过Vue对象去找到style进行绑定class -->
        <h1 :class="active">{{message}}</h1>
        
        <!-- 传入对象key:value形式,active为style,isActive由Vue对象控制,传入true或false -->
        <!-- true则样式生效,false不生效 -->
        <h1 :class="{active: isActive,line: isLine}">{{message}}</h1>
        
         <!-- 如果对象属性太多,可以在Vue对象内定义成方法,之后直接调用方法就可以 -->
        <h1 :class="getClasses()">{{message}}</h1>
        <button v-on:click="btnClick">按钮</button>
        
         <!-- 还可以再加class属性,后边都为true的话,三个class都会生效 -->
        <h1 class="title" :class="{active: isActive,line: isLine}">{{message}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: 'Hello, World!',
                active: 'active',
                isActive: false,
                isLine: true,
            },
            methods: {
                btnClick:function(){
                    this.isActive = !this.isActive
                    this.isLine = !this.isLine
                },
                getClasses: function(){
                    //注意要加this  this.isActive  this.isLine
                    return {active: this.isActive,line: this.isLine}
                }
            }
        })
    </script>
</body>

对象语法:

1、直接通过{}绑定一个类(isActive由Vue对象控制true或false)

<h1 :class="{active: isActive}">{{message}}</h1>

2、也可以通过判断,传入多个值

<h1 :class="{active: isActive,line: isLine}">{{message}}</h1>

3、和普通类同时存在,并不冲突。注:如果isActive、isLine都为true,那么会有三个class title、active、line

<h1 class="title" :class="{active: isActive,line: isLine}">{{message}}</h1>

4、如果过于复杂,可以放在一个method或者computed中

<h1 class="title" :class="getClasses()">{{message}}</h1>
2、数组语法

与对象语法写法类似,但是不能动态控制

<body>
    <div id="app">
        <h1 :class="[active, line]">{{message}}</h1>
        <h1 :class="getClasses()">{{message}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: 'Hello, World!',
                active: 'aaa',
                line: 'bbb'
            },
            methods: {
                getClasses: function(){
                    return [this.active, this.line]
                }
            }
        })
    </script>
</body>

3、动态绑定style

1、对象语法

与绑定class类似

<body>
    <div id="app">
        <h1 :style="{fontSize: fontSize, color: color}">{{message}}</h1>
        <h1 :style="getStyle()">{{message}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: 'Hello, World!',
                fontSize: '100px',
                color: 'green',
            },
            methods: {
                getStyle: function(){
                    return {fontSize: this.fontSize, color: this.color}
                }
            }
        })
    </script>
</body>
2、数组语法
<body>
    <div id="app">
        <h1 :style="[style1, style2]">{{message}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: 'Hello, World!',
                style1: {fontSize: '100px'},
                style2: {color: 'green'},
            }
        })
    </script>
</body>

3、计算属性

1、基本使用

**computed:**为定义计算属性的关键字,在Vue对象内定义,对属性值进行一些操作

<body>
    <div id="app">
        <h1>{{lastName + ' ' + firstName}}</h1>
        <h1>{{lastName}}   {{firstName}}</h1>
        <h1>{{getFullName()}}</h1>
        <h1>{{fullName}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                firstName: 'shuai',
                lastName: 'han',
            },
            computed:{
                fullName: function(){
                    return this.lastName + ' ' + this.firstName
                }
            },
            methods: {
                getFullName: function(){
                    return this.lastName + ' ' + this.firstName
                }
            }
        })
    </script>
</body>

2、复杂操作

在computed内计算好之后,界面直接取值

<body>
    <div id="app">
        <h1>总价格:{{totalPrice}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                books: [
                    {id: 100, name: '王一', price: 185},
                    {id: 101, name: '王二', price: 123},
                    {id: 102, name: '王三', price: 165},
                    {id: 103, name: '王四', price: 112},
                    {id: 104, name: '王五', price: 154},
                ]
            },
            computed:{
                totalPrice: function(){
                    let result = 0;
                    for(let i = 0; i < this.books.length; i++){
                        result += this.books[0].price;
                    }
                    return result;
                }
            }
        })
    </script>
</body>

3、计算属性的getter setter方法

与java类似,就是get set方法,赋值取值,set方法一般不常用,computed相当于只读属性

<body>
    <div id="app">
        <h1>{{fullName}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                firstName: 'shuai',
                lastName: 'han'
            },
            //计算属性一般是没有set方法,是一个只读属性
            computed:{
                fullName: {
                    get: function(){
                        return this.lastName + ' ' + this.firstName
                    }
                },
                //简写(通用写法)
                fullName: function(){
                    return this.lastName + ' ' + this.firstName
                }
            }
        })
    </script>
</body>

4、computed与methods对比

<body>
    <div id="app">
        <!-- 1、直接拼接:语法过于繁琐 不建议使用 -->
        <h1>{{lastName}}  {{firstName}}</h1>
        <!-- 2、通过定义methods -->
        <h1>{{getFullName()}}</h1>
        <!-- 3、通过computed -->
        <h1>{{fullName}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                firstName: 'shuai',
                lastName: 'han'
            },
            methods: {
                getFullName(){
                    return this.lastName + ' ' + this.firstName
                }
            },
            computed:{
                fullName: function(){
                    return this.lastName + ' ' + this.firstName
                }
            }
        })
    </script>
</body>

**computed:**当一个取值取多次的时候,这个方法只会调用一次,他会监听你返回的值是否发生改变,没有改变会直接把缓存内的值返回出去,有改变重新调用

**methods:**每取值一次调用一次方法,效率相对较低

4、事件监听

1、基本使用

v-on:click 语法糖写法 @click

<body>
    <div id="app">
        <h1>{{counter}}</h1>
        <button v-on:click="counter++">+</button>
        <button v-on:click="counter--">-</button>
        <button v-on:click="add()">+</button>
        <button v-on:click="subtract()">-</button>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                counter: 0
            },
            methods: {
                add(){
                    this.counter++
                },
                subtract(){
                    this.counter--
                }
            }
        })
    </script>
</body>

2、参数问题

<body>
    <div id="app">
        <button @click="btn1Click()">按钮1</button><!-- btnClick -->
        <button @click="btn1Click">按钮2</button><!-- btnClick -->

        <!-- 在事件定义时,写方法省略了小括号,但是方法本身需要一个参数,
        这个时候Vue会默认将浏览器生产的event事件对象作为参数传入到方法 -->
        <button @click="btn2Click">按钮3</button><!-- event对象 -->
        <button @click="btn2Click(10)">按钮4</button><!-- 10 -->
        
        <!-- 在方法定义是,我们需要event对象,同时又需要其他参数 -->
        <!-- 在调用方法时,手动获取浏览器参数的event对象:$event -->
        <button @click="btn3Click">按钮5</button><!-- event对象undefind -->
        <button @click="btn3Click(123, $event)">按钮5</button><!-- 123event对象 -->
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: 'Hello, World!'
            },
            methods: {
                btn1Click(){
                    console.log("btnClick");
                },
                btn2Click(num){
                    console.log("-------" + num);
                },
                btn3Click(num, event){
                    console.log("+++++++" + num + event);
                },
            }
        })
    </script>
</body>

3、修饰符

<body>
    <div id="app">
        <!-- .stop修饰符的使用,阻止冒泡 -->
        <div @click="divClick()">
            aaa
            <button @click.stop="btnClick()">按钮1</button>
        </div>
        
        <!-- .prevent修饰符的使用,阻止默认事件,注:以下type="submit" 点击提交之后会自动提交 -->
        <form action="baidu">
            <input type="submit" value="提交" @click.prevent="submitClick()">
        </form>

        <!-- 监听键盘键的点击 keyup:监听键盘抬起的事件与click性质类似-->
        <!-- .enter敲回车会触发的事件 -->
        <input type="text" @keyup.enter="keyup()">

        <!-- 只能触发一次 once -->
        <button @click.once="once()">按钮1</button>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: 'Hello, World!'
            },
            methods: {
                btnClick(){
                    console.log("btnClick");
                },
                divClick(){
                    console.log("divClick");
                },
                submitClick(){
                    console.log("submitClick");
                },
                keyup(){
                    console.log("keyup");
                },
                once(){
                    console.log("once");
                }
            }
        })
    </script>
</body>

1、.stop修饰符的使用,阻止冒泡

2、.prevent修饰符的使用,阻止默认事件,注:以下type=“submit” 点击提交之后会自动提交

3、监听键盘键的点击 keyup:监听键盘抬起的事件与click性质类似

4、只能触发一次 once

5、条件判断

<body>
    <div id="app">
       <h1 v-if="score>=90">优秀</h1>
       <h1 v-else-if="score>=80">良好</h1>
       <h1 v-else-if="score>=60">及格</h1>
       <h1 v-else>不及格</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                score: 99,
            },
        })
    </script>
</body>

逻辑复杂的不建议在标签内判断,用计算属性来做

1、用户登录切换案例

<body>
    <div id="app">
        <span v-if="isUser">
            <label for="username">用户账号</label>
            <!-- key的作用就是给input一个唯一标识 -->
            <input type="text" id="username" placeholder="用户账号" key="username">
        </span>
        <span v-else>
            <label for="email">用户邮箱</label>
            <input type="text" id="email" placeholder="用户邮箱" key="email">
        </span>
        <button @click="isUser = !isUser">切换类型</button>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                isUser: true
            }
        })
    </script>
</body>

2、v-show

切换频率高的时候使用v-show 反之使用v-if

<body>
    <div id="app">
        <!-- 当条件为false时,包含v-if的元素,根本就不会存在dom中 -->
        <!-- 每次在true和false之间切换的时候,都是删除或者新建 -->
        <h1 v-if="isShow" id="aaa">{{message}}</h1>

        <!-- 当条件为false时,v-show只是给元素加了一个行内样式,display:none -->
        <h1 v-show="isShow" id="bbb">{{message}}</h1>
    
        <!-- 切换频率高的时候使用v-show 反之使用v-if -->
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: 'Hello, World!',
                isShow: true,
            }
        }) 
    </script>
</body>

6、循环遍历

1、v-for遍历数组

<body>
    <div id="app">
        <!-- 在遍历过程中没有使用索引值(下标值) -->
        <ul>
            <li v-for="item in names">{{item}}</li>
        </ul>

        <!-- 在遍历过程中使用索引值(下标值) -->
        <ul>
            <li v-for="(item, index) in names">{{index+1}}.{{item}}</li>
        </ul>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                names: ['wangyi', 'wanger','wangsan']
            }
        }) 
    </script>
</body>

2、v-for遍历对象

<body>
    <div id="app">
        <!-- 在遍历对象的过程中,如果只取一个值,那么获取到的是value -->
        <ul>
            <li v-for="item in info">{{item}}</li>
        </ul>

        <!-- 获取key和value 格式:(value, key) -->
        <ul>
            <li v-for="(value, key) in info">{{key}}:{{value}}</li>
        </ul>

        <!-- 获取key和value和index 格式:(value, key, index) -->
        <ul>
            <li v-for="(value, key, index) in info">{{key}}:{{value}}  {{index}}</li>
        </ul>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                info: {
                    name: '王一',
                    age: 24,
                    height: 1.88
                }
            }
        }) 
    </script>
</body>

v-for循环,给对应元素加一个key属性

<li v-for="item in info" :key="item">{{item}}</li>

往中间插入元素的时候效率会更高

3、数组中哪些方法不是响应式的

<body>
    <div id="app">
        <ul>
            <li v-for="item in name">{{item}}</li>
        </ul>
        <button @click="btnClick()">按钮</button>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                name: ['a', 'b', 'c']
            },
            methods: {
                btnClick(){
                    //1、push方法:在数组最后添加元素
                    this.name.push('aaa');
                    this.name.push('aaa','bbb','ccc');
                    
                    //2、unshift方法:在数组最前面添加元素
                    this.name.unshift('aaa');
                    this.name.unshift('aaa','bbb','ccc');
                    
                    //3、pop方法:删除数组中最后一个元素
                    this.name.pop();

                    //4、shift方法:删除数组中第一个元素
                    this.name.shift();

                    //5、splice方法:删除元素、插入元素、替换元素
                    // 这个方法一共有三个参数
                    //param1:从哪个下标开始
                    //param2:删除几个或替换几个
                    //param3:插入的新元素的值
                    
                    //删除元素
                    //不传第二个默认删除1后边的全部元素
                    this.name.splice(1);
                    //删除1后边的三个元素
                    this.name.splice(1,3);

                    //替换元素
                    //替换1后边的两个元素,替换为v b
                    this.name.splice(1,2,'v','b');

                    //插入元素
                    //在1后边加三个元素x y z
                    this.name.splice(1,0,'x','y','z');
                
                    //6、sort方法:排序
                    this.name.sort();

                    //7、reverse方法:反转
                    this.name.reverse();

                    //以上都是响应式的
                    
                    //8、注意通过索引值修改数组中的元素不是响应式的
                    this.name[0] = 'dd';
                }
            }
        }) 
    </script>
</body>

7、v-model

1、v-model基本使用

<body>
    <div id="app">
        <input type="text" v-model="message">
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                message: 'Hello World!',
            }
        }) 
    </script>
</body>

v-model:使用的是双向绑定,就是不论上面或者下面的值改变,都会自动改变对方

2、v-model的原理

<body>
    <div id="app">
        <input type="text" v-model="message">
        <input type="text" :value="message" @input="valueChange">
        <input type="text" :value="message" @input="message = $event.target.value">
        {{message}}
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                message: 'Hello World!',
            },
            methods: {
                valueChange(){
                    this.message = event.target.value;
                }
            }
        }) 
    </script>
</body>

v-model的原理就是:value与@input的组合使用

:value:通过监听vue对象内的额message的值,动态回显在input框上

@input:监控input的值,为Vue对象的message赋值

3、v-model结合radio使用

<body>
    <div id="app">
        <label for="male">
            <input type="radio" id="male" value="男" v-model="sex">男
        </label>
        <label for="female">
            <input type="radio" id="female" value="女" v-model="sex">女
        </label>
        <h1>{{sex}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                sex:'男',
            },
        }) 
    </script>
</body>

4、v-model结合checkedbox使用

<body>
    <div id="app">
        <!-- 单选 -->
        <label for="agree">
            <input type="checkbox" id="agree" v-model="isAgree">同意协议
        </label>
        <h1>您选择的是:{{isAgree}}</h1>
        <button :disabled="!isAgree">下一步</button>
        <br>
        <!-- 多选 -->
        <input type="checkbox" value="篮球" v-model="hobbies">篮球
        <input type="checkbox" value="足球" v-model="hobbies">足球
        <input type="checkbox" value="羽毛球" v-model="hobbies">羽毛球
        <input type="checkbox" value="排球" v-model="hobbies">排球
        <input type="checkbox" value="橄榄球" v-model="hobbies">橄榄球
        <h1>您的爱好是:{{hobbies}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                message: 'Hello World!',
                isAgree: false,
                hobbies: []
            },
          
        }) 
    </script>
</body>

5、v-model结合select使用

<body>
    <div id="app">
        <select name="abc" id="" v-model="fruit">
            <option value="苹果">苹果</option>
            <option value="香蕉">香蕉</option>
            <option value="橙子">橙子</option>
            <option value="鸭梨">鸭梨</option>
        </select>
        <h1>您选择的是:{{fruit}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                message: 'Hello World!',
                fruit: ''
            },
        }) 
    </script>
</body>

6、v-model值绑定(动态赋值)

<body>
    <div id="app">
        <label v-for="item in originHobbies" :for="item">
            <input type="checkbox" :value="item" :id="item" v-model="hobbies">{{item}}
        </label>
        <h1>您选择的是:{{hobbies}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                message: 'Hello World!',
                originHobbies: ['篮球', '足球', '羽毛球', '乒乓球', '橄榄球',],
                hobbies: []
            },
        }) 
    </script>
</body>

7、v-model修饰符使用

<body>
    <div id="app">
        <!-- lazy:失去焦点或者敲回车之后在赋值 -->
        <input type="text"  v-model.lazy="message">
        <h1>您选择的是:{{message}}</h1>

        <!-- number:v-model默认全是字符串类型,加number可改成数字类型-->
        <input type="text"  v-model.number="age">
        <h1>您选择的是:{{age}}</h1>

        <!-- trim:去左右两边的空格 -->
        <input type="text"  v-model.trim="name">
        <h1>您选择的是:{{name}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                message: 'Hello World!',
                age: 0,
                name: '王一'
            },
          
        }) 
    </script>
</body>

**lazy:**失去焦点或者敲回车之后在赋值

**number:**v-model默认全是字符串类型,加number可改成数字类型

**trim:**去左右两边的空格

8、组件化开发

1、注册组件的基本步骤

  • 创建组件构造器:调用Vue.extend()方法,创建组件构造器

  • 注册组件:调用Vue.component()方法,注册组件

  • 使用组件:在Vue实例的作用范围使用组件

<body>
    <div id="app">
    	<!-- 使用组件 -->
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        //1、创建组件构造器对象
        const cpnC = Vue.extend({
            template: `
            <div>
                <h1>我是标题</h1>
                <p>我是内容</p>
            </div>`
        })
        
        //2、注册组件
        Vue.component('my-cpn', cpnC);
        const app = new Vue({
            el: "#app",
            data: {
                message: 'Hello World!',
            },
        }) 
    </script>
</body>

2、全局组件和局部组件

<body>
    <div id="app">
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        //1、创建组件构造器对象
        const cpnC = Vue.extend({
            template: `
            <div> 
                <h1>我是标题</h1>
                <p>我是内容</p>
            </div>`
        })
        //2、注册组件(全局组件:可以在多个Vue实例中使用)
        Vue.component('my-cpn', cpnC);
        const app = new Vue({
            el: "#app",
            data: {
                message: 'Hello World!',
                age: 0,
                name: '王一'
            },
            components: {
                //局部组件:只可以在当前Vue实例中使用 cpn 使用组件时的标签名
                cpn: cpnC
            }
        }) 
    </script>
</body>

3、父组件与子组件

<body>
    <div id="app">
        <cpn2></cpn2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        //子组件
        const cpnC1 = Vue.extend({
            template: `
            <div> 
                <h1>我是标题1</h1>
                <p>我是内容1</p>
            </div>`
        })
        //父组件
        const cpnC2 = Vue.extend({
            template: `
            <div> 
                <h1>我是标题2</h1>
                <cpn1></cpn1>
                <p>我是内容2</p>
            </div>`,
            components: {
                //注册子组件
                cpn1: cpnC1
            }
        })
        const app = new Vue({
            el: "#app",
            data: {
                message: 'Hello World!',
            },
            components: {
                cpn2: cpnC2
            }
        }) 
    </script>
</body>

4、组件注册语法糖写法

<body>
    <div id="app">
        <cpn1></cpn1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        //注册全局组件语法糖
        Vue.component('cpn1',{
            template: `
            <div> 
                <h1>我是标题1</h1>
                <p>我是内容1</p>
            </div>`
        })
        const app = new Vue({
            el: "#app",
            data: {
                message: 'Hello World!',
            },
            components: {
                //注册局部组件语法糖
                'cpn2' :{
                    template: `
                        <div> 
                            <h1>我是标题1</h1>
                            <p>我是内容1</p>
                        </div>`
                }
            }
        }) 
    </script>
</body>

5、组件模板分离写法

<body>
    <div id="app">
        <cpn1></cpn1>
        <cpn2></cpn2>
    </div>
    <script type="text/x-template" id="cpn2">
        <div> 
            <h1>我是标题666</h1>
            <p>我是内容666</p>
        </div>
    </script>
    <template id="cpn">
        <div> 
            <h1>我是标题123</h1>
            <p>我是内容123</p>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        Vue.component('cpn1',{
            template: '#cpn'
        })
        const app = new Vue({
            el: "#app",
            data: {
                message: 'Hello World!',
            },
            components: {
                //注册局部组件语法糖
                'cpn2' :{
                    template: '#cpn2'
                }
            }
        }) 
    </script>
</body>

通过template标签或者script标签将代码抽取出来,之后直接映射Id即可

6、组件中数据存放问题

组件内不可以访问Vue实例内的数据,但是组件对象也有一个data属性(也可以有methods等属性),只是data属性必须是一个函数,而这个函数返回一个对象,对象内部保存着数据

<body>
    <div id="app">
        <cpn1></cpn1>
    </div>
    <template id="cpn">
        <div> 
            <h1>{{title}}</h1>
            <p>我是内容123</p>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        Vue.component('cpn1',{
            template: '#cpn',
            data(){
                return {
                    title: 'ccc'
                }
            }
        })
        const app = new Vue({
            el: "#app",
        }) 
    </script>
</body>

7、组件中为什么data是函数

以上的例子,是一个计数器功能,当组件调用多次的时候,data每次返回的都是不同的对象,多个组件之间不相互影响,如果不是函数,返回都是一个对象,那么多个组件就都会操作一个数据了。

如果想让多个组件操作同一个数据的方式:如下,创建一个对象,之后data函数返回这个对象,这时如果使用这个组件多次,操作的也都是一个对象

<script>
const obj = {
   counter : 0
}
Vue.component('cpn1',{
    template: '#cpn',
    data(){
   		return : obj
    }
})
</script>
<body>
    <div id="app">
        <cpn1></cpn1>
        <cpn1></cpn1>
    </div>
    <template id="cpn">
        <div> 
            <h1>当前计数:{{counter}}</h1>
            <button @click="increment">+</button>
            <button @click="decrement">-</button>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        Vue.component('cpn1',{
            template: '#cpn',
            data(){
                return {
                    counter: 0
                }
            },
            methods:{
                increment(){
                    this.counter++
                },
                decrement(){
                    this.counter--
                }
            }
        })
        const app = new Vue({
            el: "#app",
        }) 
    </script>
</body>

8、组件通信-父组件向子组件传递数据

<body>
    <div id="app">
        <cpn :cmovies="movies" :cmessage="message"></cpn>
    </div>
    <template id="cpn">
        <div> 
            <ul>
                <li v-for="item in cmovies">{{item}}</li>
            </ul>
            <h1>{{cmessage}}</h1>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        const cpn = {
            template: '#cpn',
            //props: ['cmovies', 'cmessage'],
            props: { //props 接收父组件传过来的数据
                cmessage:{
                    type: String,  //类型限制
                    default: 'abc', //默认值
                    required: true //是否必传
                },
                cmovies: { //类型是对象或者数组的时候,默认值必须是一个函数
                    type: Array,
                    default(){
                        return []
                    }
                }                
            },
        }
        const app = new Vue({
            el: "#app",
            data: {
                message: 'Hello World!',
                movies: ['海尔兄弟1', '海尔兄弟2', '海尔兄弟3']
            },
            components: {
                cpn :cpn
            }
        }) 
    </script>
</body>

以上例子,app为父组件,cpn为子组件,子组件想获取父组件的数据,

1、先定义props属性进行接收

 <script>
	props: { //props 接收父组件传过来的数据
        cmessage:{
            type: String,  //类型限制
                default: 'abc', //默认值
                    required: true //是否必传
        },
            cmovies: { //类型是对象或者数组的时候,默认值必须是一个函数
                type: Array,
                    default(){
                        return []
                    }
            }                
    },
 </script>

2、进行传值,:cmovies为子组件中定义的属性名 movies为父组件中定义的属性名

 <cpn :cmovies="movies" :cmessage="message"></cpn>

3、之后就直接可以在组件中使用了

 <template id="cpn">
	<div> 
        <ul>
            <li v-for="item in cmovies">{{item}}</li>
         </ul>
        <h1>{{cmessage}}</h1>
    </div>
</template>

注意:子组件定义属性名尽量不要驼峰,驼峰:cMovies这样可能接收不到,需要c-movies接收

9、组件通信-子组件向父组件传递数据

<body>
    <div id="app">
        <cpn @itemclick="cpnclick"></cpn>
    </div>
    <template id="cpn">
        <div>
            <button v-for="item in cate" @click="btnclick(item)">{{item.name}}</button>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        const cpn = {
            template: '#cpn',
            data(){
                return {
                    cate :[
                        {id:1, name:'王一'},
                        {id:2, name:'王二'},
                        {id:3, name:'王三'},
                        {id:4, name:'王四'},
                    ]
                }
            },
            methods: {
                btnclick(item){
                   this.$emit("itemclick",item)     
                }
            }
        }
        const app = new Vue({
            el: "#app",
            data: {
                message: 'Hello World!',
            },
            components: {
                cpn :cpn
            },
            methods: {
                cpnclick(item){
                    console.log(item);
                }
            }
        }) 
    </script>
</body>

逻辑就是子组件通过定义方法,输出数据,之后父组件进行监听,监听到了进行回调

以上的例子总结:

1、子组件定义点击事件

2、在点击时间内创建向父组件发送数据请求 this.$emit(“itemclick”,item)

3、父组件定义v-on进行监听子组件的自定义请求 <cpn @itemclick=“cpnclick”>

4、父组件接收到数据的回调 cpnclick(item){console.log(item);}

10、组件访问-父组件访问子组件

1、通过$children去访问子组件的方法或者属性,但是需要通过下表去取具体的哪一个组件(不常用)

2、通过$refs去访问子组件的方法或者属性(常用)

  • 给需要访问的子组件标签上加上ref属性(ref=“aaa”
  • this.$refs.aaa.name去访问相应的子组件属性(.aaa相当于通过键去取值)
  • $refs为对象类型,不绑定ref属性的时候默认为空
<body>
<div id="app">
  <cpn ref="aaa"></cpn>
  <button @Click="btnClick">按钮</button>
</div>
<script src="../js/vue.js"></script>
<template id="cpn">
  <div>我是子组件</div>
</template>
<script>
  const app = new Vue({
    el:'#app',
    data:{
      message:'Hellod World'
    },
    methods:{
      btnClick(){
        // 1、通过$children去与访问子组件方法或属性
        console.log(this.$children)
        this.$children[0].showMessage()
        console.log(this.$children[0].name)
        //2、通过$refs访问子组件方法或属性 $refs为对象类型,默认为空的对象
        console.log(this.$refs.aaa.name);
      }
    },
    components:{
      cpn: {
        template:'#cpn',
        data(){
          return{
            name: '我是子组件的属性'
          }
        },
        methods: {
          showMessage(){
            console.log("showMessage");
          }
        }
      }
    }
  })
</script>
</body>

11、组件访问-子组件访问父组件

1、访问父组件this.$parent.message

2、访问根组件this.$root.message

<body>
   
<div id="app">
  <cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<template id="cpn">
    <ccpn></ccpn>
</template>
<template id="ccpn">
  <div>
    <div>我是子组件</div>
    <button @click="btnClick">按钮</button>
  </div>
</template>
<script>
  const app = new Vue({
    el:'#app',
    data:{
      message:'Hellod World'
    },
    components:{
      cpn: {
        template:'#cpn',
        data(){
          return{
            message:'hello'
          }
        },
        components:{
          ccpn:{
            template: '#ccpn',
            methods: {
              btnClick(){
                //1、访问父组件(父组件为cpn)
                console.log(this.$parent.message)//cpn 内的message  hello
                //2、访问根组件(根组件为Vue)
                console.log(this.$root.message)//Vue 内的message  Hellod World
              }
            },
          }
        }
      }
    }
  })
</script>
</body>

12、组件插槽的基本使用

组件的插槽也是为了让我们封装的组件更加具有扩展性

让使用者可以决定组件内部的一些内容到底展示什么

抽取共性,保留不同(slot)

1、插槽的基本使用

<slot></slot>

2、插槽的默认值(就是界面不往插槽内传值的时候显示的东西)

<slot><button>插槽的默认值</button></slot>

3、如果有多个值,一起传入到插槽内,都会替换,都会显示

<body>
<div id="app">
  <cpn><span>插槽span</span></cpn>
  <cpn><li>插槽li</li></cpn>
  <cpn><a href="www.baidu.com">插槽a</a></cpn>
  <cpn>
    <span>插槽span</span>
    <li>插槽li</li>
    <a href="www.baidu.com">插槽a</a>
  </cpn>
  <cpn></cpn>
  <cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<template id="cpn">
    <div>
      <h1>我是子组件</h1>
      <p>子组件</p>
      <slot><button>插槽默认值按钮</button></slot>
    </div>
</template>
<script>
  const app = new Vue({
    el:'#app',
    data:{
      message:'Hellod World'
    },
    components:{
      cpn: {
        template:'#cpn',
      }
    }
  })
</script>
</body>

13、具名插槽的使用

当一个组件具有多个插槽时,给插槽定义一个name属性,在使用的时候加上一个slot属性,指定当前的内容替换哪一个插槽

<body>
<div id="app">
  <cpn><span slot="center">标题替换中间</span></cpn>
  <cpn><button slot="left">按钮替换左边</button></cpn>
</div>
<script src="../js/vue.js"></script>
<template id="cpn">
    <div>
      <slot name="left"><span>左边</span></slot>
      <slot name="center"><span>中间</span></slot>
      <slot name="right"><span>右边</span></slot>
    </div>
</template>
<script>
  const app = new Vue({
    el:'#app',
    data:{
      message:'Hellod World'
    },
    components:{
      cpn: {
        template:'#cpn',
      }
    }
  })
</script>
</body>

14、变量的作用域

在Vue的实例内,使用的变量时Vue里面定义的,与是否在组件上使用无关

官方:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译

<body>
  <div id="app">
    <!-- 使用的是Vue实例内的siShow -->
    <cpn v-show="isShow"></cpn>
  </div>
  <script src="../js/vue.js"></script>
  <template id="cpn">
      <div>
        <h1>我是子组件</h1>
        <span>子组件内容</span>
        <!-- 使用的是组件内的属性isShow -->
        <button v-show="isShow"></button>
      </div>
  </template>
  <script>
    const app = new Vue({
      el:'#app',
      data:{
        message:'Hellod World',
        isShow: true
      },
      components:{
        cpn: {
          template:'#cpn',
          isShow: false
        }
      }
    })
  </script>
</body>

15、作用域插槽

父组件替换插槽的标签,但是内容由子组件来提供

数据是子组件的,显示方式由父组件来确认

  • 在子组件内的slot内定义属性 **:data=“子组件的属性”(**data也是随便起名字的)
  • 之后在使用的时候加上template标签,加上**slot-scope=“scope”**属性,scope.data为子组件内的值
<body>
  <div id="app">
    <cpn></cpn>
    <cpn>
      <template slot-scope="scope">
        <span v-for="item in scope.data">{{item}}</span>
        <span>{{scope.data.join(' - ')}}</span>
      </template>
    </cpn>
  </div>
  <template id="cpn">
      <div>
        <slot :data="pLanguage">
          <ul>
            <li v-for="item in pLanguage">{{item}}</li>
          </ul>
        </slot>
      </div>
  </template>
  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el:'#app',
      data:{
        message:'Hellod World',
      },
      components:{
        cpn: {
          template:'#cpn',
          data(){
            return{
              pLanguage: ['JavaScript','Java','C','C++','c#']
            }
          }
        }
      }
    })
  </script>
</body>

9、模块化开发

随着前端代码越来越复杂,会出现一系列的问题(导入多个js文件,导致变量重名等等),所以前端引入了模块化的概念

1、ES6的模块化实现

就是把自己写的变量函数封装起来,之后导出,别的模块需要用的话,就需要导入(java的导入类)

10、Webpack

从本质上来讲,webpack是一个现代的JavaScript应用的静态模块打包工具

把浏览器不能识别的语言,进行打包转化,让浏览器可以识别

Webpack依赖node环境

node环境为了可以正常的执行很多代码,必须其中包含各种依赖的包

npm工具(node packages manager)管理node之中的包

具体没记笔记,也没跟这敲(有点复杂,就是打包前端代码,图片、css等一些东西让浏览器识别)

11、箭头函数和this的指向

1、基本使用

<script>
  //箭头函数:也是一种函数的定义方式
  //1、定义函数的方式:function
  const aaa = function(){
  }
  //2、对象字面量中定义函数
  const obj = {
    bbb: function(){
    },
    bbb(){
    }
  }
  //3、ES6中的箭头函数
  const ccc = (参数列表) =>{
  }
</script>

2、参数和返回值

<script>
  //参数问题
  //1、放入两个参数
  const sum = (num1, num2) => {
    return num1 + num2
  }
  //2、放入一个参数(小括号可以省略)
  const power = num => {
  }
  //函数中
  //1、函数中有多行代码时
  const test = () =>{
    console.log("aaa")
    console.log("ccc")
  }
  //2、函数中只有一行代码时(可以省略大括号)
  const mul = (num1, num2) => num1 * num2
</script>

3、箭头函数的this

箭头函数的this引用的就是最近作用域的this(一层一层向外查找this,直到找到有this的定义)

<script>
    //什么时候使用箭头函数(当把一个函数作为另一个函数的参数的时候)
    setTimeout(function(){
      console.log(this)  //打印Window
    }, 1000)
    setTimeout(()=>{
      console.log(this)  //打印Window
    }, 1000)
    //结论:箭头函数的this引用的就是最近作用域的this(一层一层向外查找this,直到找到有this的定义)
    const obj = {
      aaa(){
        setTimeout(function(){
          console.log(this)  //打印Window
        })
        setTimeout(() => {
          console.log(this) //打印obj对象
        })
      }
    }
</script>

12、router(路由)

1、后端路由

后端处理URL和页面之间的映射关系

  • 一个界面有自己对应的网址,也就是URL
  • URL会发送到服务器,服务器通过正则对该URL进行匹配,并且最后交给一个Controller进行处理
  • Controller进行各种处理,最终生成HTML或者数据,返回给前端
  • 完成一次IO操作

这种情况下渲染好的界面,不需要单独加载任何的js和css,可以直接交给浏览器展示,有利于SEO优化

后端渲染

后端通过解析url,之后查询数据渲染好界面(java+css+html )之后传给浏览器

2、前后端分离

后端只负责提供数据,不负责任何前端的内容

  • 浏览器根据用户输入的rul地址,去静态资源服务器请求响应Html+css+js
  • 静态资源服务器内会有多套html+css+js的组合,每一个url对应一套
  • js代码执行,可能会调用api接口,去后端请求数据(ajax)
  • 之后再浏览器渲染界面
  • 小程序或者app都适用这种开发模式,后端不需改变,api接口都适用

前端渲染:

浏览器中现实的网页中大部分内容都是前端写的js代码,在浏览器中执行,最终渲染出来的网页

3、SPA页面

SPA:单页富应用(整个网页只有一个html页面)

  • 当用户输入url地址的时候,浏览器会拿到仅有的index.html+css+js
  • 静态资源服务器只有一份html+css+js的组合
  • 之后用户点击按钮或者其他什么切换界面,前端路由会生成相应url,与请求到的所有资源进行对应
  • 全部资源内分组件,每一个生成的url对应某一个组件,之后进行相应渲染

前端路由:

维护一套路由关系(url ——> 组件)

生成对应url,之后去请求到的所有资源内拿出与之对应的组件,进行渲染

其实SPA最主要的特点就是在前后端分离的基础上加了一层前端路由,也就是由前端来维护一套路由规则

前端路由的核心:

改变URL,但是页面不进行整体的刷新(因为不需要在向服务器请求资源了,资源已经在第一次请求的时候都拿到了)

4、Vue-router的使用

<script>
//以下代码为router文件夹内的index.js里的内容
//配置路由相关的信息
import VueRouter from 'vue-router'
import Vue from 'vue'
import Home from '../components/Home'
import About from '../components/About'

//1、通过Vue.use(插件),安装插件
Vue.use(VueRouter)
//2、创建VueRouter对象
const routers = [
  {
    path: '',
    //重定向 第一次进入界面显示的内容
    redirect:'/home'
  },
  {
    path: '/home',
    component: Home
  },
  {
    path: '/about',
    component: About
  }
]
const router = new VueRouter({
    //配置路由和组件之间的应用关系
    routers,
    //就是url里面不带#的,默认时hash的
    mode: 'history'
})
//3、将router对象传入到Vue实例
export default router
</script>

<script>
//以下代码为main.js的内容(路由挂载到Vue实例上)
import Vue from 'vue'
import App from './App'
import router from './router'

new Vue({
    el: '#app',
    router,
    render: h => h(App)
})    
</script>

<html>
 <!-- 以下为App.vue -->   
 <template>
     <div id="app">
         <router-link to="/home">首页</router-link>
         <router-link to="/about">关于</router-link>
         <router-view></router-view>
     </div>
</template>

<script>
	export default {
  		name: 'App'
	}
</script>
</html>

<html>
 <!-- 以下为Home.vue -->   
 <template>
      <div>
        <h1>我是首页</h1>
        <p>我是首页内容</p>  
      </div>  
</template>
<script>
export default {
  name: "Home"
}
</script>
</html>

router-link:

to:用于跳转指定路径

tag:可以指定之后渲染成什么组件 例:

replace:replace不会留下history记录,所以指定replace的情况下,后退键返回不能返回到上一个界面

1、动态路由:

动态拼接路由

2、路由懒加载:

因为SPA页面按道理来说只请求一次静态资源服务器,但是随着项目越来越大,js文件也就变得越来越大,如果一次全都加载过来,就会造成界面的短暂空白等情况

vue build的时候,正常会生成三个文件

  • vendor:第三方的东西,插件之类的
  • manifest:做底层支撑的
  • app:js文件,就是项目的业务逻辑

项目越大,app文件也就越大,加载变慢,所以需要懒加载

就是把app文件分开,第一次只加载当前需要的组件,之后点击其他界面的时候,需要哪个再去加载哪个

写法:

const routers = [
    {
        path: '/home'
        component: () => import('../components/Home')
    },
]
3、路由的嵌套:

再home的界面上加上以下内容

<router-link to="/message">信息</router-link>
<router-view></router-view>
const routers = [
    {
        path: '/home'
        component: () => import('../components/Home')
    	children: [
            {
                path: '/message'
 		        component: () => import('../components/message')
            },
        ]
	},
]
4、路由传递参数:

传递参数主要有两种类型:params和query

params的类型:

配置路由格式:/router/:id

传递的方式:在path后面跟上对应的值

传递后形成的路径:/router/123,/router/abc

query的类型:

配置路由格式:/router,也就是普通配置

传递的方式:对象中使用query的key作为传递方式

传递后形成的路径:/router?id=123,/router?id=abc

5、路由导航守卫:

就是界面跳转的时候能做事情(以下是实现,跳转的时候更改界面的标题)

//这个router就是路由对象
//from是从哪跳转  to是跳转到哪里 next()方法必须执行
//to.matched[]是一个数组,因为可能包含路由的嵌套,就写死永远取第一个就行,有业务需求在修改
//前置回调
router.beforeEach((to, from, next) => {
    document.title = to.matched[0].meta.title
    next()
})
//后置回调(不需要主动调用next())
router.afterEach((to, from) => {
})

以上为全局守卫,还有路由独享守卫,还有组件内守卫

//路由独享守卫
const router = new VueRouter({
    routers: [
        {
            path: '/foo',
            component: Foo,
            beforeEnter: (to, from, next) => {
                //...
                next()
            }
        },
    ]
})
6、keep-alive

就是从这个界面条状到另一个界面,如果不保持keep-alive的话,就会重新创建界面,每次进入与离开,都会相应的执行创建和销毁,但是如果保持了keep-alive的话,那么这个界面就会放入缓存内,就不会每次离开都销毁了,也可以使用相应的回调函数activated(活跃的时候执行)、deactivated(不活跃的时候执行),总结就是不让组件频繁的创建与销毁

<keep-alive>
	<router-view></router-view>
</keep-alive>

keep-alive的属性

exclude:保持keep-alive,但是除了哪几个

<keep-alive exclude="user,home">

13、Vuex

Vuex是一个专门为Vue.js应用程序开发的状态管理模式

状态管理:就是多个组件需要共享的变量,全部存储在一个对象内,将这个对象放在顶层vue实例中,其他组件就可以使用了

VueJS为响应式的,动态改变数据

响应式规则:

要想实现响应式,所有数据必须在store中初始化好的

Const store = new Vuex.Store({
    state: {
        info: {
            name: 'wangyi',
            age: 21,
            heighe: 170
        },
  	},
    
})

以上info内的属性都会被加入到响应式系统中,而响应式系统用会监听属性的变化,当属性发生变化时,会通知所有界面中用到该属性的地方,让界面发生刷新

如果要通过mutations来修改state内的属性的时候:

mutations: {
	updateInfo(){
        //这种修改现有属性的是为响应式的,因为他在初始化的时候已经被监听了
        state.info.name = 'wanger'
        //这种添加在原有基础上添加属性的方式不是响应式的,因为该address属性没有被监听,所以界面不会显示
        state.info['address'] = '吉林市'
        //这种方式是响应式的,也是添加属性,但是他会把新加入的属性,加到监听里面去,所以界面会显示
        Vue.set(state.info, 'address', '吉林市')
        //删除与添加同理
        delete state.info.age
        Vue.delete(state.info, 'age')
    }
},

修改数据:

在这里插入图片描述

如果想要修改store内的数据

从Vue Components直接修改数据,传回State,是可以修改的,但是官方不建议这样做

<h1>{{$store.state.num++}}</h1>

官方建议,经过Actions到Mutations,之后再传回State

如果有异步操作,可以经过Actions,没有异步操作,直接从Vue Compinents到Mutations也是可以的

Mutations这一步,是有一个Devtools(浏览器内)的工具,帮我们跟踪,哪一个组件修改了属性,方便后期调试等

Vuex基本使用:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

Const store = new Vuex.Store({
  modules: {},
  mutations: {},
  actions: {},
  state: {
      num: 100
  },
  getters: {},
})
export default store

//使用
<h1>{{$store.state.num}}</h1>

1、store:

单一状态树,所有的信息都放在一个store内,方便后期维护管理。(永远只有一个store)

2、state:

用来存放信息(变量),其他界面可以使用

3、getters:

类似于Vue的计算属性,就是经过操作之后把数据再拿出去

Const store = new Vuex.Store({
    state: {
        num: 100
    },
    getters: {
        //state为默认参数
        powerCounter(state){
            return state.num * state.num
        },
        //这个getters里面的方法可以有第二个属性,这个第二个属性可以调用其他的方法
        test(state,getters){
            return getters.powerCounter
        },
        //调用的时候传来的参数
        testparam(state){
			return function(param){
                return num * param
            }            
        }
    }
})
//使用
<h1>{{$store.getters.powerCounter}}</h1>
//传参使用
<h1>{{$store.getters.testparam(param)}}</h1>

**4、mutations: **

只能定义同步方法(修改数据)不能进行异步操作

export default new Vuex.Store({
  mutations: {
      //state为默认参数
      increment(state){
          state.num++
      },
      incrementCount(state, count){
          state.num += count
      },
      addStudent(state, stu){
          state.students.push(stu)
      }
  },
  state: {
      num: 100,
      students: []
  },
})

//界面
<button @click="add"></button>
//传参
<button @click="addCount(10)"></button>
//传递多个参数
<button @click="addStudent"></button>
...
methods:{
    add(){
        //调用mutations方法的时候使用commit之后跟方法名
        this.$store.commit('increment')
    },
    addCount(count){
        //普通的提交方式
		this.$store.commit('incrementCount', count)	        
    	//特殊的提交方式通过这中方方式传过去的就不是一个值了,而是一个对象,相应接收也是需要改变的
        this.$store.commit({
            type: 'incrementCount',
            count: count
        })
    },
    addStudent(){
 		const stu = {id:114, name:'wangyi', age:21}
        this.$store.commit('addStudent', stu)
    }
}

5、Action:

定义异步方法(修改数据)

action执行完之后还要回到mutations(详情见上面图片)

Const store = new Vuex.Store({
  state: {
      num: 100
  },
  actions: {
      //context 上下文 params 参数
      updateInfo(context, params){
          setTimeout(() => {
              //提交到mutations
              context.commit('updateInfo')
              console.log(params)
          }1000)
      },
      updateInfo2(context, params){
         return new Promise(resolve, reject) =>{
             setTimeout(() => {
                 //提交到mutations
                 context.commit('updateInfo')
                 console.log(params)
                 //action执行完成之后的回调
                 resolve("action执行完成!")
             }1000)
         } 
      }
  },
})

//组件内调用
<button @click="updateInfo"></button>
...
methods:{
    //正常携带参数调用
    updateInfo(){
        this.$store.dispatch('updateInfo',params)
    },
    //有回调,就是action执行完成之后,这边会有个回调函数,这边能知道action已经执行完成
    this.$store.dispatch('updateInfo2', params).then(res => {
        //res action执行完成之后返回的信息
        console.log(res);//action执行完成!
    })
}

6、modules:

Vuex使用单一状态树,那么意味着很多状态都会交给Vuex来管理

当应用百年的非常复杂时,store对象就有可能变得非常臃肿

为了解决这个问题,Vuex允许我们将store分割成模块(Module)每个模块拥有自己的state、mutations、actions、getters等

const moduleA = {
    state: {
        name: 'wangyi'
    },
    mutations: {
    	updateName(state, newName){
            state.name = newName
        }
    },
    
    getters: {
        fullName(state){
            return state.name + '111'
        },
        fullName2(state, getters){
            //modules里面也可以调用getters
            return getters.fullName + '222'
        },
        fullName3(state, getters, rootState){
            //rootState为原始store内的属性
            return getters.fullName2 + rootState.num
        }
    },
    actions: {
    	updateName(context){
            //异步操作,当前这个context是上下文,他commit只能commit自己的mutation,不能提交到原始的			  //store内
            context.commit('updateName', 'wangsan')
        }  
    },
}
              
const moduleB = {
    state: {...},
    mutations: {...},
    actions: {...},
    getters: {...}
}
              
const store = new Vuex.Store({
    state: {
      num: 100  
    },
    modules: {
    	a: moduleA,
        b: moduleB
    },
})
                
//调用属性
<h1>{{$store.state.a.name}}</h1>
//调用mutations
<button @click="updateName"></button>
//调用getters                
<h1>{{$store.state.fullName}}</h1>
...
methods:{
    updateName(){
        //调用模块内的mutation 程序会先去原始的store内查找mutation,找不到的话就会去模块内找
        this.$store.commit('updateName', 'wanger')
    }
}

如果代码过多的话,可以把每个属性都抽取出去,方便维护和修改

Vue CLI(脚手架)

淘宝镜像:npm install --registry=https://registry.npm.taobao.org

之后使用:cnpm install [name]

下载Vue CLI(最新):npm install -g @vue/cli

下载Vue CLI(下载2):

Vue CLI2初始化项目:vue init webpack my-project

Project name //项目名称
Project description //项目描述
Author //作者
Vue build //用什么编译器,后续还会有笔记(当前理解就是可不可以编译template)
Install vue-router//是否安装路由
User ESLint to lint your code//是否需要语法规范
Pick an ESLint preset//选择一种规范
Set up unit tests//是否需要测试模块
Setup e2e tests with Nightwatch//是否需要测试模块
should we run .....//用什么来管理当前项目(npm/yarm)

runtime-compiler

template —> ast(抽象语法树) —> render —>virtual dom(虚拟dom)—> UI(真实dom)

runtime-only(1、效率更高 2、代码量更少)

render —>virtual dom(虚拟dom)—> UI(真实dom)

Vue CLI3初始化项目:vue create my-project

Vue CLI3:我创建的是4.x版本,就是配置文件更少,看起来更简洁

在这里插入图片描述

回调函数:

created:创建之前执行

destroyed:销毁之后执行

beforeRouteleave:组件内导航守卫,离开当前页面之前调用,具体还有另外几个函数,官网有

以下两个函数,只有该组件被保持了状态使用了keep-alive时,才是有效的

activated:处于活跃状态的时候执行

deactivated:不活跃的时候执行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值