Vue学习笔记整理

一、Vue2

Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的 渐进式框架。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。Vue.js是一个MVVM模式的框架。

1、vue2需掌握的几方面

  • 网络通信 : axios(不属于Vue框架,单独的一套前端通信框架,负责与服务器交互。)
  • 页面跳转 : vue-router
  • 状态管理:vuex
  • Vue-UI : ICE , Element UI ( npm 安装
    推荐使用 npm 的方式安装,它能更好地和 webpack 打包工具配合使用。
    npm i element-ui -S)
  • css:SASS(基于Ruby)、LESS(基于NodeJS)
  • WebPack:模块打包器,主要作用就是打包、压缩、合并及按序加载
  • NPM:项目综合管理工具,类似于Maven
  • YARN:NPM的替代方案,类似于Maven和Gradle的关系

2、Vue2入门语法

初始vue模板:

<div id="app" v-once> <!--v-once标签添加后,其标签下内容不发生改变 -->
  {{ message }} --双大括号文本插值
</div>

new一个Vue对象,绑定div ‘#app’ 到 el 属性,data属性中给定默认值message,修改message的值,页面上的值也会发生改变。如果加入v-once,其值不会改变。

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
})

app.message='change!!';
2-1 条件 v-if

v-if: vue的条件判断,当seen为ture,p标签显示。

<div id="app-3">
  <p v-if="seen">现在你看到我了</p>
</div>
var app3 = new Vue({
  el: '#app-3',
  data: {
    seen: true
  }
})
app3.seen = false;
  • v-else
  • v-else-if
<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

用 key 管理可复用的元素
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>
2-2 循环 v-for

v-for: vue的循环标签,todos传参为数组对象,todo为遍历出的对象,可以通过 todo.text 取出对象的属性值。

<div id="app-4">
  <ol>
    <li v-for="todo in todos">
      {{ todo.text }}
    </li>
  </ol>
</div>
var app4 = new Vue({
  el: '#app-4',
  data: {
    todos: [
      { text: '学习 JavaScript' },
      { text: '学习 Vue' },
      { text: '整个牛项目' }
    ]
  }
})

在 v-for 块中,我们可以访问所有父作用域的 property。v-for 还支持一个可选的第二个参数,即当前项的索引。

<ul id="example-2">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>
var example2 = new Vue({
  el: '#example-2',
  data: {
    parentMessage: 'Parent',
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})

结果:

  • Parent - 0 - Foo
  • Parent - 1 - Bar

也可以用 of 替代 in 作为分隔符,因为它更接近 JavaScript 迭代器的语法:

<div v-for="item of items"></div>
2-3 事件监听 v-on

v-on: vue的事件监听器,监听事件方法,点击按钮时,触发reverseMessage方法,反转按钮名称。

缩写:v-on: 等于 @

<div id="app-5">
  <p>{{ message }}</p>
  <button v-on:click="reverseMessage">反转消息</button>
  <button @click="reverseMessage">反转消息</button>
</div>
var app5 = new Vue({
  el: '#app-5',
  data: {
    message: 'Hello Vue.js!'
  },
  methods: {
    reverseMessage: function () {
      this.message = this.message.split('').reverse().join('')
    }
  }
})
2-4 双向绑定 v-model

v-model: vue提供的双向绑定指令,实现表单输入和应用状态之间的双向绑定。

<div id="app-6">
  <p>{{ message }}</p>
  <input v-model="message">
</div>
var app6 = new Vue({
  el: '#app-6',
  data: {
    message: 'Hello Vue!'
  }
})
app6.message='change!!';
2-4 组件化应用构建

组件本质上是一个拥有预定义选项的一个 Vue 实例。在 Vue 中注册组件很简单:

// 定义名为 todo-item 的新组件
Vue.component('todo-item', {
  template: '<li>这是个待办项</li>'
})

var app = new Vue(...)

现在你可以用它构建另一个组件模板:

<ol>
  <!-- 创建一个 todo-item 组件的实例 -->
  <todo-item></todo-item>
</ol>

但是这样会为每个待办项渲染同样的文本,这看起来并不炫酷。我们应该能从父作用域将数据传到子组件才对。让我们来修改一下组件的定义,使之能够接受一个 prop:

Vue.component('todo-item', {
  // todo-item 组件现在接受一个
  // "prop",类似于一个自定义 attribute。
  // 这个 prop 名为 todo。
  props: ['todo'],
  template: '<li>{{ todo.text }}</li>'
})

现在,我们可以使用 v-bind 指令将待办项传到循环输出的每个组件中:

<div id="app-7">
  <ol>
    <!--
      现在我们为每个 todo-item 提供 todo 对象
      todo 对象是变量,即其内容可以是动态的。
      我们也需要为每个组件提供一个“key”,稍后再
      作详细解释。
    -->
    <todo-item
      v-for="item in groceryList"
      v-bind:todo="item"
      :key="item.id"
    ></todo-item>
  </ol>
</div>
Vue.component('todo-item', {
  props: ['todo'],
  template: '<li>{{ todo.text }}</li>'
})

var app7 = new Vue({
  el: '#app-7',
  data: {
    groceryList: [
      { id: 0, text: '蔬菜' },
      { id: 1, text: '奶酪' },
      { id: 2, text: '随便其它什么人吃的东西' }
    ]
  }
})
2-5 原始 HTML

v-html:双大括号会将数据解释为普通文本,而非 HTML 代码,而v-html会将数据解释为html代码。

<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
2-6 Attribute

Mustache 语法不能作用在 HTML attribute 上,遇到这种情况应该使用 v-bind 指令:

<div v-bind:id="dynamicId"></div>

对于布尔 attribute (它们只要存在就意味着值为 true),v-bind 工作起来略有不同,在这个例子中:

<button v-bind:disabled="isButtonDisabled">Button</button>

如果 isButtonDisabled 的值是 null、undefined 或 false,则 disabled attribute 甚至不会被包含在渲染出来的 元素中。

缩写:v-bind: 等于 :

从 2.6.0 开始,可以用方括号括起来的 JavaScript 表达式作为一个指令的参数:

<!--
注意,参数表达式的写法存在一些约束,如之后的“对动态参数表达式的约束”章节所述。
-->
<a v-bind:[attributeName]="url"> ... </a>

这里的 attributeName 会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。例如,如果你的 Vue 实例有一个 data property attributeName,其值为 “href”,那么这个绑定将等价于 v-bind:href。
同样地,你可以使用动态参数为一个动态的事件名绑定处理函数:

<a v-on:[eventName]="doSomething"> ... </a>
2-6-1 对象语法

我们可以传给 v-bind:class 一个对象,以动态地切换 class:

<div v-bind:class="{ active: isActive }"></div>

上面的语法表示 active 这个 class 存在与否将取决于数据 property isActive 的 truthiness。

你可以在对象中传入更多字段来动态切换多个 class。此外,v-bind:class 指令也可以与普通的 class attribute 共存。

<div
  class="static"
  v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
data: {
  isActive: true,
  hasError: false
}

当 isActive 或者 hasError 变化时,class 列表将相应地更新。例如,如果 hasError 的值为 true,class 列表将变为 “static active text-danger”。
绑定的数据对象不必内联定义在模板里:

<div v-bind:class="classObject"></div>
data: {
  classObject: {
    active: true,
    'text-danger': false
  }
}

渲染的结果和上面一样。我们也可以在这里绑定一个返回对象的计算属性。这是一个常用且强大的模式:

<div v-bind:class="classObject"></div>
data: {
  isActive: true,
  error: null
},
computed: {
  classObject: function () {
    return {
      active: this.isActive && !this.error,
      'text-danger': this.error && this.error.type === 'fatal'
    }
  }
}
2-6-2 数组语法

我们可以把一个数组传给 v-bind:class,以应用一个 class 列表:

<div v-bind:class="[activeClass, errorClass]"></div>
data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}

如果你也想根据条件切换列表中的 class,可以用三元表达式:

<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>

这样写将始终添加 errorClass,但是只有在 isActive 是 truthy 1 时才添加 activeClass。

不过,当有多个条件 class 时这样写有些繁琐。所以在数组语法中也可以使用对象语法:

<div v-bind:class="[{ active: isActive }, errorClass]"></div>
2-7 使用 JavaScript 表达式

对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持

{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}

<div v-bind:id="'list-' + id"></div>

这些表达式会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效。

<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}

<!-- 流控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}

模板表达式都被放在沙盒中,只能访问全局变量的一个白名单,如 Math 和 Date 。你不应该在模板表达式中试图访问用户定义的全局变量。

2-8 修饰符

修饰符 (modifier) 是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault():

<form v-on:submit.prevent="onSubmit">...</form>

在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
  • .passive
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>

<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>

<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成  -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
不要把 .passive 和 .prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive 会告诉浏览器你不想阻止事件的默认行为。

为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:

.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
你还可以通过全局 config.keyCodes 对象自定义按键修饰符别名

// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
2-9 控制元素显示隐藏 v-show

用于根据条件展示元素的选项 v-show 指令:

h1 v-show="ok">Hello!</h1>

不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS property display。

注意,v-show 不支持 < template > 元素,也不支持 v-else。

3、Vue对象详解

3-1 数据与方法

当一个 Vue 实例被创建时,它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。

// 我们的数据对象
var data = { a: 1 }

// 该对象被加入到一个 Vue 实例中
var vm = new Vue({
  data: data
})

// 获得这个实例上的 property
// 返回源数据中对应的字段
vm.a == data.a // => true

// 设置 property 也会影响到原始数据
vm.a = 2
data.a // => 2

// ……反之亦然
data.a = 3
vm.a // => 3

当这些数据改变时,视图会进行重渲染。值得注意的是只有当实例被创建时就已经存在于 data 中的 property 才是响应式的。也就是说如果你添加一个新的 property,比如: vm.b = ‘hi’ ;那么对 b 的改动将不会触发任何视图的更新。如果你知道你会在晚些时候需要一个 property,但是一开始它为空或不存在,那么你仅需要设置一些初始值。比如:

data: {
  newTodoText: '',
  visitCount: 0,
  hideCompletedTodos: false,
  todos: [],
  error: null
}

这里唯一的例外是使用 Object.freeze(),这会阻止修改现有的 property,也意味着响应系统无法再追踪变化。

var obj = {
  foo: 'bar'
}

Object.freeze(obj) //之后修改obj,系统无法追踪其变化

new Vue({
  el: '#app',
  data: obj
})
<div id="app">
  <p>{{ foo }}</p>
  <!-- 这里的 `foo` 不会更新! -->
  <button v-on:click="foo = 'baz'">Change it</button>
</div>

Vue 实例还暴露了一些有用的实例 property 与方法。它们都有前缀 $,以便与用户定义的 property 区分开来。例如:

var data = { a: 1 }
var vm = new Vue({
  el: '#example',
  data: data
})

vm.$data === data // => true
vm.$el === document.getElementById('example') // => true

// $watch 是一个实例方法
vm.$watch('a', function (newValue, oldValue) {
  // 这个回调将在 `vm.a` 改变后调用
})
3-2 实例生命周期钩子

每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。

  • created
  • mounted
  • updated
  • destroyed
//例如:
new Vue({
  data: {
    a: 1
  },
  created: function () {
    // `this` 指向 vm 实例
    console.log('a is: ' + this.a)
  }
})
// => "a is: 1"

tip生命周期钩子的 this 上下文指向调用它的 Vue 实例,不要在选项 property 或回调上使用箭头函数,因为箭头函数并没有 this,this 会作为变量一直向上级词法作用域查找,直至找到为止,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。

vue生命周期图
bind:只调用一次,第一次绑定到父元素时,父节点不存在,常用于对dom元素进行初始化(特指样式)或者事件的绑定
inserted:插入父节点调用,父节点存在,可以获取设置dom的值,常用于编写初始化业务逻辑(特指js行为)
update:被绑定元素更新的时候调用,常用于编写主逻辑
unbind:解绑调用,常用于解绑事件removeEventListeren和删除元素delete el.xxx
bind在组件的created之后执行,而inserted在组件的mounted之后执行,所以bind时的el.parentElement为null,而inserted存在
innerHTML也可以再bind中进行初始化获取修改
如果需要传值多个可以传一个对象
update后将会触发当前组件的下所有使用该指令的componentUpdated和update钩子,
update指令在但是可能发生在其子 VNode 更新之前,componentUpdated指令所在组件的 VNode 及其子 VNode 全部更新后调用,举个例子,当我们更改指令绑定元素的innerHTML时,在update获取的是修改之前的,在componentUpdated获取的是修改之后的

3-3 计算属性缓存 computed
<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})

结果:

Original message: “Hello”

Computed reversed message: “olleH”

这里我们声明了一个计算属性 reversedMessage。我们提供的函数将用作 property vm.reversedMessage 的 getter 函数:

console.log(vm.reversedMessage) // => 'olleH'
vm.message = 'Goodbye'
console.log(vm.reversedMessage) // => 'eybdooG'

你可以打开浏览器的控制台,自行修改例子中的 vm。vm.reversedMessage 的值始终取决于 vm.message 的值。

你可以像绑定普通 property 一样在模板中绑定计算属性。Vue 知道 vm.reversedMessage 依赖于 vm.message,因此当 vm.message 发生改变时,所有依赖 vm.reversedMessage 的绑定也会更新。而且最妙的是我们已经以声明的方式创建了这种依赖关系:计算属性的 getter 函数是没有副作用 (side effect) 的,这使它更易于测试和理解。

<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在组件中
methods: {
  reversedMessage: function () {
    return this.message.split('').reverse().join('')
  }
}

我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
这也同样意味着下面的计算属性将不再更新,因为 Date.now() 不是响应式依赖:

computed: {
  now: function () {
    return Date.now()
  }
}

相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。
如果你不希望有缓存,请用方法来替代。

Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。细想一下这个例子:

div id="demo">{{ fullName }}</div>
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
  watch: {
    firstName: function (val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})

上面代码是命令式且重复的。将它与计算属性的版本进行比较:

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})

计算属性默认只有 getter,不过在需要时你也可以提供一个 setter:

// ...
computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
// ...

现在再运行 vm.fullName = ‘John Doe’ 时,setter 会被调用,vm.firstName 和 vm.lastName 也会相应地被更新。

3-4 侦听器 watch

虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

<div id="watch-example">
  <p>
    Ask a yes/no question:
    <input v-model="question">
  </p>
  <p>{{ answer }}</p>
</div>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
  el: '#watch-example',
  data: {
    question: '',
    answer: 'I cannot give you an answer until you ask a question!'
  },
  watch: {
    // 如果 `question` 发生改变,这个函数就会运行
    question: function (newQuestion, oldQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.debouncedGetAnswer()
    }
  },
  created: function () {
    // `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
    // 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
    // AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
    // `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
    // 请参考:https://lodash.com/docs#debounce
    this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
  },
  methods: {
    getAnswer: function () {
      if (this.question.indexOf('?') === -1) {
        this.answer = 'Questions usually contain a question mark. ;-)'
        return
      }
      this.answer = 'Thinking...'
      var vm = this
      axios.get('https://yesno.wtf/api')
        .then(function (response) {
          vm.answer = _.capitalize(response.data.answer)
        })
        .catch(function (error) {
          vm.answer = 'Error! Could not reach the API. ' + error
        })
    }
  }
})
</script>

在这个示例中,使用 watch 选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

除了 watch 选项之外,您还可以使用命令式的 vm.$watch API。

3-5 插槽

在 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除且仍在文档中的 attribute。新语法的由来可查阅这份 RFC。
Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 < slot> 元素作为承载分发内容的出口。
它允许你像这样合成组件:

<navigation-link url="/profile">
  Your Profile
</navigation-link>

然后你在 < navigation-link > 的模板中可能会写为:

<a
  v-bind:href="url"
  class="nav-link"
>
  <slot></slot>
</a>

当组件渲染的时候,< slot></ slot> 将会被替换为“Your Profile”。插槽内可以包含任何模板代码,包括 HTML:

<navigation-link url="/profile">
  <!-- 添加一个 Font Awesome 图标 -->
  <span class="fa fa-user"></span>
  Your Profile
</navigation-link>

甚至其它的组件:

<navigation-link url="/profile">
  <!-- 添加一个图标的组件 -->
  <font-awesome-icon name="user"></font-awesome-icon>
  Your Profile
</navigation-link>

如果 < navigation-link > 的 template 中没有包含一个 < slot > 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。
当你想在一个插槽中使用数据时,例如:

<navigation-link url="/profile">
  Logged in as {{ user.name }}
</navigation-link>

插槽跟模板的其它地方一样可以访问相同的实例 property (也就是相同的“作用域”),而不能访问 < navigation-link> 的作用域。例如 url 是访问不到的:

<navigation-link url="/profile">
  Clicking here will send you to: {{ url }}
  <!--
  这里的 `url` 会是 undefined,因为其 (指该插槽的) 内容是
  _传递给_ <navigation-link> 的而不是
  在 <navigation-link> 组件*内部*定义的。
  -->
</navigation-link>

作为一条规则,请记住:

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

4、vue路由 vue-router

如果你只需要非常简单的路由而不想引入一个功能完整的路由库,可以像这样动态渲染一个页面级的组件:

const NotFound = { template: '<p>Page not found</p>' }
const Home = { template: '<p>home page</p>' }
const About = { template: '<p>about page</p>' }

const routes = {
  '/': Home,
  '/about': About
}

new Vue({
  el: '#app',
  data: {
    currentRoute: window.location.pathname
  },
  computed: {
    ViewComponent () {
      return routes[this.currentRoute] || NotFound
    }
  },
  render (h) { return h(this.ViewComponent) }
})

结合 HTML5 History API,你可以建立一个麻雀虽小但是五脏俱全的客户端路由器。可以直接看实例应用。

5、webpack基本使用

5-1 创建项目目录并初始化

创建项目,并打开项目所在目录的终端,输入命令:

npm init -y
5-2 创建首页及js文件

在项目目录中创建index.html页面
在项目目录中创建js文件夹,并在文件夹中创建index.js文件
安装jQuery
打开项目目录终端,输入命令:

 npm install jQuery -S

导入jQuery
打开index.js文件,编写代码导入jQuery并实现功能:

import $ from "jquery";
$(function(){
    $("li:odd").css("background","cyan");
    $("li:odd").css("background","pink");
})

运行发现:
报错 因为import $ from “jquery”;这句代码属于ES6的新语法代码,在浏览器中可能会存在兼容性问题。

安装配置webpack
1、输入如下代码

npm install webpack webpack-cli -D

2、在项目根目录中,创建一个 webpack.config.js 的配置文件
在 webpack.config.js 文件中编写代码进行webpack配置,如下:

module.exports = {
    mode:"development"//可以设置为development(开发模式),production(发布模式)
}

3、修改项目中的package.json文件添加运行脚本dev,如下:

"scripts":{
    "dev":"webpack"
}

在这里插入图片描述

4、运行 npm run dev 命令进行项目打包,并在页面中引入项目打包生成的js文件(即为在 dist 路径下生成的 main.js)

配置打包的入口与出口
默认打包方式
将src/index.js 作为默认的打包入口js文件
将dist/main.js 作为默认的打包输出js文件

配置打包方式

--dirname 表示当前文件的绝对路径

    const path = require("path");
    module.exports = {
        mode:"development",
        //设置入口文件路径
        entry: path.join(__dirname,"./src/xx.js"),
        //设置出口文件
        output:{
            //设置路径
            path:path.join(__dirname,"./dist"),
            //设置文件名
            filename:"res.js"
        }
    }

配置自动打包功能
原因: 在修改代码后需要 重新运行 npm run dev
1、安装自动打包的包

 npm install webpack-dev-server -D

2、修改package.json中的dev指令如下:

    "scripts":{
      "dev":"webpack-dev-server"
    }

3、将引入的js文件路径更改为:
<script src="/bundle.js"></script>
在这里插入图片描述

4、运行npm run dev,进行打包
5、打开网址查看效果:http://localhost:8080
在这里插入图片描述

注意:
1、webpack-dev-server会启动个实时打包的http服务器
2、webpack-dev- server打包生成的输出文件,默认放到了项目根目录中,而且是虚拟的、看不见的

配置html-webpack-plugin
此为预览插件

使用 npm install html-webpack-plugin -D 安装预览功能包

1、安装默认预览功能的包:html-webpack-plugin

npm install html-webpack-plugin -D
2、修改webpack.config.js文件,如下:

     //导入包
  const HtmlWebpackPlugin = require("html-webpack-plugin");
      //创建对象
     const htmlPlugin = new HtmlWebpackPlugin({
                //设置生成预览页面的模板文件
                template:"./src/index.html",
                //设置生成的预览页面名称
                filename:"index.html"
            })

3、继续修改webpack.config.js文件,添加plugins信息:

            module.exports = {
                ......
                plugins:[ htmlPlugin ]
            }

配置自动打开浏览器页面
在这里插入图片描述

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --open --host 127.0.0.1 --port 8888",
    "build": "webpack -p"
  },

Webpack 加载器
loader 调用过程图示
在这里插入图片描述

css 打包器
1、 安装 style-loader 安装包处理样式文件
npm install style-loader css-loader -D

2、 在webpack.config.js 的module 的rules 数组中配置
在这里插入图片描述

 plugins: [htmlPlguin, new VueLoaderPlugin()],
  module: {
    rules: [
      { test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader'] },
      { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
      { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
      { test: /\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/, use: 'url-loader?limit=16941' },
      { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ },
      { test: /\.vue$/, use: 'vue-loader' }
    ]
  }

3、 在 index.js 导入相应配置
import './css/1.css'
注意:
1、 use 数组中指定的 loader 顺序是固定的
2、 多个loader 的调用顺序是从后往前调

less 打包器
1、运行如下命令
npm i less-loader less -D
2、 在webpack.config.js 的module 的rules 数组中配置
{ test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
3、 在 index.js 导入相应配置

配置 postCSS 自动添加 css 的兼容前缀
目的: 解决各个浏览器的兼容问题

1、运行 npm i postcss-loader autoprefixer -D命令
2、在项目根目录中创建 postcss 的配置文件 postcss.config.js 并初始化如下配置
在这里插入图片描述

const autoprefixer = require('autoprefixer')
module.exports = {
  plugins: [autoprefixer]
}

3、在webpack.config.js 修改css 的loader 的规则如下:
在这里插入图片描述

{ test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader'] },
打包样式表中的图片和字体文件
1、运行 npm install url-loader file-loader -D
2、更改webpack.config.js的module中的rules数组

module.exports = {
    ......
    plugins:[ htmlPlugin ],
    module : {
        rules:[
            {
                //test设置需要匹配的文件类型,支持正则
                test:/\.css$/,
                //use表示该文件类型需要调用的loader
                use:['style-loader','css-loader']
            },
            {
                test:/\.less$/,
                use:['style-loader','css-loader','less-loader']
            },
            {
                test:/\.scss$/,
                use:['style-loader','css-loader','sass-loader']
            },{
                test:/\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/,
                //limit用来设置字节数,只有小于limit值的图片,才会转换
                //为base64图片
                use:"url-loader?limit=16940"
            }
        ]
    }
}

注意:

1、其中 ? 之后的是 loader 的参数项
2、limit 用来指定图片的大小,单位是字节(byte),只有limit
大小的图片,才能被转换为 base64 图片

打包处理JS中高级语法
我们需要安装babel系列的包
1、安装babel转换器

npm install babel-loader @babel/core @babel/runtime -D
2、安装babel语法插件包
npm install @babel/preset-env @babel/plugin-transform-runtime @babel/plugin-proposal-class-properties -D
3、在项目根目录创建并配置babel.config.js文件
在这里插入图片描述

    module.exports = {
        presets:["@babel/preset-env"],
        plugins:[ "@babel/plugin-transform-runtime", "@babel/plugin-proposal-class-properties" ]
    }

4、配置规则:更改webpack.config.js的module中的rules数组

module.exports = {
    ......
    plugins:[ htmlPlugin ],
    module : {
        rules:[
            {
                //test设置需要匹配的文件类型,支持正则
                test:/\.css$/,
                //use表示该文件类型需要调用的loader
                use:['style-loader','css-loader',exclude : /node_modules/]
            },

Vue 单文件组件
传统组件存在的问题 :
1、全局定义的组件不能重名
2、字符串模板缺乏语法高亮,在HTML多行时需要
3、不支持css(当html和js组件化时,css没有参与其中
4、没有构建步骤限制,只能使用H5和ES5,不能使用预处理器(babel)

单文件的组成结构
template 组件的模板区域
script 业务逻辑区域
style 样式区域

代码:

<template>
    //组件代码区域
 <div>
  <h1>这是App.vue  根组件</h1>
 </div>
</template>
<script>
    //js代码区域
    export 
</script>
<style scoped>
    样式代码区域
</style>

导入单文件组件
import App Vue from ' ./components/App.vue'
webpack配置vue 组件加载器
1、安装vue组件的加载器
npm install vue-loader vue-template-compiler -D
2、配置规则:更改webpack.config.js的module中的rules数组

    const VueLoaderPlugin = require("vue-loader/lib/plugin");
    const vuePlugin = new VueLoaderPlugin();
    module.exports = {
        ......
        plugins:[ htmlPlugin, vuePlugin  ],
        module : {
            rules:[
                ...//其他规则
                { 
                    test:/\.vue$/,
                    loader:"vue-loader",
                }
            ]
        }
    }

在这里插入图片描述

在webpack项目中使用 vue
在这里插入图片描述

将vue单文件组件能够使用,我们必须要安装vue,并使用vue来引用vue单文件组件。
1、安装Vue npm install vue -S
2、在index.js中引入vue:import Vue from “vue”
3、创建Vue实例对象并指定el,最后使用render函数渲染单文件组件

注意:

建议使用 render 函数 ,而不是template 等模块等,因为导入的是Vue 的简化版,有可能不支持

    const vm = new Vue({
        el:"#first",
        render:h=>h(app)
    })

webpack打包发布项目
在项目上线之前,我们需要将整个项目打包并发布。
1、 配置package.json

    "scripts":{
        "dev":"webpack-dev-server",
        "build":"webpack -p"
    }

在这里插入图片描述

2、在项目打包之前,可以将dist目录删除,生成全新的dist目录
3、在终端运行 npm run build ,进行打包


  1. truthy 不是 true,详见 MDN 的解释。 ↩︎

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值