撸一遍vue的基础特性

Vue.js无疑是最近最火的一套前端框架,被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。其轻量级,渐进式的优点对开发者的吸引力毋庸置疑。本人玩过两年的Angular,对Vue也充满了好奇,于是也想认识一下Vue。

Vue.js安装

主流的安装方式当然是使用vue-cli工具,这跟angular挺像的。但是作为刚入门的开发者,官方比较推荐的安装方式是直接引入script。vue脚本也分为开发版vue.js和生产版vue.min.js,开发环境下推荐使用vue.js,可以在开发过程中看到常见错误相关的警告。你可以选择使用CDN服务,直接引入这个脚本即可进行开发。

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

本人还是习惯直接把脚本下载到项目文件夹中。

<script src="./lib/vue.js"></script>

学习Vue

学习Vue.js最好的方法当然是把代码都撸一遍,这样印象会比较深刻。

v-if

这个指令类似于angular的*ngIf,作为一个结构性指令,用来控制元素的插入和移除。当v-if=”true”时,元素正常显示;反之元素则被移除。

v-show

这个指令达到的效果看起来与v-if是一样的,但是从本质上来讲是不同的。v-show其实仅仅从样式上来控制显示和隐藏,改变的是display属性。与jQuery的show()和hide()方法有异曲同工之妙。

插值表达式

<span>{{ content }}</span>

这个是数据绑定的标准写法,与angular是一样的。content变量的值改变时,页面渲染也随之变化。插值表达式中支持js表达式。

v-html

从字面意思能看出来,该指令绑定的值会输出html内容,类似于jQuery的html()方法。在angular中好像没有看到这个指令,我是自定义了一个directive来实现的。

属性绑定v-bind

这个指令用来绑定元素属性,通常用于向子组件传递props。比如子组件studentList内部需要属性id来做逻辑判断,这个id可以由父组件来传递,这里就可以使用到v-bind。

<student-list v-bind:id="somevalue"></student-list>

v-bind:可以缩写为:

<student-list :id="somevalue"></student-list>

事件绑定v-on

用来绑定事件,比如鼠标点击事件,可以这样写:

<button v-on:click="toggleVueIf">Toggle VUE IF</button>

v-bind:可以缩写为@:

<button @click="toggleVueIf">Toggle VUE IF</button>

v-for

v-for用来遍历数组或对象
(1)数组,接收的参数上可以是两个,顺序是value, index

<ul v-for="(value, index) in vueForArray">
  <li>{{ index }}: {{ value }}</li>
</ul>

(2)对象,接收的参数上可以是三个,顺序是value, key, index

<ul v-for="(value, key, index) in vueForObject">
  <li>{{ index }}. {{ key }} : {{ value }}</li>
</ul>

计算属性computed

对于插值表达式中涉及到的复杂计算,建议用计算属性computed来替代。在new Vue时可以使用computed属性。

// html中
{{ reversedMessage }}
// vue实例中
computed: {
  reversedMessage: function() {
    return this.testMessage.split('').reverse().join('');
  }
}

这里只是一个倒序的算法,不算很复杂,只是举例说明。

watch属性

我们可以使用watch来进行侦听,来响应数据的变化。上面计算属性的应用,我们也可以改用watch来写:

watch: {
  testMessage: function() {
    this.reversedMessage = this.testMessage.split('').reverse().join('');
  }
}

这里,我们通过侦听testMessage的变化来做出响应,用于改变reversedMessage的值。

ps:那么computed和watch的应用场景怎么区分?
个人认为,computed更适合做一些数据值的计算,而涉及到侦听某变量需要做一些业务处理时,建议使用watch。

class绑定

<!-- 类似这种形式,与属性绑定大同小异。class的绑定值可以是键值对,也可以是数组。 -->
<div :class="{ category: isCategory, red: isRed }"></div>

style绑定

与class绑定类似,支持键值对语法(css键值对),也支持数组(多个样式对象同时作用)。

<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

双向绑定v-model

这一特性与angular的[(ngModel)]是一致的。通常用于表单元素。

<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>

不过v-model还支持很多修饰符,如
(1).lazy

<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg" >

(2).number
自动将用户的输入值转为数值类型
(3).trim
自动过滤用户输入的首尾空白字符

.sync

看名字就知道了,同步的意思,如果绑定的属性加上这个修饰符,就实现了双向绑定。.sync破坏了单向数据流,于2.0 中移除,但又在 2.3.0 版本后以语法糖形式重新引入。

<comp :foo.sync="bar"></comp>

父子组件通信

父组件通过属性传递数据给子组件props,而子组件以this.$emit(eventname, data)的方式发事件给父组件,父组件模板中需要绑定对应事件。

// 父组件模板,通过绑定greet传递数据给子组件,@replay接收来自子组件的事件。
<child :greet="greetMsg" @reply="showReply"></child>
// 子组件props属性接收
props: ['greet']
// 子组件模板
<p>Greet from Father Component: {{greet}}</p>
<button @click="replyToFather">Reply</button>
// 点击button时调用replyToFather方法,通过$emit发送事件给父组件。
methods: {
  replyToFather: function() {
    this.$emit('reply', this.replyInfo);
  }
}

slot

类似angular的ng-content。父组件可以将想要的内容插在子组件的插槽中。子组件slot标签通过name属性区分插槽,如name=”slot1”,不写name属性的就是默认插槽了;而父组件要在传递给插槽的标签中加上slot属性来区分插在哪个槽中,如slot=”slot1”,如果不加slot属性,则自动插在默认插槽中。slot标签中的内容都被视为备用内容,如果父组件不给子组件传入内容,则会显示子组件slot标签中的备用内容。使用如下:

<!-- 父组件模板 -->
<child>
  <!-- 没有指定slot属性,所以插在子组件中没有name属性的slot位置 -->
  <p>Message From Father</p>
  <!-- 指定了slot属性的值为head,所以插在子组件中name属性值为head的slot位置 -->
  <p slot="head">For Head</p>
  <!-- 指定了slot属性的值为foot,所以插在子组件中name属性值为foot的slot位置 -->
  <p slot="foot">For Foot</p>
  <!-- 没有指定slot属性,所以插在子组件中没有name属性的slot位置 -->
  <p>Other information...</p>
<child>
<!-- 子组件模板 -->
<div>
  <slot name="head">head content...</slot>
  <slot>Backup content...</slot>
  <slot name="foot">foot content...</slot>
</div>

作用域插槽

官方提供的说明我不太看得懂,根据我个人的理解,一个很重要的应用场景就是用来抽象列表式组件。比如一个展示性的列表组件,但是具体展示图文,还是其他的,需要由其父组件来指定。我这里写了一个demo。

<!-- 父组件模板 -->
<my-list :items="movies">
  <template slot-scope="props">
    <li>
      <img class="poster" :src="props.item.posterUrl"/>
      <div>{{ props.item.moviename }}</div>
    </li>
  <!-- 我可以在这里调用各种组件,来适应各种需要,比如我可以做海报展示,那么我只要一个<img>;比如我只要电影名称的列表,那么就只要用到电影名称 -->
  </template>
</my-list>
<!-- 子组件模板,模板中的items是由props接收的 -->
<ul>
  <span class="hot-movie">近期热映</span>
  <slot name="slot-item" v-for="item in items" :item="item"></slot>
</ul>

使用要点:
(1)父组件通过属性绑定将数据(一般是数组,毕竟是用于列表展示嘛)传递给子组件。

<my-list :items="movies"></my-list>

(2)父组件传递给子组件的内容用template标签包裹,template标签具备slot-scope=”props”,props来源于子组件slot标签绑定的属性集,而本例中slot标签绑定了item属性,所以template中的内容可以调用props.item下的属性。

动态组件

利用component标签及其is属性可以动态切换组件。curComponent的值为组件名。

<component :is="curComponent"></component>

keep-alive标签

利用keep-alive标签包裹component标签可以让切换组件保留在内存中,可以保留它的状态,避免重新渲染。

<keep-alive>
  <component :is="curComponent"></component>
</keep-alive>

ref属性

ref属性实现了组件的引用,不过应当避免使用ref。

<ref-comp ref="refComp"></ref-comp>
<!-- 我们可以在父组件中直接改变子组件中的refValue属性 -->
this.$refs.refComp.refValue += 'a';

transition过渡

在组件外包裹一层transition标签,name标识transition,即可为组件加上过渡效果。如:

<transition name="fade">
  <p v-show="showFade">Fade</p>
</transition>

在进入/离开的过渡中,会有 6 个 class 切换,默认 class 名称格式如下。

  • fade-enter // 进入过渡开始,一般在这个class下定义-过渡开始时的css状态
  • fade-enter-active // 进入过渡活跃状态,一般在这个-class下定义进入过渡过程中的动画
  • fade-enter-to // 进入过渡结束,一般在这个class下定义过渡结束时的css状态。ps:离开过渡不再说明,类似开始过渡。
  • fade-leave // 离开过渡开始
  • fade-leave-active // 离开过渡活跃状态
  • fade-leave-to // 离开过渡结束

我们也可以自定义过渡类名,需要增加transition标签的属性,这样就可以使用第三方的动画库了。用法如下:

<transition name="fade" enter-active-class="animated tada" leave-active-class="animated bounceOutRight">
  <p v-show="showFade">Fade</p>
</transition>

过渡效果主要的应用场景有:

  • v-if
  • v-show
  • 动态组件

transition有着一系列javascript钩子函数,从字面意思可以与过渡的class对应起来,如下所示:

<transition
  :css="false"
  @before-enter="beforeEnter"
  @enter="enter"
  @after-enter="afterEnter"
  @enter-cancelled="enterCancelled"

  @before-leave="beforeLeave"
  @leave="leave"
  @after-leave="afterLeave"
  @leave-cancelled="leaveCancelled"
>
......
</transition>

钩子函数都有参数el,用于引用添加了transition包裹的元素。enter和leave钩子函数中额外有一个参数done,done是一个回调函数,是必须在最后调用的。否则,它们会被同步调用,过渡会立即完成。

enter: function (el, done) {
  // ...
  done();
}

有了js钩子函数,那么我就可以不使用class来定义过渡的效果了,我可以使用js动画库,如velocity.js,这个时候最好添加v-bind:css=”false”,Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。

我们可以给元素设置初始渲染的过渡效果。

<transition appear>
  <!-- ... -->
</transition>

appear拥有相同的class钩子和js钩子,也可以自定义类名。

多个元素的过渡

transition中多个元素过渡时,可以这样写,给每个元素加上key属性来作为唯一标识:

<transition>
  <button v-if="isEditing" key="save">
    Save
  </button>
  <button v-else key="edit">
    Edit
  </button>
</transition>

上述代码也可以简写为绑定key的形式,而不再需要if,else:

<transition>
  <button :key="isEditing">
    {{ isEditing ? 'Save' : 'Edit' }}
  </button>
</transition>

其中的isEditing ? ‘Save’ : ‘Edit’也可以抽象为一个computed属性。

除了多个元素的过渡,类似的还有动态组件的过渡。

<transition name="fade-dynamic" mode="out-in">
  <component :is="curComponent"></component>
</transition>

mode属性定义了过渡模式,防止当前元素的离开与下一个元素的进入产生重叠现象:

  • in-out:新元素先进行过渡,完成之后当前元素过渡离开。
  • out-in:当前元素先进行过渡,完成之后新元素过渡进入。

列表过渡

列表过渡用到的组件是transition-group。transition-group会以真实的元素存在于html文档中,而transition是不存在于html文档中的。transition-group存在的形式由tag属性指定,如

<transition-group name="group-list" tag="div">
  <div v-for="item in groups" :key="item.id" class="group-item">
    <img class="group-item-img" :src="item.picUrl"/>
  </div>
</transition-group>

为了让group-list的过渡效果平滑,有一个v-move属性,也是通过绑定class实现

.group-list-move {
  transition: transform 1s;
}

另一种实现方式如下:

.group-item {
  margin: 10px;
  display: inline-block;
  width: 100px;
  height: 60px;
  transition: all 1s;
}
.group-item-img {
  width: 100%;
  height: 100%;
}
/* 这个作用是让元素在离开的过程中不占位,使过渡看起来十分平滑 */
.group-list-leave-active {
  position: absolute;
}
/* .group-list-enter-active, .group-list-leave-active {
  transition: all 1s;
} */
.group-list-enter, .group-list-leave-to {
  opacity: 0;
  transform: translateY(30px);
}
/* move属性作用于元素的改变定位的过程中,这里会让transform有一个过渡效果;
如果需要让列表整体有一个整体性过渡,那么可以在group-item类中加上transition属性,
那么也就不需要group-list-enter-active和group-list-leave-active类中有transition属性了。
*/
/* .group-list-move {
  transition: transform 1s;
} */

mixin

mixin是一种提高编写效率的写法,详情请参考mixin

vue自定义指令

一个指令定义对象可以提供如下几个钩子函数。

  • bind:只调用一次,指令第一次绑定到元素时调用。
  • inserted:被绑定元素插入父节点时调用
  • update
  • componentUpdated
  • unbind

目前未对指令进行深究,只写了一个简单的指令。

directives: {
  autoClick: {
    inserted: function(el) {
      el.click();
    }
  }
}

vue组件生命周期

参考:
(1)Vue2.0 探索之路——生命周期和钩子函数的一些理解
(2)API

猜你喜欢

转载自blog.csdn.net/weixin_41196185/article/details/79822170
今日推荐