vue(自用)

Vue介绍

Vue(读音/vjuː/,类似于view) 是一套用于构建前后端分离的框架。刚开始是由国内优秀选手尤雨溪开发出来的,目前是全球“最”流行的前端框架。使用vue开发网页很简单,并且技术生态环境完善,社区活跃,是前后端找工作必备技能!
MVVM模式
M:即Model,模型,包括数据和一些基本操作
V:即View,视图,页面渲染结果
VM:即View-Model,模型与视图间的双向操作(无需开发人员干涉)

官网

Vue安装和使用

vue的安装大体上分成三种方式,第一种是通过script标签引用的,第二种是通过npm(node package manager)来安装,第三种是通过vue-cli命令行来安装。作为初学者,建议直接通过第一种方式来安装,把心思集中在vue的学习上,而不是安装上。

# 开发环境
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
# 或者是指定版本号
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
# 或者是下载代码保存到本地
<script src="lib/vue.js"></script>


# 生产环境,使用压缩后的文件
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js"></script>

基本使用

要使用Vue,首先需要创建一个Vue对象,并且在这个对象中传递el参数,el参数全称是element,用来找到一个给vue渲染的根元素。并且我们可以传递一个data参数,data中的所有值都可以直接在根元素下使用{{}}来使用。

<div id="app">
    <p>{{username}}</p>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            "username": "逻辑教育"
        }
    });
</script>

其中data中的数据,只能在vue的根元素下使用,在其他地方是不能被vue识别和渲染的
另外也可以在vue对象中添加methods,这个属性中专门用来存储自己的函数。methods中的函数也可以在模板中使用,并且在methods中的函数来访问data中的值,只需要通过this.属性名就可以访问到了,不需要额外加this.data.属性名来访问

<div id="app">
    <p>{{greet()}}</p>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            "username": "逻辑教育"
        },
        methods: {
            greet: function(){
                return "晚上好!" + this.username
            }
        }
    });
</script>

文本

在html中通过{{}}(双大括号)中可以把Vue对象中的数据插入到网页中。并且只要Vue对象上对应的值发生改变了,那么html中双大括号中的值也会立马改变。
当然,如果在html的{{}}中,第一次渲染完成后,不想要跟着后期数据的更改而更改,那么可以使用v-once指令来实现。v-pre不编译{{}}的内容

<p v-once>{{username}}</p>

显示原生的HTML

有时候我们的Vue对象中,或者是后台返回给我们一个段原生的html代码,我们需要渲染出来,那么如果直接通过{{}}渲染,会把这个html代码当做字符串。这时候我们就可以通过v-html指令来实现

使用v-text和v-html指令来替代 {{}}
说明:
v-text:将数据输出到元素内部,如果输出的数据有HTML代码,会作为普通文本输出
v-html:将数据输出到元素内部,如果输出的数据有HTML代码,会被渲染

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>vuejs测试</title>
	<script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
	v-text:<span v-text="msg"></span><br>
	v-html:<span v-html="msg"></span><br>
</div>
<script>
	let app = new Vue({
		el:"#app",
		data:{
			msg:"<h2>hello, vue.</h2>"
		}
	});
</script>
</body>
</html>

属性绑定

如果我们想要在html元素的属性上绑定我们Vue对象中的变量,那么需要通过v-bind来实现

<div id="app">
    <img class="{{classname}}">你好,世界</p>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            "classname": "pclass"
        },
    });
</script>

需要使用v-bind才能生效

<div id="app">
    <img v-bind:src="imgSrc" alt="">
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            "imgSrc": "https://i.ytimg.com/vi/5HKZ6bU6Zg0/maxresdefault.jpg"
        }
    });
</script>

在绑定class或者style的时候,可以通过以下方式来实现。

绑定Class

通过数组的方式来实现

<div id="app">
    <p v-bind:class="[classname1,classname2]">你好,世界</p>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            classname1: "pcolor",
            classname2: "pfont"
        }
    });
</script>

通过对象的方式来实现

<div id="app">
    <p v-bind:class="{pcolor:isColor,pfont:isFont}">你好,世界</p>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            isColor: true,
            isFont: true
        }
    });
</script>

绑定Style

用对象的方式

# 读取对应样式的值
<li :style="{backgroundColor:pBgColor,fontSize:pFontSize}">首页</li>
# 或者是直接读取整个字符串
<li :style="liStyle">首页</li>

但是样式如果有横线,则都需要变成驼峰命名的方式
用数组的方式

<li :style="[liStyle1,liStyle2]">首页</li>
<script>
    new Vue({
        el: "#app",
        data: {
            liStyle: {
            backgroundColor: "red",
            fontSize: "14px"
        },
        liStyle2: {
            fontWeight: 800
        }
        }
    })
</script>

使用JavaScript表达式

在使用了v-bind的html属性,或者使用了{{}}的文本。我们还可以执行一个JavaScript表达式

<div id="app">
  <p v-bind:style="{color:color?'red':'blue'}">{{username.split(" ").reverse().join(" ")}}</p>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            username: "luoji ketang",
            color: false
        }
    });
</script>

注意,只能是JavaScript表达式,不能是语句,比如var a=1;a=2;这样的是js语句,不是表达式了

条件判断

在模板中,可以根据条件进行渲染。条件用到的是v-ifv-else-if以及v-else来组合实现的

<div id="app">
    <p v-if="weather == 'sun'">今天去公园玩!</p>
    <p v-else-if="weather == 'rain'">今天去看电影!</p>
    <p v-else>今天哪儿也不去!</p>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            weather: 'sun'
        }
    });
</script>

有时候我们想要在一个条件中加载多个html元素,那么我们可以通过template元素上实现

<div id="app">
    <template v-if="age<18">
        <p>数学多少分?</p>
        <p>英语多少分?</p>
    </template>
    <template v-else-if="age>=18 && age<25">
        <p>女朋友找到了吗?</p>
        <p>考研究生了吗?</p>
    </template>
    <template v-else>
        <p>二胎生了吗?</p>
        <p>工资多少?</p>
    </template>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            age: 24
        }
    });
</script>

另外,在模板中,Vue会尽量重用已有的元素,而不是重新渲染,这样可以变得更加高效。如果你允许用户在不同的登录方式之间切换

<div id="app">
    <template v-if="loginType=='username'">
        <label for="username">用户名:</label>
        <input type="text" id="username" name="username" placeholder="用户名">
    </template>
    <template v-else-if="loginType=='email'">
        <label for="email">邮箱:</label>
        <input type="text" id="email" name="email" placeholder="邮箱">
    </template>
    <div>
        <button v-on:click="changeLoginType">切换登录类型</button>
    </div>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            loginType: "username"
        },
        methods: {
            changeLoginType: function(event){
                this.loginType = this.loginType=="username"?"email":"username";
            }
        }
    });
</script>

这个里面会有一个问题,就是如果我在username的输入框中输入完信息,切换到邮箱中,之前的信息还是保留下来,这样肯定不符合需求的,如果我们想要让html元素每次切换的时候都重新渲染一遍,可以在需要重新渲染的元素上加上唯一的key属性,其中key属性推荐使用整形,字符串类型。

<div id="app">
    <template v-if="loginType=='username'">
        <label for="username">用户名:</label>
        <input type="text" id="username" name="username" placeholder="用户名" key="username">
    </template>
    <template v-else-if="loginType=='email'">
        <label for="email">邮箱:</label>
        <input type="text" id="email" name="email" placeholder="邮箱" key="email">
    </template>
    <div>
        <button v-on:click="changeLoginType">切换登录类型</button>
    </div>
</div>

注意,元素仍然会被高效地复用,因为它们没有添加key属性

key

当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将
不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过
的每个元素。
如果使用key这个功能可以有效的提高渲染的效率;key一般使用在遍历完后,又增、减集合元素的时候更有意义。
但是要实现这个功能,你需要给Vue一些提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需
要为每项提供一个唯一 key 属性。理想的 key 值是每项都有的且唯一的 id。 也就是key是该项的唯一标识。
示例:

ul>
	<li v-for="(item,index) in items" :key="index"></li>
</ul>

这里使用了一个特殊语法: :key="" 后面会讲到,它可以让你读取vue中的属性,并赋值给key属性
这里绑定的key是数组的索引,应该是唯一的

v-show和v-if

v-if是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。 v-if也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。 相比之下,v-show就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于CSS进行切换。 一般来说, v-if有更高的切换开销,而v-show有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show较好;如果在运行时条件很少改变,则使用v-if较好。

循环

在模板中可以用v-for指令来循环数组,对象等
循环数组

<div id="app">
    <table>
            <tr>
                <th>序号</th>
                <th>标题</th>
                <th>作者</th>
            </tr>
            <tr v-for="(book,index) in books">
                <td>{{index}}</td>
                <td>{{book.title}}</td>
                <td>{{book.author}}</td>
            </tr>
    </table>
</div>

循环对象
循环对象跟循环数组是一样的。并且都可以在循环的时候使用接收多个参数

<div id="app">
    <div v-for="(value,key) in person">
        {{key}}:{{value}}
    </div>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            person: {
                "username": "逻辑教育",
                "age": 18,
                "homepage": "https://www.baidu.com/"
            }
        }
    });
</script>

保持状态
循环出来的元素,如果没有使用key元素来唯一标识,如果后期的数据发生了更改,默认是会重用的,并且元素的顺序不会跟着数据的顺序更改而更改

<div id="app">
    <div v-for="(book,index) in books">
        <label for="book">{{book}}</label>
        <input type="text" v-bind:placeholder="book">
    </div>
    <button v-on:click="changeBooks">更换图书</button>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            books: ['三国演义','水浒传','红楼梦','西游记']
        },
        methods: {
            changeBooks: function(event){
                this.books.sort((x,y) => {
                    return 5 - parseInt(Math.random()*10)
                });
            }
        }
    });
</script>

触发视图更新

Vue对一些方法进行了包装和变异,以后数组通过这些方法进行数组更新,会出发视图的更新。

  1. push():添加元素的方法。
this.books.push("居然")
  1. pop():删除数组最后一个元素。
this.books.pop()
  1. shift():删除数组的第一个元素。
 this.books.shift()
  1. unshift(item):在数组的开头位置添加一个元素。
this.books.unshift("居然")
  1. splice(index,howmany,item1,…,itemX):向数组中添加或者删除或者替换元素。
 // 向books第0个位置添加元素
 this.books.splice(0,0,"金瓶梅")
 // 下标从0开始,删除2个元素
 this.books.splice(0,2)
 // 下标从0开始,替换2个元素
 this.books.splice(0,2,'金瓶梅','骆驼祥子')
  1. sort(function):排序。
 this.books.sort(function(x,y){
     // 取两个随机数排序
     a = Math.random();
     b = Math.random();
     return a-b;
 });
  1. reverse():将数组元素进行反转。
 this.books.reverse();

视图更新注意事项

  1. 直接修改数组中的某个值是不会出发视图更新的。比如:
this.books[0] = 'Python';

这种情况应该改成用splice或者是用Vue.set方法来实现:

 Vue.set(this.books,0,'Python');
  1. 如果动态的给对象添加属性,也不会触发视图更新。只能通过Vue.set来添加。比如:
 <div id="app">
     <ul>
         <li v-for="(value,name) in person">{{name}}:{{value}}</li>
     </ul>
     <script>
         let vm = new Vue({
             el: "#app",
             data: {
                 person: {"username": '逻辑教育'}
             },
             methods: {
                 changePerson: function(event){
                     Vue.set(this.person,'age',18)
                 }
             }
         });
     </script>
 </div>

事件绑定

事件绑定就是在HTML元素中,通过v-on绑定事件的。事件代码可以直接放到v-on后面,也可以写成一个函数。

<div id="app">
    <p>{{count}}</p>
    <button v-on:click="count+=1"></button>
    <button v-on:click="subtract(10)">10</button>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            count: 0
        },
        methods: {
            subtract: function(value){
                this.count -= value;
            }
        }
    });
</script>

传入event参数

如果在事件处理函数中,想要获取原生的DOM事件,那么在html代码中,调用的时候,可以传递一个$event参数。

<button v-on:click="subtract(10,$event)">10</button>
...
<script>
...
methods: {
    subtract: function(value,event){
        this.count -= value;
        console.log(event);
    }
}
...
</script>

计算属性和监听器

一般情况下属性都是放到data中的,但是有些属性可能是需要经过一些逻辑计算后才能得出来,那么我们可以把这类属性变成计算属性。

<div id="app">
    <label for="length">长:</label>
    <input type="number" name="length" v-model:value="length">
    <label for="width">宽:</label>
    <input type="number" name="width" v-model:value="width">
    <label for="area">面积:</label>
    <input type="number" name="area" v-bind:value="area" readonly>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            length: 0,
            width: 0,
        },
        computed: {
            area: function(){
                return this.length*this.width;
            }
        }
    });
</script>

可能有的小伙伴会觉得这个计算属性跟我们之前学过的函数好像有点重复。实际上,计算属性更加智能,他是基于它们的响应式依赖进行缓存的。也就是说只要相关依赖(比如以上例子中的area)没有发生改变,那么这个计算属性的函数不会重新执行,而是直接返回之前的值。这个缓存功能让计算属性访问更加高效。

计算属性的set

计算属性默认只有get,不过在需要时你也可以提供一个set,但是提供了set就必须要提供get方法。
在data数据发生改变时,get会自动调用并且获得改变的值,set在绑定属性发生改变时可以获取改变的值

<div id="app">
    <div>
        <label>省:</label>
        <input type="text" name="province" v-model:value="province">
    </div>
    <div>
        <label>市:</label>
        <input type="text" name="city" v-model:value="city">
    </div>
    <div>
        <label>区:</label>
        <input type="text" name="district" v-model:value="district">
    </div>
    <div>
        <label>详细地址:</label>
        <input type="text" name="address" v-model:value="address">
    </div>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            district: "",
            city: "",
            province: ""
        },
        computed: {
            address: {
                get: function(){
                    let result = "";
                    if(this.province){
                        result = this.province + "省";
                    }
                    if(this.city){
                        result += this.city + "市";
                    }
                    if(this.district){
                        result += this.district + "区";
                    }
                    return result;
                },
                set: function(newValue){
                    let result = newValue.split(/||/)
                    if(result && result.length > 0){
                        this.province = result[0];
                    }
                    if (result && result.length > 1){
                        this.city = result[1];
                    }
                    if(result && result.length > 2){
                        this.district = result[2];
                    }
                }
            }
        }
    });
</script>

监听属性

监听属性可以针对某个属性进行监听,只要这个属性的值发生改变了,那么就会执行相应的函数。

<div id="app">
    <div>
        <label>搜索:</label>
        <input type="text" name="keyword" v-model:value="keyword">
    </div>
    <div>
        <p>结果:</p>
        <p>{{answer}}</p>
    </div>
</div>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            keyword: "",
            answer: ""
        },
        watch: {
            keyword: function(newKeyword,oldKeyword){
                this.answer = '加载中...';
                let that = this;
                setTimeout(function(){
                    that.answer = that.keyword;
                },Math.random()*5*1000);
            }
        } 
    });
</script>

深度监控

如果监控的是一个对象,需要进行深度监控,才能监控到对象中属性的变化,例如:

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>vuejs测试</title>
</head>

<body>
	<div id="app">
		<input v-model="message" />
		<hr><br>
		<input v-model="person.name"><br>
		<input v-model="person.age"> <button @click="person.age++">+</button>
		<h2>
			姓名为:{{person.name}};年龄为:{{person.age}}
		</h2>
	</div>
	<script src="node_modules/vue/dist/vue.js"></script>
	<script>
		var app = new Vue({
			el: "#app",//el即element,要渲染的页面元素
			data: {
				message: "hello vue",
				person: { "name": "itcast", "age": 12 }
			},
			watch: {
				message(newValue, oldValue) {
					console.log("新值:" + newValue + ";旧值:" + oldValue);
				},
				person: {
					//开启深度监控,可以监控到对象属性值的变化
					deep: true,
					//监控的处理方法
					handler(obj) {
						console.log("name = " + obj.name + ", age=" + obj.age);
					}
				}
			}
		});
	</script>
</body>

</html>

以前定义监控时,person是一个函数,现在改成了对象,并且要指定两个属性:
deep:代表深度监控,不仅监控person变化,也监控person中属性变化
handler:就是以前的监控处理函数

表单输入绑定

v-model指定可以实现表单值与属性的双向绑定。即表单元素中更改了值会自动的更新属性中的值,属性中的值更新了会自动更新表单中的值。

绑定的属性和事件:
v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件:

  1. text和textarea元素使用value属性和input事件。
  2. checkbox和radio使用checked属性和change事件。
  3. select字段将value作为prop并将change作为事件。

表单元素绑定

input绑定(绑定value)

v-model是v-model:value的缩写,改变 input标签中的值 可以改变下面的属性
<input v-model="message" placeholder="请输入...">
<input v-model:value="message" placeholder="请输入...">
<p>输入的内容是:{{ message }}</p>
new Vue({
  el: '#example-3',
  data: {
    message: ""
  }
})

textarea绑定(绑定value)

<span>输入的内容是:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<br>
<textarea v-model="message" placeholder="请输入多行内容..."></textarea>

checkbox绑定(绑定checked)

<div id='example-3'>
  <input type="checkbox"  value="Jack" v-model="checkedNames">
  <label for="jack">Jack</label>
  <input type="checkbox"  value="John" v-model="checkedNames">
  <label for="john">John</label>
  <input type="checkbox"  value="Mike" v-model="checkedNames">
  <label for="mike">Mike</label>
  <br>
  <span>Checked names: {{ checkedNames }}</span>
</div>
new Vue({
  el: '#example-3',
  data: {
    checkedNames: []
  }
})

radio绑定(绑定checked)

<div id="example-4">
    <input type="radio" value="男" v-model="gender">
    <label></label>
    <br>
    <input type="radio" value="女" v-model="gender">
    <label></label>
    <br>
    <span>Picked: {{ gender }}</span>
</div>
new Vue({
  el: '#example-4',
  data: {
    gender: ''
  }
})

select绑定(绑定prop)

<div id="example-5">
    <select v-model="selected">
        <option disabled value="">请选择</option>
        # 如果有value值 选择的就是value值
        <option value="1">A</option>
        <option>B</option>
        <option>C</option>
    </select>
    <span>Selected: {{ selected }}</span>
</div>
new Vue({
  el: '...',
  data: {
    selected: ''
  }
})

修饰符

.lazy
在默认情况下,v-model在每次input事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加lazy修饰符,从而转变为使用change事件进行同步,即在鼠标失焦时才更新:

<!--"change"时而非"input"时更新 光标移除input输入框的时候 -->
<input type="text" v-model:value.lazy="message">
<input v-model.lazy="message" >
new Vue({
  el: '#app',
  data: {
    message: ''
  }
})

.number
如果想自动将用户的输入值转为数值类型,可以给v-model添加number修饰符

<input v-model.number="age" type="number">

这通常很有用,因为即使在type="number"时,HTML输入元素的值也总会返回字符串。如果这个值无法被parseFloat()解析,则会返回原始的值。

.trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符

<input v-model.trim="msg">

.stop :阻止事件冒泡

.prevent :阻止默认事件发生

.self :只有元素自身触发事件才执行。

.once :只执行一次

.left : 左键事件

.right : 右键事件

.middle : 中间滚轮事件

自定义组件

有时候有一组html结构的代码,并且这个上面可能还绑定了事件。然后这段代码可能有多个地方都被使用到了,如果都是拷贝来拷贝去,很多代码都是重复的,包括事件部分的代码都是重复的。那么这时候我们就可以把这些代码封装成一个组件,以后在使用的时候就跟使用普通的html元素一样,拿过来用就可以了。

定义全局组件

<script>
	//定义组件
	const counter = {
		template: "<button @click='num++'>你点击了{{num}}次;我记住了</button>",
		data() {
			return { num: 0 }
		}
	};
	//全局注册组件;参数1:组件名称,参数2:组件
	Vue.component("counter", counter);
	var app = new Vue({
		el: "#app"
	});
</script>

局部注册

一旦全局注册,就意味着即便以后你不再使用这个组件,它依然会随着Vue的加载而加载。
因此,对于一些并不频繁使用的组件,会采用局部注册。
先在外部定义一个对象,结构与创建组件时传递的第二个参数一致:
然后在Vue中使用它:

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>vuejs测试</title>
</head>

<body>
	<div id="app">
		<!--使用定义好的全局组件-->
		<counter></counter>
		<counter></counter>
		<counter></counter>
	</div>
	<script src="node_modules/vue/dist/vue.js"></script>
	<script>
		//定义组件
		const counter = {
			template: "<button @click='num++'>你点击了{{num}}次;我记住了</button>",
			data() {
				return { num: 0 }
			}
		};
		//全局注册组件;参数1:组件名称,参数2:组件
		//Vue.component("counter", counter);
		var app = new Vue({
			el: "#app",
			//局部注册组件
			components: {
				counter: counter
			}
		});
	</script>
</body>

</html>

基本使用

<div id="app">
    <button-counter></button-counter>
    <button-counter></button-counter>
    <button-counter></button-counter>
</div>
<script>
    Vue.component('button-counter', {
        template: '<button v-on:click="count+=1">点击了{{ count }}次</button>'
        data: function(){
            return {
                count: 0
            }
        },
    });
    let vm = new Vue({
        el: "#app",
        data: {}
    });
</script>

以上我们创建了一个叫做button-counter的组件,这个组件实现了能够记录点击了多少次按钮的功能。后期如果我们想要使用,就直接通过button-counter使用就可以了。然后因为组件是可复用的Vue实例,所以它们与new Vue接收相同的选项,例如data、computed、watch、methods以及生命周期钩子等。仅有的例外是像el这样根实例特有的选项。另外需要注意的是:组件中的data必须为一个函数!

给组件添加属性

像原始的html元素都有自己的一些属性,而我们自己创建的组件,也可以通过prop来添加自己的属性。这样别人在使用你创建的组件的时候就可以传递不同的参数了

<div id="app">
    <blog-post v-for="blog in blogs" :title="blog.title"></blog-post>
    <blog-post v-bind:blogs="blogs"></blog-post>
</div>
<script>
    Vue.component('blog-post', {
        props: ['blogs'],
        template: `
        <table>
            <tr>
                <th>序号</th>  
                <th>标题</th>  
            </tr>  
            <tr v-for="(blog,index) in blogs">
                <td>{{index+1}}</td>
                <td>{{blog.title}}</td>
            </tr>
        </table>
        `
    })
    new Vue({
        el: "#app",
        data: {
            blogs: [
                {"title":"钢铁是怎样练成的?","id":1},
                {"title":"AI会毁灭人类吗?","id":2},
                {"title":"如何学好Vue!","id":3},
            ]
        }
    });
</script>

单一根元素

如果自定义的组件中,会出现很多html元素,那么根元素必须只能有一个,其余的元素必须包含在这个根元素中。比如以下是一个组件中的代码,会报错:

<h3>{{ title }}</h3>
<div v-html="content"></div>

我们应该改成:

<div class="blog-post">
  <h3>{{ title }}</h3>
  <div v-html="content"></div>
</div>

子组件事件和传递事件到父组件

子组件中添加事件跟之前的方式是一样的,然后如果发生某个事件后想要通知父组件,那么可以使用this. e m i t 函 数 来 实 现 。 当 点 击 组 件 的 多 选 框 , 会 调 用 组 件 的 o n C h e c k 函 数 , o n C h e c k 会 用 emit函数来实现。 当点击组件的多选框,会调用组件的onCheck函数,onCheck会用 emitonCheckonCheckemit调用check-changed即checks并传参,改变componentblog

<div id="app">
    <blog-item v-for="blog in blogs" v-bind:blog="blog" @check-changed="checks"></blog-item>    
    
    <div v-for="blog in componentblog">
        {{blog.title}}
    </div>
</div>
<script>
    Vue.component('blog-item',{
        props:['blog'],
        template:`
        <div>
            <span>{{blog.title}}</span>
            <input type="checkbox" @click="onCheck">   
        </div>
        `,
        methods:{
            onCheck:function(){
                // console.log(123)
                this.$emit('check-changed',this.blog)
            }
        }
    })
    new Vue({
        el: '#app',
        data: {
            blogs:[
                {"title":"欢迎来到逻辑!","id":1},
                {"title":"你今天学习了嘛?","id":2},
                {"title":"如何学好Vue!","id":3},
            ],
            componentblog:[]
        },
        
        methods:{
            checks:function(blog){
                // indexOf 判断某个元素在数组中的位置,返回下标
                var index = this.componentblog.indexOf(blog)
                if(index >= 0){
                    this.componentblog.splice(index,1)
                }else{
                    this.componentblog.push(blog)
                }
                console.log(blog)
            }
        }
    })
</script>

传递复杂数据

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>vuejs测试</title>
</head>

<body>
	<div id="app">
		<h2>传智播客开设的课程有:</h2>
		<!-- 接受来自父组件的属性值,使用v-bind指向父组件的属性lessons;注意使用my-list -->
		<my-list :items="lessons"></my-list>
	</div>
	<script src="node_modules/vue/dist/vue.js"></script>
	<script>
		//定义组件
		const myList = {
			//可以使用双引号、单引号或者如下使用的 ` 飘号
			template: `
			<ul>
				<li v-for="item in items" :key="item.id">{{item.id}}--{{item.name}}</li>
			</ul>
			`,
			//定义接收来自父组件的属性
			props: {
				//定义模版中使用的属性
				items: {
					//必须为数组类型
					type: Array,
					//默认为空数组
					default: []
				}
			}
		};
		var app = new Vue({
			el: "#app",
			data: {
				msg: "父组件中的msg属性的内容",
				lessons: [
					{ "id": 1, "name": "Java" },
					{ "id": 2, "name": "PHP" },
					{ "id": 3, "name": "前端" }
				]
			},
			//注册组件
			components: {
				//如果组件key和value一致可以简写如下
				myList
			}
		});
	</script>
</body>
</html>

items:是要接收的属性名称
type:限定父组件传递来的必须是数组,否则报错;type的值可以是Array或者Object(传递对象的
时候使用)
default:默认值,
default,如果是对象则需要写成方法的方式返回默认值。如:

default(){
return {"xxx":"默认值"};
}

需要注意的是,因为html中大小写是不敏感的,所以在定义子组件传给父组件事件名称的时候,不要使用myEvent这种驼峰命名法,而是使用my-event这种规则。

自定义组件v-model

一个组件上的v-model默认会利用名为value的prop(属性)和名为input的事件,但是像单选框、复选框等类型的输入控件可能会将value特性用于不同的目的。这时候我们可以在定义组件的时候,通过设置model选项可以用来实现不同的处理方式

<div id="app">
    <stepper v-model:value="goods_count"></stepper>
</div>
<script>
     Vue.component('stepper',{
        props:['count'],
        model:{
            event: 'count-changed',
            prop: "count"
        },
        template:`
        <div>
            <button @click="sub">-</button>  
            <span>{{count}}</span>
            <button @click="add">+</button>  
        </div>
        `,
        methods:{
            sub:function(){
                this.$emit("count-changed", this.count-1)
            },
            add:function(){
                this.$emit("count-changed", this.count+1)
            }
        }
    });
    new Vue({
        el: "#app",
        data:{
            "goods_count":0
        }
    })
</script>

其中的props定义的属性分别是给外面调用组件的时候使用的。model中定义的prop:'count’是告诉后面使用v-model的时候,要修改哪个属性;event:'count-changed’是告诉v-model,后面触发哪个事件的时候要修改属性。

插槽

我们定义完一个组件后,可能在使用的时候还需要往这个组件中插入新的元素或者文本。这时候就可以使用插槽来实现。

<div id="app">
    <navigation-link url="/profile/">
        个人中心
    </navigation-link>
</div>
<script>
    Vue.component('navigation-link', {
        props: ['url'],
        template: `
        <a v-bind:href="url" class="nav-link">
            <slot></slot>
        </a>
        `
    })
    new Vue({
        el: "#app"
    });
</script>

当组件渲染的时候,将会被替换为“个人中心”。插槽内可以包含任何模板代码,包括HTML:

<navigation-link url="/profile">
  <!-- 添加一个 Font Awesome 图标 -->
  <span class="fa fa-user"></span>
  个人中心
</navigation-link>
如果没有包含一个元素,

则该组件起始标签和结束标签之间的任何内容都会被抛弃。

生命周期函数

生命周期函数代表的是Vue实例,或者是Vue组件,在网页中各个生命阶段所执行的函数。生命周期函数可以分为创建阶段和运行期间以及销毁期间。
其中创建期间的函数有beforeCreate、created、beforeMount、mounted;
运行期间的函数有beforeUpdate、updated;
销毁期间有beforeDestroy、destroyed。
以下是官方文档给到的一张图,从这种图中我们可以了解到每个部分执行的函数。
在这里插入图片描述

创建期间:

beforeCreate
Vue或者组件刚刚实例化,data、methods都还没有被创建。

created
此时data和methods已经被创建,可以使用了。模板还没有被编译。

beforeMount
created的下一阶段。此时模板已经被编译了,但是并没有被挂在到网页中。

mounted
模板代码已经被加载到网页中了。此时创建期间所有事情都已经准备好了,网页开始运行了。

运行期间:

beforeUpdate
在网页网页运行期间,data中的数据可能会进行更新。在这个阶段,数据只是在data中更新了,但是并没有在模板中进行更新,因此网页中显示的还是之前的。

updated
数据在data中更新了,也在网页中更新了。

销毁期间:

beforeDestroy
Vue实例或者是组件在被销毁之前执行的函数。在这一个函数中Vue或者组件中所有的属性都是可以使用的。

destroyed
Vue实例或者是组件被销毁后执行的。此时Vue实例上所有东西都会解绑,所有事件都会被移除,所有子元素都会被销毁。

过滤器

过滤器就是数据在真正渲染到页面中的时候,可以使用这个过滤器进行一些处理,把最终处理的结果渲染到网页中。

过滤器使用

过滤器可以用在两个地方:双花括号插值**和v-bind表达式 (后者从2.1.0+开始支持)。过滤器应该被添加在JavaScript表达式的尾部,由“管道”符号指示:

<!-- 在双花括号中 -->
{{ message|capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId|formatId"></div>

过滤器定义

你可以在一个组件的选项中定义本地的过滤器

filters: {
  capitalize: function (value) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
  }
}

或者在创建 Vue 实例之前全局定义过滤器

Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})
new Vue({
  // ...
})

Vuejs ajax

axios可以使用的方法有:

axios(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])

config请求配置

这些是创建请求时可以用的配置选项。只有 url 是必需的。如果没有指定 method ,请求将默认使用 get 方法。

{
	// `url` 是用于请求的服务器 URL
	url: '/user',
	// `method` 是创建请求时使用的方法
	method: 'get', // 默认是 get
	// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
	// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
	baseURL: 'https://some-domain.com/api/',
	// `transformRequest` 允许在向服务器发送前,修改请求数据
	// 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
	// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
	transformRequest: [function (data) {
	// 对 data 进行任意转换处理
	return data;
	}],
	// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
	transformResponse: [function (data) {
	// 对 data 进行任意转换处理
	return data;
	}],
	// `headers` 是即将被发送的自定义请求头
	headers: {
	'X-Requested-With': 'XMLHttpRequest',
	'Content-Type': 'application/json'
	},
	// `params` 是即将与请求一起发送的 URL 参数
	// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
	params: {
	ID: 12345
	},
	// `data` 是作为请求主体被发送的数据
	// 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
	// 在没有设置 `transformRequest` 时,必须是以下类型之一:
	// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
	// - 浏览器专属:FormData, File, Blob
	// - Node 专属: Stream
	data: {
	firstName: 'Fred'
	},
	// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
	// 如果请求话费了超过 `timeout` 的时间,请求将被中断
	timeout: 1000,
	// `withCredentials` 表示跨域请求时是否需要使用凭证
	withCredentials: false, // 默认的
	// `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document',
	'json', 'text', 'stream'
	responseType: 'json', // 默认的
	// `maxContentLength` 定义允许的响应内容的最大尺寸
	maxContentLength: 2000,
	// `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。如果
	`validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否
	则,promise 将被 rejecte
	validateStatus: function (status) {
	return status >= 200 && status < 300; // 默认的
	},
	// `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
	// 如果设置为0,将不会 follow 任何重定向
	maxRedirects: 5 // 默认的
}

响应结构

{
	// `data` 由服务器提供的响应
	data: {},
	// `status` 来自服务器响应的 HTTP 状态码
	status: 200,
	// `statusText` 来自服务器响应的 HTTP 状态信息
	statusText: 'OK',
	// `headers` 服务器响应的头
	headers: {},
	// `config` 是为请求提供的配置信息
	config: {}
}

使用 then 时,你将接收下面这样的响应:

axios.get('/user/12345')
	.then(function(response) {
	console.log(response.data);
	console.log(response.status);
	console.log(response.statusText);
	console.log(response.headers);
	console.log(response.config);
});

axios(config)

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>vuejs测试</title>
	<script src="js/vue-2.6.10.js"></script>
	<script src="js/axios.min.js"></script>
</head>

<body>
	<div id="app">
		<ul>
			<li v-for="(user,index) in users" :key="index">
				{{index}}--{{user.name}}--{{user.age}}--{{user.gender}}
			</li>
		</ul>
	</div>
	<script>
		var app = new Vue({
			el: "#app",
			data: {
				users: []
			},
			created() {
				//加载数据
				axios({
					method: "get",
					url: "data.json"
				}).then((res) => {
					console.log(res);
					//将获取数据设置到users属性
					app.users = res.data;
				}).catch(error => {
					alert(error);
				});
			}
		});
	</script>
</body>
</html>

get方法示例

将上述示例中的axios操作部分修改为如下:

axios.get("data.json")
	.then( res => {
		console.log(res);
		//将获取数据设置到users属性
		app.users = res.data;
	}).catch(error =>{
	console.log(error)
});

post方法示例

axios.post("data.json")
	.then( res => {
		console.log(res);
		//将获取数据设置到users属性
		app.users = res.data;
	}).catch(error =>{
	console.log(error)
});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值