随着前端页面开发越来越复杂,用户与数据的交互也越来越繁杂,而很多交互都是临时性的,没必要每一次都要和服务器中的模型对象进行交互,但是传统的jQuery等函数库又力不从心,这时MVVM模式就应运而生了。
View<=>ViewModel<=>Model
基本流程
基本术语
{
{name}}
- 实例:Vue本身就是一个构造函数,可以用来创建对象,使用Vue第一步,就是要创建一个Vue实例:
new Vue()
,完成对挂载点的所有DOM操作:增删改查,条件判断与循环遍历,事件等;- 实例参数:Vue()接受一个js字面量对象作为参数,所有的功能,都以对象属性的方式进行设置;
- 挂载点:Vue实例的作用域,本质上就是通过css选择器获取到的页面元素:
;
- 模板:带有HTML标签的字符串,挂载点内的内容, 实例中数据的载体/显示位置:
;
{ {site}}
- 值/变量:挂载点中的文本内容;
- 属性:描述模板或HTML标签;
- 事件:模板或元素上发生的系统或用户事件,例如:点击、移动等;
- 渐进式:就是你可以一步一步、有阶段性地来使用Vue.js,不必一开始就使用所有的东西;
通过构造函数Vue
就可以创建一个Vue的根实例,el
用于指定一个页面中已存在的DOM元素来挂载Vue实例,它可以是HTMLElement
,也可以是CSS选择器:
id="app">
const app = new Vue({
el:document.getElementById('app') //或则是'#app'
})
挂载成功后,我们可以通过app.$el来访问该元素。
创建Vue实例传入的options:
每个Vue实例创建时,都会经历一系列的初始化过程,同时也会调用相应的生命周期钩子,Vue的生命周期钩子比较常用的有:
这些钩子与el和data类似,也是作为选项写入Vue实例内,并且钩子的this指向的是调用它的Vue实例。
XXX
{ {XX}}
(Mustache语法)或 v-text 指令<div id="app">
<p>{
{name}}p>
<p v-text="sex">p>
<p v-html="msg">p>
<p v-bind:title="title">听妈妈的话p>
<p v-bind:title="'赵雷'">成都p>
<p>{
{num * 2}}p>
<p>{
{name.slice(0,4).toUpperCase()}}p>
div>
<script>
const vm = new Vue({
el:"#app",
data:{
name:'Thinco',
sex:'man',
msg:'hello world!',
title:'周杰伦',
num: 100
}
})
script>
【注意】:
v-html
输出后,有可能导致XSS攻击,所以要在服务端对用户提交的内容进行处理,一般可将尖括号“<>”转义。v-pre
即可跳过这个元素和它的子元素的编译过程,例如:{
{这里的内容是不会被编译的}}
{
{var book = 'Vue.js'}}
{
{if (ok) return msg}}
Vue.js支持在{ {}}插值的尾部添加一个管道符“(|)”对数据进行过滤,经常用于格式化文本,比如字母全部大写、货币千位使用逗号分隔等。过滤的规则是自定义的,通过给Vue实例添加选项filters来设置。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式。
{
{ message | capitalize }}
<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({
// ...
})
当全局过滤器和局部过滤器重名时,会采用局部过滤器。过滤器可以串联,也可以接收参数,例如:
{
{message | filterA | filterB}}
{
{message | filterA('arg1','arg2')}}
【注意】:过滤器应当用于处理简单的文本转换,如果要实现更为复杂的数据变换,应该使用计算属性。
【计算属性的定义与用途】
【计算属性用法】
在一个计算属性里可以完成各种复杂的逻辑,包括运算、函数调用等,只要最终返回一个结果就可以。
每一个计算属性都包含一个getter和一个setter,绝大多数情况下,我们只会用默认的getter方法来读取一个计算属性,在业务中很少用到setter,所以在申明一个计算属性时,可以直接使用默认的写法,不必将getter和setter都声明。
姓名:{
{fullName}}
姓名:{
{allName}}
计算属性还有两个很实用的小技巧:
【计算属性缓存】
你可能发现调用methods里的方法也可以与计算属性起到同样的作用。使用计算属性还是methods取决于你是否需要缓存,当遍历大数组和做大量计算时,应当使用计算属性,除非你不希望得到缓存。
计算属性与方法属性之间的关系:
<div id="app">
<p>
品名:{
{name}}<br>
价格:<input type="number" v-model.number="price"><br>
数量:<input type="number" v-model.number="number">
p>
<p>金额:{
{total}}元p>
<p>金额:{
{total1()}}元p>
div>
<script>
let vm = new Vue({
el: "#app",
data: {
name: 'iphoneXR',
price: 0,
number: 0
},
//计算属性/派生属性
computed: {
total: function () {
return this.price * this.number;
}
},
//方法属性
methods: {
total1: function () {
return this.price * this.number;
}
},
})
script>
【实例的监听属性: watch】
watch: 该对象属性是要监听的实例数据对象,包括计算属性
【监听属性的回调函数与传参】
<div id="app">
<p>用户名:<input v-model="username" type="text">p>
{
{username}}
div>
<script>
const vm = new Vue({
el:"#app",
data:{
username:'',
userList:['jay','thinco']
},
//监听属性/监听器
watch:{
//监听回调函数的参数(当前的值/已更新值,第二个参数可选)
username:function(newValue,oldValue){
this.userList.forEach(function(value){
if(newValue == value){
alert("该用户已经存在");
}
})
}
}
});
script>
<div id="app">
<textarea v-model="text">{
{text}}textarea>
div>
<script>
let vm = new Vue({
el: "#app",
data: {
//用户输入的内容
text: "",
//敏感词汇
sensitive: [
'逃课', "发呆", "迟到", "早退"
]
},
watch: {
text: function (value) {
this.sensitive.forEach(function (words) {
if (value.indexOf(words) !== -1) {
//存在敏感词
alert("请不要输入敏感词汇");
location.reload();
}
})
}
}
})
script>
(1) 原生JS实现一个留言板
<div id="app">
<input type="text" >
<button>提交button>
<ul>ul>
div>
<script>
//获取元素
let input = document.getElementsByTagName('input')[0];
let button = document.getElementsByTagName('button')[0];
let ul = document.getElementsByTagName('ul')[0];
button.onclick = function(){
//创建元素
let li = document.createElement('li');
//添加内容
li.innerHTML = input.value;
//添加到页面
if(ul.children.length == 0){
//没有子节点
ul.appendChild(li);
}else{
let first = ul.firstChild;
ul.insertBefore(li,first);
}
//清空input
input.value = '';
}
script>
(2) Vue实现一个留言板
<h4>留言板h4>
<div id="app">
<input type="text" v-model="input" placeholder="请输入内容" >
<button @click="fill">提交button>
<ul>
<li v-for='(item,index) in list'>{
{item}}
<button @click="del(index)">删除button>
li>
ul>
div>
<script>
let vm = new Vue({
el:"#app",
data:{
input:'',
list:[]
},
methods:{
//添加
fill:function(){
//尾部添加
//this.list.push(this.input);
//头部添加
this.list.unshift(this.input);
//清空留言区
this.input = '';
},
//删除
del:function(index){
if(confirm('真的删除吗?')){
this.list.splice(index,1);
}
}
}
});
script>
<div id="app">
<h4>用户注册h4>
<p>
<label for="username">用户名:label>
<input type="text" id="username" v-model.lazy.trim="username" @input="input" @keyup.delete="resumeName">
<span v-show="nameError" :style="error">{
{username}}用户名已存在,请更换span>
p>
<p>
<label for="email">邮箱:label>
<input type="email" id="email" v-model.lazy.trim="email" @input="input" @keyup.delete="resumeEmail">
<span v-show="emailError" :style="error">{
{email}}邮箱已注册过,请更换span>
p>
<p>
<button @click="submit">登录button>
<span :style="error">{
{tips}}span>
p>
div>
<script>
let vm = new Vue({
el:'#app',
data:{
//用户名
username:'',
//邮箱
email:'',
//用户名验证提示状态
nameError:false,
//邮箱验证提示显示状态
emailError:false,
//设置错误信息的文本样式
error:{
color:'red'},
//登录提示信息
tips:'',
//已存在用户名列表
userList:['admin','thinco','jay'],
//已注册过的邮箱
emailList:['[email protected]','[email protected]']
},
//监听器
watch:{
//监听用户名
username:function(value){
//如果冲突则提示用户
this.userList.forEach(function(name){
if(name === value){
this.nameError = true;
}
},this)
},
//监听邮箱的更新
email:function(value){
//如果冲突则提示用户
this.emailList.forEach(function(name){
if(name === value){
this.emailError = true;
}
},this)
},
},
//事件响应方法
methods:{
submit:function(){
//非空判断
if(this.username.length === 0 && this.email.length === 0){
this.tips = '用户名和邮箱不能为空';
//验证通过
}else if(this.nameError === false && this.emailError === false){
this.error = {
color: 'green'};
this.tips = '验证通过,正在跳转';
setTimeout(function(){
location.href = 'index.php';
},1000);
}else{
this.tips = '用户名或邮箱错误';
}
},
input:function(){
this.tips = '';
},
//当按下删除或退格键时触发,应该关闭错误
resumeName:function(){
this.nameError = false;
},
resumeEmail:function(){
this.emailError = false;
}
}
});
script>
v-
为前缀【v-bind】
可以缩写为::
,基本用途是动态更新HTML元素上的属性。
【v-on】
可以缩写为:@
,用来绑定事件监听器,v-on可以监听原生的DOM事件,表达式除了方法名,也可以直接是一个内联语句。
【v-once】
v-once是一个不需要表达式的指令,作用是定义它的元素或组件只渲染一次,包括元素或组件的所有子节点。首次渲染后,不再随着数据的变化重新渲染,将被视为静态内容。
<div id="app">
<span v-once>{
{message}}span>
div>
...
【v-html】
某些情况下,我们从服务器请求到的数据本身就是一个HTML代码
,可以使用此指令解析出HTML展示。
【v-text】
v-text作用和Mustache一致。
【v-pre】
跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法。
【v-cloak】
v-cloak是一个不需要表达式的指令。在某些情况下,网页还在加载 Vue.js ,而导致 Vue 来不及渲染,我们浏览器可能会直接显然出未编译的Mustache标签。我们可以使用 v-cloak 指令来解决这一问题。
原理是:在vue解析之后,会去除属性v-cloak。
<style>
[v-cloak]{
display: none; }
style>
<div id="app" v-cloak>
{
{context}}
div>
【注意】:
在简单项目中,使用 v-cloak 指令是解决屏幕闪动的好方法。但在大型、工程化的项目中(webpack、vue-router)只有一个空的 div 元素,元素中的内容是通过路由挂载来实现的,这时我们就不需要用到 v-cloak 指令。
【语法糖】
语法糖是指在不影响功能的情况下,添加某种方法实现同样的效果,从而方便程序开发。Vue.js的v-bind和v-on指令都提供了语法糖,也可以说是缩写。
<h2 :class="{
'active': isActive}">Hello Worldh2>
<h2 class="title" :class="{
'active': isActive, 'line': isLine}">Hello Worldh2>
<h2 class="title" :class="classes">Hello Worldh2>
<h2 class="title" :class="getClasses()">Hello Worldh2>
:class
设置一个对象,可以动态地切换class,对象中也可以传入多个属性,来动态切换class。另外,:class
可以与普通class共存。:class内的表达式每项为真时,对应的类名就会加载。
- 一般当条件多于两个时,都可以绑定到data或computed、methods。
- 数组语法
<h2 :class="['active']">Hello Worldh2>
<h2 :class="[active, 'line']">Hello Worldh2>
<h2 class="title" :class="['active', 'line']">Hello Worldh2>
<h2 class="title" :class="classes">Hello Worldh2>
- 当需要应用多个class时,可以使用数组语法,给:class绑定一个数组。
<div id="app">
<div :class="[activeCls,errorCls]">div>
div>
<script>
let app = new Vue({
el:'#app',
data:{
activeCls:'active',
errorCls:'error'
}
})
script>
- 也可以根据三元表达式来切换class。
- 当然,与对象语法一样,也可以使用data、computed、methods三种方法来实现。
使用计算属性给元素设置类名,在业务中经常用到,尤其是在写复用的组件时,所以在开发过程中,如果表达式较长或逻辑复杂,应该尽可能地优先使用计算属性。
(2) 绑定内联样式
使用:style
可以给元素绑定内联样式,方法与:class
类似,也有对象语法和数组语法。
- CSS属性名称可以:
- 使用驼峰命名(camelCase),如:fontSize。
- 或短横线分隔命名(kebab-case),记得用单引号括起来,如:‘font-size’,否则会当做变量去解析。
- 大多数情况下,直接写一长串的样式不便于阅读和维护,所以一般写在data或computed里。
- 在实际业务中,
:style
的数组语法并不常用,因为往往可以写在一个对象里面;而较为常用的应当是计算属性。
- 使用
:style
时,Vue.js会自动给特殊的CSS属性名称增加前缀,比如transform。
【绑定方式一:对象语法】
<div :style="{
color: currentColor, fontSize: fontSize + 'px'}" >div>
style后面跟的是一个对象类型:
- 对象的key是CSS属性名称
- 对象的value是具体赋的值,值可以来自于data中的属性
【绑定方式二:数组语法】
<div :style="[baseStyles, overridingStyles]">div>
style后面跟的是一个数组类型,多个值以,
分割即可。
【在组件上使用】
如果直接在自定义组件上使用class或:class
,样式规则会直接应用到这个组件的根元素上。如果需要给具体的子元素设置类名时,应当使用组件的props
来传递。这些用法同样适用于绑定内联样式style的内容。
4.3 条件渲染指令
【v-if、v-else-if、v-else指令】
控制模板元素的存在或移除,移除是真正的删除了该元素。
与JavaScript的条件语句if、else、else if类似,Vue.js的条件指令可以根据表达式的值在DOM中渲染或销毁元素/组件。
<div id="app">
<p v-if="status === 1">当status为1时显示该行p>
<p v-else-if="status === 2">当status为2时显示该行p>
<p v-else>否则显示该行p>
div>
...
Vue在渲染元素时,出于效率考虑,会尽可能地复用已有的元素而非重新渲染,比如:
<div id="app">
<template v-if="type === 'name'">
<label for="">用户名:label>
<input type="text" placeholder="请输入用户名">
template>
<template v-else>
<label for="">邮箱:label>
<input type="text" placeholder="请输入邮箱">
template>
<button @click="handleToggleClick">切换输入类型button>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
let vm = new Vue({
el:'#app',
data:{
type:'name'
},
methods:{
handleToggleClick: function(){
this.type = this.type === 'name' ? 'mail' : 'name';
}
}
})
script>
键入内容后,点击切换按钮,虽然DOM变了,但是之前输入框中键入的内容没有改变,只是替换了placeholder的内容,说明
元素被复用了。
如果你不希望这样做,可以使用Vue.js提供的key属性,它可以让你自己决定是否要复用元素,key的值必须是唯一的。
【v-show指令】
控制模板元素的显示与隐藏,仅仅是用css控制(display:none;)。
当v-show表达式的值为false时,元素会隐藏,查看DOM结构会看到元素上加载了内联样式display:none
。v-show不能在
上使用。
<div id="app">
<p v-if="on">今天天气不错p>
<p v-show="seen">今天天气很好p>
div>
<script>
let vm = new Vue({
el: "#app",
data: {
on: false,
seen: true,
},
})
script>
【v-if和v-show】
v-if和v-show具有类似的功能,不过v-if才是真正的条件渲染,它会根据表达式适当地销毁或重建元素及绑定的事件或子组件。若表达式初始值为false,则一开始元素/组件并不会渲染,只有当条件第一次变为真时才开始编译。
而v-show只是简单的CSS属性的切换,无论条件真与假,都会被编译。相比之下,v-if更适合条件不经常改变的场景,因为它切换开销相对较大,而v-show适用于频繁切换条件。
4.4 列表渲染指令
【v-for】
当需要将一个数组遍历或枚举一个对象循环显示时,就会用到列表渲染指令v-for。它的表达式需结合in来使用,类似item in items
的形式,也支持用of来替代in作为分隔符。遍历数组时,v-for的表达式支持一个可选参数(当前项的索引)。遍历对象时,有两个可选参数(当前项的键名和索引)。v-for还可以迭代整数。
-
v-for 指令
- 循环遍历数组或对象
- 也可遍历整数
-
v-for 指令参数
- v-for=“item in items” 或 v-for=“item of items”
- v-for="(item, index) in items" (遍历数组:item数组元素 index索引)
- v-for="(value, name, index) in items" (遍历对象:value值 name键名 index索引)
<div id="app">
<p>课程列表p>
<ul>
<li v-for="(course,index) in courses" :key="index">{
{index}}:{
{course}}li>
ul>
div>
<script>
let vm = new Vue({
el: "#app",
data: {
courses:['HTML',"CSS","JS","Python"]
},
})
script>
【注意】
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。
【数组更新】
Vue的核心是数据与视图的双向绑定,当我们修改数据时,Vue会检测到数据变化,所以用v-for渲染的视图也会立即更新。Vue包含了一组观察数组变异的方法,使用它们改变数组也会触发视图更新:
- push() 向数组的末尾添加一个或多个元素,并返回新的长度。
- pop() 删除并返回数组的最后一个元素。
- shift() 删除并返回数组第一个元素。
- unshift() 向数组的开头添加一个或更多元素,并返回新的长度。
- splice() 添加或删除数组中的元素。
- sort() 对数组的元素进行排序。
- reverse() 颠倒数组中元素的顺序。
使用它们不会改变原数组,它们返回一个新数组,在使用这些非变异方法时,可以用新数组来替换原数组:
- filter() 创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
- concat() 连接两个或多个数组。
- slice() 从已有的数组中返回选定的元素。
Vue在检测到数组变化时,并不是直接重新渲染整个列表,而是最大化地复用DOM元素。替换的数组中,含有相同元素的项不会被重新渲染,因此可以大胆的用新数组来替换旧数组,不用担心性能问题。
需要注意的是,以下变动的数组中,Vue是不能检测到的,也不会触发视图更新:
- 通过索引直接设置项,比如:app.books[3] = {…}。
- 修改数组长度,比如:app.books.length = 1。
可以用两种方法实现同样的效果,第一种是使用Vue内置的set方法:
//set(要修改的对象,索引值,修改后的值)
Vue.set(app.books,3,{
name: '<>',
author: 'MrThinco'
})
如果是在webpack中使用组件化的方式,默认是没有导入Vue的,这时可以使用$set,例如:
this.$set(app.books,3,{
name: '<>' ,
author: 'MrThinco'
})
//这里this指向的就是当前组件实例,即app。在非webpack模式下也可以用$set方法,例如:app.$set(...)
另一种方法:
app.books.splice(3,1,{
name: '<>',
author: 'MrThinco'
})
【过滤与排序】
当你不想改变原数组,想通过一个数组的副本来做过滤或排序的显示时,可以使用计算属性来返回过滤或排序后的数组。
4.5 方法与事件
【模板中的事件与实例中的方法】
<div id="app">
<button v-on:click="say">点击button>
<button v-on:click="say()">点击button>
<button @click="say()">点击button>
<button v-on:click="write('my name is Thinco')">点击button>
<p>{
{welcome}}p>
div>
<script>
const vm = new Vue({
el:"#app",
data:{
welcome:'',
},
//事件属性:注册事件方法
methods: {
say:function(){
this.welcome = 'hello world!';
},
write:function(text){
this.welcome = text;
}
},
})
script>
【模板指令:v-on】
v-on在事件绑定上,类似原生JavaScript的onclick等写法,也是在HTML上面进行监听的。@click
的表达式可以直接使用JavaScript语句,也可以是一个在Vue实例中methods选项内的函数名。
- 指令:
v-on:事件名称
(与jQuery中命名规则相同)
v-on
可以简写为@
- 按钮点击事件会触发一个方法
- 这个方法声明在vue实例的事件属性中
v-on参数:
- 如果该方法不需要额外参数,那么调用方法的()可以不写,如果此方法本身中有一个参数,那么会默认将原生事件event参数传递进去。
- 事件定义时,如果需要传入其他参数,同时需要event的时候,可以通过$event传入事件。
{
{counter}}
methods:{
handleAdd(event){
console.log(event);
this.counter++;
},
handleAddTen(count,event){
console.log(event);
this.counter += 10;
}
}
【实例属性:methods】
- Vue实例属性methods中声明事件对应的方法函数
- methods是字面量对象方式定义,属性名就是事件函数名
- 事件方法值必须是一个回调函数,可以接收参数
【修饰符】
在上面使用的event.preventDefault()
也可以用Vue事件的修饰符来实现。
- .stop - 调用
event.stopPropagation()
。
- .prevent - 调用
event.preventDefault()
。
- .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
- .native - 监听组件根元素的原生事件。
- .capture - 添加事件侦听器时使用事件捕获模式。
- .self - 只当事件在该元素本身(而不是子元素)触发时触发回调。
- .once - 只触发一次回调。
具体用法如下:
...
...
...
在表单元素上监听键盘事件时,还可以使用按键修饰符,比如按下具体某个按键时才调用方法:
//也可以自己配置具体按键:
Vue.config.keyCodes.f1 = 112;
//全局定义后,就可以使用@keyup.f1
除了具体的某个keyCode外,Vue还提供了一些快捷名称,以下是全部的别名:
- .enter
- .tab
- .delete(捕获“删除”和“退格”键)
- .esc
- .space
- .up
- .down
- .left
- .right
这些按键修饰符也可以组合使用,或和鼠标一起配合使用:
- .ctrl
- .alt
- .shift
- .meta(Mac下是Common键,Windows下是窗口键)
Do something
4.6 表单与v-model
Vue.js提供了v-model指令,用于在表单类元素上双向绑定数据。
【单向绑定与双向绑定】
- 在实例数据变化,引起模板中的数据变化,这是单向数据绑定
- 双向是指模板中的数据变化,同样会引发实例中的数据发生变化
- 支持双向数据绑定的dom元素必须允许用户输入或选择内容
- 双向数据绑定主要应用到表单元素上,例如:input,textarea,select等
【模板指令: v-model】
- v-model指令适用于表单元素上进行双向的数据绑定
在使用v-model时,如果是使用中文输入法输入中文,一般在没有选定词组前,也就是在拼音阶段,Vue是不会更新数据的,当敲下汉字时才会触发更新。如果希望总是实时更新,可以用@input
来替代v-model。
- 单选按钮:
- 单选按钮在单独使用时,不需要v-model,直接使用v-bind绑定一个布尔类型的值,为真时选中,为否时不选中。
- 如果是组合使用来实现互斥选择的效果,就需要v-model配合value来使用。
- 复选框:
- 单独使用时,是用v-model来绑定一个布尔值。
- 组合使用时,也是v-model与value一起,多个勾选框都绑定到同一个数组类型的数据,value的值在数组当中,就会选中这一项。这一过程是双向的,在勾选时,value的值也会自动push到这个数组中。
- 选择列表:
分为单选和多选两种方式。因为它的样式依赖平台和浏览器,无法统一,也不太美观,功能也受限,所以常见的解决方案是用div模拟一个类似的控件。
<div id="app">
<p>用户名:<input v-model="username" type="text" placeholder="用户名不少于6个字符">p>
<p>您输入的内容是:{
{username}}p>
<p>
<select v-model="level" name="" id="">
<option value="1">vip1option>
<option value="2">vip2option>
<option value="3">vip3option>
select>
p>
<p>您的等级是:{
{level}}p>
<input type="radio" :checked="picked1">
<input type="radio" v-model="picked2" value="html">
<input type="radio" v-model="picked2" value="js">
<input type="radio" v-model="picked2" value="css">
<input type="checkbox" v-model="checked1" id="checked">
<label for="checked">选择状态:{
{checked1}}label>
<input type="checkbox" v-model="checked2" value="html">
<input type="checkbox" v-model="checked2" value="js">
<input type="checkbox" v-model="checked2" value="css">
div>
<script>
const vm = new Vue({
el:"#app",
data:{
username:'',
level:'1', //默认选中 'vip1'
picked1: true,
picked2: 'js', //默认选中'js'
checked1: false,
checked2: ['html','css']
}
})
script>
【绑定值】
v-model绑定的值是一个静态字符串或布尔值,但在业务中,有时需要绑定一个动态的数据,这时可以用v-bind来实现。
【修饰符】
与事件的修饰符类似,v-model也有修饰符,用于控制数据同步的时机。
- .lazy
在输入框中,v-model默认是在input事件中同步输入框的数据(除了提示中介绍的中文输入法情况外),使用修饰符.lazy会转变为在change事件中同步。在失焦或按回车时才更新。
- .number
使用修饰符.number可以将输入转换为Number类型,否则虽然你输入的是数字,但它的类型其实是String。
- .trim
修饰符.trim可以自动过滤输入的首尾空格。
【v-model原理】
v-model其实是一个语法糖,它的背后本质上是包含两个操作:
- v-bind绑定一个value属性
- v-on指令给当前元素绑定input事件
等同于
4.7 开发案例:购物车
书籍名称
出版日期
价格
购买数量
操作
{
{item.id}}
{
{item.name}}
{
{item.date}}
{
{item.price|showPrice}}
{
{item.count}}
总价格:{
{totalPrice|showPrice}}
购物车为空
五、组件开发
5.1 Vue组件
(1)组件的定义
组件(component),是Vue.js最强大的功能之一,可以扩展模板功能,封装可重用的代码片段。
组件名称:
1. 该名称会在模板中以html标签方式出现,而html标签不区分大小写
2. 所以必须全部用小写字母,并且为了防止与现有标签名冲突,推荐使用名称中用连接线-
组件数据:
1. 该数据是私有数据,仅限于该组件使用
2. 组件中的数据必须使用函数回调定义,返回数据对象
组件模板:
1. 可以使用自定义的数据
2. 注意组件的模板一定要有一个根元素,例如这里用的是div,即将模板内容必须包含在一个html标签内
3. 组件模板中,可以使用所有Vue指令
(2)组件的用途
组件可将页面抽象成一颗组件树,组件中的每一个节点,都可以用组件来定义和描述,组件式开发使人员分工协作,独立开发与维护更加方便。
(3)组件的分类
组件需要注册后才可以使用,注册有全局注册和局部注册两种方式。
- 全局组件:被所有Vue实例所共享
Vue.component('my-component',{
template : '这里是组件的内容'
})
template的DOM结构必须被一个元素包含,否则无法渲染。
my-component就是注册的组件自定义标签名,推荐使用小写加减号分隔的形式命名。要在父实例中使用这个组件,必须要在实例创建前注册,之后就可以用
的形式来使用组件了。<div id="app" >
<my-component>my-component>
div>
<script>
Vue.component('my-component',{
//选项
} )
var app =new Vue({
el: '#app'
})
script>
- 局部组件:仅允许在定义它的Vue实例挂载点中使用
在Vue实例中,使用components选项可以局部注册组件,注册后的组件只有在该实例作用域下有效。var app = new Vue({
el:"#app",
components:{
'my-component':{
template: '这里是组件的内容'
}
}
})
Vue组件的模板在某些情况下会受到HTML的限制,比如内规定只允许是、、 等这些表格元素,所以在内直接使用组件是无效的。这种情况下,可以使用特殊的属性来挂载组件。
tbody在渲染时,会被替换为组件的内容,常见的限制元素还有、、
。
【注意】
如果使用的是字符串模板,是不受限制的,比如.vue单文件用法。
除了template选项外,组件中还可以像Vue实例那样使用其他的选项,比如:data、computed、methods等。但是在使用data时,和实例稍有区别,data必须是函数,然后数据return出去。(因为JavaScript对象是引用类型,所以如果return出的对象引用了外部一个对象,那这个对象就是共享的,任何一方修改都会同步。)
【模板分离写法】
Vue提供了两种方案来定义HTML模块内容:
- 使用
标签
- 使用
标签
<body>
<script type="text/x-template" id="myCpm">
<div>
<h2>模板分离的写法</h2>
</div>
script>
<template id="myCpm2">
<div>
<h2>模板分离的写法h2>
div>
template>
<script>
// 注册全局组件
Vue.component('cpn', {
template: '#myCpm' })
// 第二种注册局部组件
let vm = new Vue({
el: '#app',
components: {
'cpn2': {
template: '#myCpm2' }
}
})
script>
body>
5.2 父组件向子组件传递数据
如何进行父子组件间的通信呢?Vue官方提到:
- 父向子:通过props向子组件传递数据
- 子向父:通过事件向父组件发送消息
(1)父组件与子组件的定义
- 父组件: Vue实例(子组件的调用者)
- 子组件: Vue实例挂载点可访问的组件
- 局部组件: vue实例中的components属性中声明
- 全局组件: Vue.component()声明
(2)props属性
在组件中使用props选项来声明需要从父组件接收的数据,props的值可以是两种,一种是字符串数组,一种是对象。
- 子组件用来接收父组件数据的容器
- 必须在子组件中定义
- props的值可以是字符串数组,数组中的字符串就是传递时的名称。
- props的值可以是对象,对象可以设置传递时的类型和默认值等。
来自父组件的数据
- props中声明的数据与组件data函数return的数据主要区别就是props的来自父级,而data中的是组件自己的数据,作用域是组件本身,这两种数据都可以在模板template及计算属性computed和方法methods中使用。
- 由于HTML特性不区分大小写,当使用DOM模板时,驼峰命名的props名称要转为短横线分隔命名。如果使用的是字符串模板,仍然可以忽略这些限制。
- 有时候传递的数据不是直接写死的,而是来自父级的动态数据,这时可以使用指令v-bind来动态绑定props的值,当父组件的数据变化时,也会传递给子组件。
【注意】
如果你要直接传递数字、布尔值、数组、对象,而不是用v-bind,传递的仅仅是字符串。
Vue2.x通过props传递数据是单向的,也就是父组件数据变化时会传递给子组件,但是反过来不行。而在Vue里提供了.sync修饰符来支持双向绑定。
<text-document v-bind:title.sync="doc.title">text-document>
在JavaScript中对象和数组是引用类型,指向同一个内存空间,所以props是对象和数组时,在子组件内改变是会影响父组件的。
【数据验证】
当props需要验证时,就需要对象写法。比如某个数据必须是数字类型,如果传入字符串,就会在控制台弹出警告。
Vue.component('my-component',{
props : {
//必须是数字类型
propA : Number,
//必须是字符串或数字类型
propB : [String, Number],
//布尔值,如果没有定义,默认值就是 true
propC: {
type : Boolean ,
default : true
},
//数字,而且是必传
propD: {
type: Number ,
required : true
},
//如果是数组或对象,默认值必须是一个函数来返回
propE: {
type : Array ,
default : function () {
return [] ;
}
},
//自定义一个验证函数
propF: {
validator : function (value) {
return value > 10;
}
}
}
})
验证的type类型可以是:
- String
- Number
- Boolean
- Object
- Array
- Function
type也可以是一个自定义构造器,使用instanceof检测。
(3)子组件与父组件的数据绑定
- 在实例挂载点的组件模板上,使用v-bind指令
- 将父组件指定数据对象绑定到子组件的props属性中
- 单向绑定,即子组件对父组件的数据,只能获取,不能更新
<div id="app">
<global-component :link="nav">global-component>
<local-component :link="nav" :lesson="course">local-component>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
//子组件:全局组件
Vue.component('global-component',{
props:['link'],
template:'',
});
//父组件
let vm = new Vue({
el:'#app',
data:{
nav:['首页','视频','工具'],
course:'Vue.js'
},
//子组件:局部组件
components:{
'local-component':{
data:function(){
return {
site:'MrThinco的微博'};
},
//props是用来接收父组件传递过来的数据的容器,是一个数组
props:['link','lesson'],
template:'{
{site}}
{
{lesson}}',
}
}
});
script>
5.3 子组件向父组件传递数据
(1)子组件传递数据的方式
- 子组件是通过自定义事件向父组件传递数据(自定义事件名:推荐使用 kebab-case,不支持驼峰命名,但脚手架中支持)
- 子组件中定义
methods: {...}
属性中的方法,方法内再通过this.$emit('eventName',data)
方法,将事件与数据发送出来。最后,在父组件中,通过v-on来监听子组件自定义事件
(2)父组件接收数据的方式
- 父组件通过:v-on指令,事件监听
- 在它的事件方法中,获取到子组件的数据
- 最后在实例挂载点模板中输出数据
<div id="app">
<my-component @senddata="getdata">my-component>
<ul>
<li v-for="item in userInfo">{
{item}}li>
ul>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
//父组件:实例
let vm = new Vue({
el:"#app",
//创建数据容器,接收子组件数据
data:{
userInfo:[]
},
methods:{
getdata:function(userInfo){
userInfo.forEach(function(value){
this.userInfo.push(value);
},this)
}
},
//子组件:局部组件
components:{
'my-component':{
//创建要发送给父组件的数据
data:function(){
return {
name:'MrThinco',
email:'[email protected]'
}
},
//创建一个模板,并在模板中定义事件
template:'',
//组件方法:
methods:{
send:function(){
this.$emit('senddata',[this.name,this.email]);
}
}
}
}
});
script>
除了用v-on在组件上监听自定义事件外,也可以监听DOM事件,这时可以用.native修饰符表示监听的是一个原生事件,监听的是该组件的根元素。
(3)子组件索引
Vue提供了子组件索引的方法,用特殊的属性 ref
来为子组件指定一个索引名称。在父组件模板中,子组件标签上使用 ref
指定一个名称,并在父组件内通过 this.$refs
来访问指定名称的子组件。
r e f s 只 在 组 件 渲 染 完 成 后 才 填 充 , 并 且 它 是 非 响 应 式 的 , 它 仅 仅 作 为 一 个 直 接 访 问 子 组 件 的 应 急 方 案 , 应 当 避 免 在 模 板 或 计 算 属 性 中 使 用 refs只在组件渲染完成后才填充,并且它是非响应式的,它仅仅作为一个直接访问子组件的应急方案,应当避免在模板或计算属性中使用 refs只在组件渲染完成后才填充,并且它是非响应式的,它仅仅作为一个直接访问子组件的应急方案,应当避免在模板或计算属性中使用refs。
5.4 同级组件之间如何传递数据
同级组件通信:在Vue2.x中,有一种方案是通过中央事件总线,也就是一个中介来完成。
但是这种方案和直接使用Vuex的状态管理方案还是逊色很多。
(1)空Vue实例
- 空Vue实例,也叫虚拟实例,大多做为中间过度实例使用
- 同级组件之间无法直接进行数据通信,但可通过第三方实现
- 这个第三方,可以通过创建一个空Vue实例代替
(2)实例作用域之间的切换
- 因为涉及到中间Vue实例,所以切换数据作用域很有必要
- 在通信过程中,要随时关注变量: this 的当前指向
(3)实例的mounted属性和$on函数
- mounted: 实例挂载点渲染完成后自动触发
- o n ( 事 件 名 称 , 事 件 回 调 函 数 ) , 用 来 监 听 实 例 上 自 定 义 事 件 , 该 事 件 必 须 由 on(事件名称, 事件回调函数),用来监听实例上自定义事件,该事件必须由 on(事件名称,事件回调函数),用来监听实例上自定义事件,该事件必须由emit触发
<div id="app">
<my-component1>my-component1>
<my-component2>my-component2>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
//创建空的中间实例
let middle = new Vue();
//创建实例
let vm = new Vue({
el:"#app",
components:{
'my-component1':{
data:function(){
return {
data:[0,1,2,3]}
},
template:'',
methods:{
change:function(){
middle.$emit('getverify',this.data)
}
}
},
'my-component2':{
//创建一个数组
data:function(){
return {
verify:['1dsd','fgh5','wj8h','kid9'],//验证码
code:'9527' //默认值
};
},
//组件模板
template:'{
{code}}
',
//挂载完成的时候,监听事件
mounted:function(){
//暂存当前作用域对象
let current = this;
middle.$on('getverify',function(index){
//从0-3之间随机取一个数,作为一个下标
let n = index[Math.floor(Math.random()*index.length)]
//改变默认验证码
current.code = current.verify[n];
});
}
}
}
});
script>
5.5 父子组件的访问方式
有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问根组件。
- 父组件访问子组件:使用 c h i l d r e n 或 children或 children或refs
- 子组件访问父组件:使用$parent
【** c h i l d r e n ∗ ∗ 】 t h i s . children**】 this. children∗∗】this.children是一个数组类型,它包含所有子组件对象。
我们这里通过一个遍历,取出所有子组件的文本内容。
<div id="app">
<parent-cpn>parent-cpn>
div>
<template id="parent">
<div>
<child-cpn1>child-cpn1>
<child-cpn2>child-cpn2>
<button @click="showChildCpn">显示所有子组件信息button>
div>
template>
<template id="child1">
<div>
<span>我是子组件1span>
div>
template>
<template id="child2">
<div>
<span>我是子组件2span>
div>
template>
<script src="https://cdn.jsdelivr.net/npm/[email protected]">script>
<script>
Vue.component('parent-cpn',{
template:'#parent',
components:{
'child-cpn1':{template:'#child1'},
'child-cpn2':{template:'#child2'}
},
methods: {
showChildCpn(){
//获取到子组件
for(let i=0; i
$children的缺陷:
- 通过$children访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值。
- 当子组件过多,我们需要拿到其中一个时,往往不能确定它的索引值,甚至还可能会发生变化。
- 有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用$refs。
【$refs】
$refs的使用:
- $refs和ref指令通常是一起使用的。
- 首先,我们通过ref给某一个子组件绑定一个特定的ID。
- 其次,通过this.$refs.ID就可以访问到该组件了。
<child-cpn1 ref="child1">child-cpn1>
<child-cpn2 ref="child2">child-cpn2>
<button @click="showRefsCpn">通过refs访问子组件button>
showRefsCpn(){
console.log(this.$refs.child1.$el.innerText);
console.log(this.$refs.child2.$el.innerText);
}
【** p a r e n t ∗ ∗ 】 在 子 组 件 中 直 接 访 问 父 组 件 , 可 以 通 过 parent**】 在子组件中直接访问父组件,可以通过 parent∗∗】在子组件中直接访问父组件,可以通过parent。
- 尽管在Vue开发中,我们允许通过$parent来访问父组件,但是在真实开发中尽量不要这样做。
- 子组件应该尽量避免直接访问父组件的数据,因为这样耦合度太高了。
- 如果我们将子组件放在另外一个组件之内,很可能该父组件没有对应的属性,往往会引起问题。
- 另外,更不好的是通过$parent直接修改父组件的状态,那么父组件中的状态将变得飘忽不定,很不利于调试和维护。
【$root】
当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。
5.6 slot插槽
编译作用域:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。
(1)插槽是什么
- 插槽使用
标签在组件的模板内定义
中的内容表示,如果没有在该组件中插入任何其他内容,就默认显示该内容。有时为一个插槽设置具体的后备 (也就是默认的) 内容是很有用的,它只会在没有提供内容的时候被渲染。
- 插槽是组件模板中预留的扩展接口、占位符,最终会被组件中的指定内容替换
- 插槽可以使代码复用,插槽可以将组件内的内容进行分组有效管理
- 如果组件模板中没有包含一个
元素,则使用该组件时,组件起始标签和结束标签之间的任何内容都会被抛弃。
【注意】
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
(2)匿名插槽
- 不需要名称的插槽
- 通常只应用在单插槽的场景中
(3)具名插槽
- 用来区分模板中的多个插槽,建议总是给插槽起一个有意义的名称
- 在向具名插槽提供内容的时候,我们可以在一个
元素上使用 v-slot
指令,并以 v-slot
的参数形式提供其名称
- 一个不带 name 的
出口会带有隐含的名字“default”
<div id="app">
<my-component1>
<p>MrThincop>
my-component1>
<my-component2>
<template v-slot:myname >
<p>MrThincop>
template>
<template v-slot:sex >
<p>Manp>
template>
my-component2>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
//全局组件:匿名插槽/单插槽
Vue.component('my-component1',{
template:' ',
});
//全局组件:具名插槽
Vue.component('my-component2',{
template:' '
});
let vm = new Vue({
el:'#app',
});
script>
(4)作用域插槽
作用域插槽是slot一个比较难理解的点,而且官方文档说的又有点不清晰。
这里,我们用一句话对其做一个总结,然后我们在后续的案例中来体会:
父组件替换插槽的标签,但是内容由子组件来提供。
设想一个带有如下模板的
组件:
<span>
<slot>{
{ user.lastName }}slot>
span>
我们可能想换掉备用内容,用名而非姓来显示。
<current-user>
{
{ user.firstName }}
current-user>
为了让 user 在父级的插槽内容中可用,我们可以将 user 作为
元素的一个 attribute 绑定上去:
<span>
<slot :user="user">
{
{ user.lastName }}
slot>
span>
绑定在
元素上的 attribute 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot
来定义我们提供的插槽 prop 的名字:
<current-user>
<template v-slot:default="slotProp">
{
{ slotProp.user.firstName }}
template>
current-user>
我们选择将包含所有插槽 prop 的对象命名为 slotProp,但你也可以使用任意你喜欢的名字。
跟 v-on
和 v-bind
一样,v-slot
也有缩写,即把参数之前的所有内容 (v-slot:)
替换为字符 #
。例如 v-slot:header
可以被重写为 #header
。
5.7 开发小案例-组件实现用户点赞功能
- 组件本质就是一个html自定义标签
- 标签有属性,所以组件也可以有一些自定义的属性
- 这些属性的值,可以是普通数据,也可以是事件
- 组件与它的拥有者(Vue实例)之间的通信通过属性完成
<div id="app">
<like-component>like-component>
div>
<template id="like-tpl">
<button @click="setLike" :style="isLiked?{
backgroundColor:'yellow'}:''">{
{text}} {
{isLiked ? '+' : ''}}{
{likeCount}}button>
template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
let vm = new Vue({
el:'#app',
components:{
'like-component':{
data:function(){
return {
text:'点赞',
likeCount:200,
//设置当前的点赞状态,false:未点赞
isLiked:false
}
},
template:'#like-tpl',
methods:{
setLike:function(){
//判断用户是否已经点过赞
if(this.isLiked){
this.likeCount--;
this.text = '点赞';
this.isLiked = false;
}else{
this.likeCount++;
this.text = '已点赞';
this.isLiked = true;
}
}
}
}
}
});
script>
5.8 开发小案例-商品信息列表与计算
<div id="app">
<products :my-products="products" >products>
div>
<template id="products-tpl">
<table :style="tableStyle">
<caption :style="title">商品信息表caption>
<thead>
<tr :style="bgColor">
<th :style="tdStyle">编号th>
<th :style="tdStyle">品名th>
<th :style="tdStyle">单价th>
<th :style="tdStyle">数量th>
tr>
thead>
<tbody>
<tr v-for="(product,index) in myProducts">
<td :style="tdStyle">{
{index}}td>
<td :style="tdStyle">{
{product.productName}}td>
<td :style="tdStyle">{
{product.unitPrice}}td>
<td :style="tdStyle"><input type="number" v-model.number="product.quantity">td>
tr>
tbody>
<tfoot>
<td colspan="3" :style="tdStyle">总计:td>
<td :style="tdStyle">{
{total}}td>
tfoot>
table>
template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
let vm = new Vue({
el:'#app',
//实例数据(父组件)
data:{
products:[
{
productName:'小米笔记本',
unitPrice:5500,
quantity:0
},
{
productName:'华为笔记本',
unitPrice:6600,
quantity:0
},
{
productName:'苹果笔记本',
unitPrice:8800,
quantity:0
}
]
},
//局部组件,它从实例(父组件)中接收数据
components:{
products:{
//注意:html属性名不区分大小写,myProducts会转换为my-products
props:['myProducts'],
//自定义的样式
data:function(){
return {
tableStyle:{
borderCollapse:'collapse',
border:'1px solid #555',
width:'90%',
textAlign:'center'
},
tdStyle:{
border:'1px solid #555',
padding:'8px'
},
bgColor:{
backgroundColor:'lightblue'
},
title:{
fontSize:'20px',
marginBottom:'10px'
}
}
},
//ES6:用反引号来包含大量的html代码
//如果模板内容过多,用模板标签 template 进行简化
template:"#products-tpl",
//计算属性
computed:{
//合计价格
total:function(){
let sum = 0;
this.myProducts.forEach(function(product){
sum += product.unitPrice * product.quantity;
},this);
//返回结果
return sum;
}
}
}
}
});
script>
5.9 开发小案例-用插槽快速的实现网页的布局
<style>
.header,.footer{
min-height:60px;
background-color: lightblue;
}
.main{
margin: 5px auto;
min-height: 600px;
overflow: hidden;
}
.main .side{
width: 30%;
min-height: inherit;
background-color: antiquewhite;
float: left;
}
.main .content{
width: 70%;
min-height: inherit;
background-color: lightgreen;
float: left;
}
style>
<div id="app">
<layout>
<div class="header" slot="header">{
{header}}div>
<div class="main" slot="main">
<div class="side">{
{main[0]}}div>
<div class="content">{
{main[1]}}div>
div>
<div class="footer" slot="footer">{
{footer}}div>
layout>
div>
<template id="layout-tpl">
<div class="container">
<slot name="header">slot>
<slot name="main">slot>
<slot name="footer">slot>
div>
template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
//全局组件:布局组件
Vue.component('layout',{
template:'#layout-tpl'
});
let vm = new Vue({
el:'#app',
data:{
header:'头部',
main:['侧边栏','内容区'],
footer:'底部'
}
})
script>
六、import
vue中常用的几种import(模块、文件)引入方式,export,export default,全部/部分文件的导出/导入。
6.1 import(模块、文件)引入方式
【1】引入第三方插件
import echarts from 'echarts'
【2】导入css文件
import 'iview/dist/styles/iview.css';
// 如果是在.vue文件中那么在外面套个style
【3】导入组件
import name1 from './name1'
import name2 from './name2'
components:{
name1,
name2,
}
【注意】import '@…'的语句:@ 等价于 /src 这个目录,避免写麻烦又易错的相对路径。
【4】引入工具类
// 导出:方式一
export function axiosfetch1(options) {
}
export function axiosfetch2(options) {
}
// 导出:方式二
const axiosfetch1 = options => {
}
const axiosfetch2 = options => {
}
export {
axiosfetch1,
axiosfetch2
}
/*第一种是引入单个方法*/
// 导入
import {
axiosfetch} from './util';
// 在vue中,直接用axiosfetch()
/*第二种导入成组的方法*/
import * as tools from './util';
// 在vue中,直接用this.$tools.methodName调用就可以了
Vue.prototype.$tools = tools
【5】export 和 export default 区别
// export 需要加花括号,可以一次导入多个或一个
import {
axiosfetch} from './util';
import {
axiosfetch,post} from './util';
import * from './util';
// export default 不需要加花括号,只能导入一个
import axiosfetch from './util';
6.2 export,import和export default的关系
export 与import是es6中新增模块功能最主要的两个命令。
- export与export default均可用于导出常量、函数、文件、模块等
- 在一个文件或模块中,export、import可以有多个,export default仅有一个
- 通过export方式导出,在导入时要加{ },export default则不需要{ }
【注意】import引入文件路径:
- import引入一个依赖包,不需要相对路径。如:import app from ‘app’
- import 引入一个自己写的js文件,是需要相对路径的。如:import app from ‘./app.js’
import引入文件变量名
【1】 使用export抛出的变量需要用{}进行import
// a.js导出方式
export const str = "blablabla~";
export function log(sth) {
return sth;
}
// b.js导入方式
import { str, log as _log } from 'a'; //也可以分开写两次,导入的时候带花括号。还可以用as重命名
【2】使用export default抛出的变量,只需要自己起一个名字就行
// a.js
let obj = { name: ‘example’ };
export default obj;
// b.js
import newNname from ‘./a.js’; //newNname 是自己随便取的名字,这里可以随便命名
console.log(newNname.name);
其中export和export default最大的区别就是export不限变量数可以导出多个,而export default只导出一次。而且 export出的变量想要使用必须使用{}来盛放,而export default 不需要 只要import任意一个名字来接收对象即可。
6.3 部分导入和部分导出,全部导入和全部导出
【1】部分导出和部分导入
部分导出和部分导入的优势,当资源比较大时建使用部分导出,这样一来使用者可以使用部分导入来减少资源体积,比如element-ui官方的就推荐使用部分导入来减少项目体积,因为element-ui是一个十分庞大的框架,如果我们只用到其中的一部分组件, 那么只将用到的组件导入就可以了。
//部分导出
//A.js
export function helloWorld(){
conselo.log("Hello World");
}
export function test(){
conselo.log("this's test function");
}
//部分导入
//B.js
import {helloWorld} from "./A.js" //只导入A.js中的helloWorld方法
helloWorld(); //执行utils.js中的helloWorld方法
如果我们需要A.js中的全部资源,则可以全部导入,如下:
import * as _A from "./A.js" //导入全部的资源,_A为别名,在调用时使用
_A.helloWorld(); //执行A.js中的helloWorld方法
_A.test(); //执行A.js中的test方法
【2】全部导出和全部导入
如果使用全部导出,那么使用者在导入时则必须全部导入,推荐在写方法库时使用部分导出,从而将全部导入或者部分导入的权力留给使用者。
需要注意的是:一个js文件中可以有多个export,但只能有一个export default
//全部导出 A.js
const helloWorld = function(){
conselo.log("Hello World");
}
const test = function(){
conselo.log("this's test function");
}
export default{
helloWorld,
test
}
//全部导入 B.js
import A from "./A.js"
A.helloWorld();
A.test();
你可能感兴趣的:(03,Vue)