Vue学习笔记

Vue

 

学习目标

Vue学习笔记_第1张图片

前端知识体系

HTML(页面的结构)、CSS(表现层)、JavaScript(行为)

HTML

就不说了。

CSS

CSS层叠样式是一门标记语言,并不是编程语言,因此不可以自定义变量,不可以引用等,换句话说就是不具
任何语法支持,它主要缺陷如下:

  • 语法不够强大,比如无法嵌套书写,导致模块化开发中需要书写很多重复的选择器;
  • 没有变量和合理的样式夏用机制,使得逻辑上相关的属性值必须以字 面量的形式重复输出,导致难以維护;

这就导致了我们在工作中无端增加了许多工作量。为了解决这个问题,前端开发人员会使用一种称之为【CSS预处理器】的工具,提供 CSS 缺失的样式层复用机制、减少冗余代码,提高样式代码的可维护性。大大提高了以前在样式上的开发效率。

什么是 CSS 预处理器

CSS 预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为 CSS 增加了一些编程的特性,将CSS作为目标生成文件,然后开发者就只要使用这种语言进行 CSS 的编码工作。转化成通俗易懂的话来说就是一种专门的编程语言,进行 Web 页面样式设计,再通过编译器转化为正常的CSS 文件,以供项目使用”

常用的 CSS 预处理器有哪些

  • SASS:基于Ruby,通过服务端处理,功能强大。解析效率高。需要学习 Ruby 语言,上手难度高于 LESS.
  • LESS:基于NodeJS,通过客户端处理,使用简单。功能比 SASS 简单,解析效率也低于 SASS,但在实际开中足够了,所以我们后台人员如果需要的话,建议使用 LESS。

JavaScript

Javascript 一门弱类型脚本语言,其源代码在发往客户端运行之前不需经过编译,而是将文本格式的字符代码发送给刘览器由浏览器解释运行。

Vue学习笔记_第2张图片

Native 原生JS开发

原生JS 开发,也就是让我们按照【ECMAScript】标准的开发方式,简称是 ES,特点是所有浏览器都支持。截止到目前,ES 标准已发布如下版本:

  • ES3
  • ES4(内部,未正式发布)
  • ES5(全浏览器支持)
  • ES6(常用,当前主流版本)
  • ES7
  • ES8
  • ES9(草家阶段)

区别就是逐步增加新特性。

Typescript 微软的标准

Typescript 是一种由微软开发的自由和开源的编程语言。它是JavaScript 的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。由安德斯-海尔斯伯格(C#、Delphi、 TypeScript 之父、.NET 创立者)主导。

该语言的特点就是除了具备 ES 的特性之外还纳入了许多不在标准范国内的新特性,所以会导致很多浏览器不能直接支持 TypeScript 语法,需要编译后(编译成JS) 才能被浏览器正确执行。

JavaScript框架

  • jQuery:大家熟知的JavaScript 框架,优点是简化了 DOM 操作,缺点是 DOM操作太频繁,影响前端性能;在前端眼里使用它仅仅是为了兼容 IE6、7、8;
  • Angular:Google 收购的前端框架,由一群ava 程序员开发,其特点是将后台的 MVC 模式搬到了前端并增
  • React: Facebook 出品,一款高性能的JS 前端框架;特点是提出了新概念【虚拟 DOM】 用于减少真实DOM操作,在内存中模拟 DOM 操作,有效的提升了前端渲染效率;缺点是使用复杂,因为需要额外学习一门 【JsX】语言;
  • Vue:一款渐进式 javaScript 框架,所谓渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等新特性。其特点是综合了 Angular(模块化)和React (虛拟 DOM) 的优点;
  • Axios:前端通信框架,因为 vue 的边界很明确,就是为了处理 DOM,所以并不具备通信能力,此时就需要额外使用一个通信框架与服务器交互;当然也可以直接选择使用 jQuery 提供的 AJAX 通信功能;

UI框架

  • Ant-Design:阿里巴巴出品,基于 React的 UI框架
  • ElementUl:饿了么出品,基于 vue 的U框架
  • Bootstrap: Twitter 推出的一个用于前端开发的开源工具包
  • AmazeUl:又叫妹子UI,一款 HTML5 跨屏前端框架

JavaScript构建工具

  • BaBel JS 编译工具,主要用于浏览器不支持的ES新特性,比如用于编译TypeScript
  • WebPack:模块打包工具,主要作用于打包、压缩、合并及按序加载

前后端分离的演进史

后端为主的MVC时代

为了降低开发的复杂度,以后端为出发点,比如:Struts、SpringMVC等框架的使用,就是后端的MVC时代,以SpringMVC的为例:

Vue学习笔记_第3张图片

  • 用户发起请求到前端控制器(DispathcerServlet)
  • 前端控制器请求处理器映射器(HandlerMapping)查找Hanlder,可以根据XmL配置、注解进行查找
  • 处理器映射器向前端控制器返回Handler
  • 前端控制器调用处理器适配器(HandlerAdapter)去执行Handler
  • 处理器适配器去执行 handler
  • handler 执行完成之后给适配器返回 ModelAndView
  • 处理器适配器向前端控制器返回 ModelAndView,ModelAndView是SpringMVC框架的一个底层对象,包括Model、View
  • 前端控制器请求视图解析器去进行视图解析,根据逻辑视图名解析成真正的视图(JSP)
  • 视图解析器向前端控制器返回View
  • 前端控制器进行视图渲染,视图渲染将模型数据(ModelAndView对象中)填充到request域
  • 前端控制器向用户响应结果

优点

MVC是一个非常好的协作模式,能够有效降低代码的男合度,从架构上能够让开发者明白代码应该写在哪里。为了让View 更纯粹,还可以使用 Thymeleaf、Freemarker 等模板 !擎,使模板里无法写入Java 代码,让前后端分工更加清晰。

缺点

前端开发重度依赖开发环境,开发效率低,这种架构下,前后端协作有两种模式:

  • 第一种是前端写 DEMO,写好后,让后端去套模板。好处是 DEMO 可以本地开发,很高效。不足是还需要后端套模板,有可能套错,套完后还需要前端确定,来回沟通调整的成本比较大;
  • 另一种协作模式是前端负责浏览器端的所有开发和服务器端的 View 层模板开发。好处是 U1 相关的代码都是前端去写就好,后端不用太关注,不足就是前端开发重度綁定后端环境,环境成为影响前端开发效率的重要因素。

前后端职责纠缠不清:模板引擎功能强大,依旧可以通过拿到的上下文变量来实现各种业务逻辑。这样,只要前端弱势一点,往往就会被后端要求在模板层写出不少业务代码,还有一个很大的灰色地带是 controller。页面路由等功能本应该是前端最关注的,但却是由后端来实现。

controller 本身与Mode 往往也会纠缠不清,看了让人咬牙的业务代码经常会出现在 controller 层。这些问题不能全归结于程序员的养,否则JSP就够了。

对前端发挥的局限性:性能优化如果只在前端做空间非常有限,于是我们经常需要后端合作,但由于后端框架限制,我们很难使用 【Comet】、【Bigpipe】 等技术方案来优化性能。

基于Ajax带来的SPA时代

时间回到 2005年 AJAx (Asynchronous Javascript And XML, 异步javaScript 和XML,老技术新用法) 被正式提出并开始使用 CDN 作为静态资源存储,于是出现了JavaScript 王者归来(在这之前JS都是用来在网页上贴狗皮育药广告的)的SPA (Single Page Application) 单页面应用时代。

Vue学习笔记_第4张图片

优点:

这种模式下,前后端分离非常清晰,前后端的协作点就是AJAX接口。看起来是如此美妙,但回过来看看的话,这与jsp时代的区别不大。复杂度从服务端的jsp里移到了浏览器的JavaScript,浏览器端 变得很复杂,类似,SpringMVC,这个时代开始出现浏览器端的分层结构:

Vue学习笔记_第5张图片

缺点

  • 前后端接口的约定:如果后端的接口一塌糊涂,如果后端的业务横型不够稳定,那化前端开发会很痛告;不少团队也有类似会试,通过接口规则、接口平台等方式来做。有了和后端一起沉淀的 接口规则,还可以用来模拟数据,使得前后端可以在约定接口后实现高效井行开发。
  • 前端开发的复杂度控制:SPA 应用大多以功能交互型为主,Javascript代码过十万行很正常。大量JS代码的组织,与View 层的鄉定等,都不是容易的事情。

前端为主的MV*时代

此处的MV* 模式如下:

  • MVC(同步通信为主):Model、 View、 Controller
  • MVP(异步通信为主):Model、 View、Presenter
  • MWM(早步通信为主):Mpdell、view、ViewModel

为了降低前端开发复杂度,涌现了大量的前端框架,比如:AngularJs、React、vue. js、EmberJs 等,这些框架总的原则是先按类型分层
比如 Templates、Controllers、Models,然后再在层内做切分,如下图:

Vue学习笔记_第6张图片

优点:

  • 前后端职责很清晰:前端工作在利览器端,后端工作在服务端。清晰的分工,可以让开发并行,测试数据的模拟不难,前端可以本地开发。后端则可以专注于业务逻辑的处理,输出 RESTful。
  • 前端开发的复杂度可控:前端代码很重,但合理的分层,让前端代码能各司其职。这一块蛮有意思的,简单如模板特性的选择,就有很多很多讲究。并非越强大越好,限制什么,留下哪些自由,代码应该如何组织,所有这一切设计,得花一本书的厚度去说明。
  • 部署相对独立:可以快速改进产品体验

缺点:

  • 代码不能复用。比如后端依1日需要对数据做各种校验,校验逻辑无法复用浏览品端的代码。如果可以复用,那么后端的数据校验可以相对简单化。
  • 全异步,对SEO 不利。往往还需要服务端做同步渲染的降级方案。
  • 性能并非最佳,特别是移动互联网环境下。
  • SPA 不能满足所有需求,依1日存在大量多页面应用。URL Design 需要后端配合,前端无法完全掌控。

NodeJS带来的全栈时代

前端为主的MV*模式解决了很多的问题,但如上所述,依旧存在不少的不足之处,随着NodeJS的兴起。JavaScript开始有能力运行在服务器。这意味可以有一种新的开发模式:

Vue学习笔记_第7张图片

在这种研发模式下,前后端的职责很清晰。对前端来说,两个UI 层各司其职:

  • Front-end UI layer 处理刘览器层的展现逻辑。通过 CSS 這染样式,通过 JavaScript 添加交互功能,HTML的生成也可以放在这层,具体看应用场景。
  • Back-end UI layer 处理路由、模板、数据获取、Cookie 等。通过路由,前端终于可以自主把控 URLDesign,这样无论是单页面应用还是多页面应用,前端都可以自由调控。后端也終于可以摆脱对展现的强关注,转而可以专心于业务逻辑层的开发。

通过 Node, Web Server 层也是javaScript 代码,这意味着部分代码可前后复用,需要 SEO 的场景可以在服务端同步淔染,由于异步请求大多导致的性能问题也可以通过服名端来續餵,前一种模式的不足,通过这种模式几乎都能完美解决掉。

与JSP 模式相比,全栈模式看起来是一种回归,也的确是一种向原始开发模式的回1归,不过是一种螺旋上升式的回
归。

基于 NodeJS 的全栈模式,依旧面临很多挑战:

  • 需要前端对服务端编程有更进一步的认识。比如TCP/IP 等网络知识的掌握。
  • NodeJS 层与java 层的高效通信。NodeJS 模式下,都在服务器端,RESTFul HTTP 通信末必高效,通过 SOAP等方式通信更高效。一切需要在验证中前行。
  • 对部署、运维层面的熟练了解,需要更多知识点和实操经验。
  • 大量历史遗留问题如何过渡。这可能是最大最大的阻力。

前端的MVVM模式

什么是MVVM

MVVM (Model-View-ViewModel)是一种软件架构设计模式,由微软 WPF(用于替代 WinForm,以前就是用这个技术开发桌面应用程序的)和Silverlight(类似于Java Applet,简单点说就是在浏览器上运行的WPF) 的架构师 Ken Cooper 和 Ted Peters 开发,是一种简化用户界面的事件驱动编程方式。由John Gossman(同样也是WPF 和 Silverlight 的架构师) 于2005年在他的博客上发表。

Vue学习笔记_第8张图片
Vue学习笔记_第9张图片

MWVM源自于经典的 MVC (Model-View-Controller)模式(期间还演化出了 MVP (Model-View-Presenter)模式)。MVVM 的核心是 ViewModel 层,负责转换 Model 中的数据对象来让数据变得更容易管理和使用,其作用如下:

  • 该层向上与视图层讲行双向数据綁定
  • 向下与 Model 层通讨接口请求讲行数据交互
Vue学习笔记_第10张图片

MVVM现在已经相当成熟了,主要运用但不仅仅运用在网络应用程序开发中。当下流行的MVVM框架有vue.js、Angular JS等。

为什么要用MVVM模式

MVVM 模式和 MVC 模式一样,主要目的是分离视图(View)和模型(Model),有几大好处:

  • 低耦合:视图 (View)可以独立于Model 变化和修改,一个ViewModel 可以绑定到不同的 View 上,当View 变化的时候 Model 可以不变,当 Model 变化的时候 View 也可以不变。
  • 可复用:你可以吧一些视图设辑放在一个ViewModel 里面,让很多 View 重用这段视图逻辑。
  • 独立开发:开发人员可以专注于业务逻辑和数据的开发 (ViewModel),设计人员可以专注于页面设计。
  • 可测试:界面素来是比较难于测试的,而现在测试可以针对 ViewModel 来写。

MVVM的组成部分

Vue学习笔记_第11张图片

View

View 是视图层,也就是用户界面。前端主要由 HTML 和 CSS 来构建,为了更方便地展现 ViewModel 或者 Model 层的数据,已经产生了各种各样的前后端模板语言,比如 FreeMarker、Marko、Pug、Jinja2等等,各大 MVVM 框架如 KnockoutJS,Vue,Angular 等也都有自己用来构建用户界面的内置模板语言。

ViewModel

ViewModel 是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的 Model 数据进行转换处理,做二次封装,以生成符合 View 层使用预期的视图数据模型。需要注意的是 ViewModel 所封装出来的数据模型包括视图的状态和行为两部分,而 Model 层的数据模型是只包含状态的,比如页面的这一块展示什么,那一块展示什么这些都属于视图状态(展示),而页面加载进来时发生什么,点击这一块发生什么,这一块滚动时发生什么这些都属于视图行为(交互),视图状态和行为都封装在了 ViewModel 里。

这样的封装使得 ViewModel 可以完整地去描述 View 层。由于实现了双向绑定,ViewModel 的内容会实时展现在 View 层,这是激动人心的,因为前端开发者再也不必低效又麻烦地通过操纵 DOM 去更新视图,MVVM 框架已经把最脏最累的一块做好了,我们开发者只需要处理和维护 ViewModel,更新数据视图就会自动得到相应更新,真正实现数据驱动开发。

看到了吧,View 层展现的不是 Model 层的数据,而是 ViewModel 的数据,由 ViewModel 负责与 Model 层交互,这就完全解耦了 View 层和 Model 层,这个解耦是至关重要的,它是前后端分离方案实施的重要一环。

ViewModel 是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的Model数据进行转换处理,做二次封装,以生成符合 View 层使用预期的视图数据模型。

需要注意的是 ViewModel 所封装出来的数据模型包括视图的状态和行为两部分,而Model 层的数据模型是只包含状态的

  • 比如页面的这一块展示什么,那一块展示什么这些都属于视图状态 (展示)
  • 页面加载进来时发生什么,点击这一块发生什么,这一块滚动时发生什么这些都属于视图行为(交互)

View 层展现的不是Model 层的数据,而是 ViewModel 的数据,由 ViewModel 负责与Model 层交互,这就完全解耦了 View 层和Model 层,这个解耦是至关重要的,它是前后端分离分离实施的重要一环。

Model

Model 是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,主要围绕数据库系统展开。后端的处理通常会非常复杂:

Vue学习笔记_第12张图片

前后端对比

后端:我们这里的业务逻辑和数据处理会非常复杂!
前端:关我屁事!

后端业务处理再复杂跟我们前端也没有半毛钱关系,只要后端保证对外接口足够简单就行了,我请求API,你把数据返出来,咱俩就这点关系,其他都扯淡。

Vue概述

Vue学习笔记_第13张图片

介绍 — Vue.js (vuejs.org)

Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

如果你想在深入学习 Vue 之前对它有更多了解,我们制作了一个视频,带您了解其核心概念和一个示例工程。

MVVM模式的实现者

我们知道MVVM的表示如下:

  • Model:模型层,在这里表示JavaScript对象
  • View:视图层,在这里表示DOM对象(Html操作的元素)
  • ViewModel:连接视图和数据中间的中间件,Vue.js就是MVVM中的ViewModel层的实现者

在MVVM的架构中,是不允许数据和视图层直接通信的,只能通过ViewModel来通信。而ViewModel就是定义了一个observer观察者。

  • ViewModel 能够实时的观察到数据的变化,并对视图对应的内容进行更行。
  • ViewModel 能够监听到视图的变化,并能够通知数据发生改变。

至此,我们就明白了,一个vue.js就是MVVM的实现者,他的核心就是适当了DOM的监听数据绑定

其他的MVVM的实现者

  • Angulat JS
  • React JS
  • 微信小程序

为什么要使用Vue.JS

  • 轻量级,体积小是一个重要指标。vuejs 压缩后有只有 30多kb (Angular 压缩后 56kb+,React 压缩后44kb+)
  • 移动优先。更适合移动端,比如移动端的 Touch 事件
  • 易上手,学习曲线平稳,文档齐全
  • 吸取了 Angular(模块化) 和React (虚拟 DOM)的长处,并拥有自己独特的功能,如:计算属性开源,社区活跃度高

Vue.Js的核心两大要素

数据驱动

Vue.js在实例化的过程中,会对实例化对象选项中的 data 选项进行遍历,遍历其所有属性并使用Object.defineProperty 把这些属性全部转为 getter/setter。

同时每一个实例对象都有一个watcher实例对象,他会在模板编译的过程中,用getter去访问data的属性,watcher此时就会把用到的data属性记为依赖,这样就建立了视图与数据之间的联系。

当之后我们渲染视图的数据依赖发生改变(即数据的setter被调用)的时候,watcher会对比前后两个的数值是否发生变化,然后确定是否通知视图进行重新渲染这样就实现了所谓的数据对于视图的驱动。

通俗地讲,它意味着我们在普通 HTML 模板中使用特殊的语法将 DOM “绑定”到底层数据。

一旦创建了绑定,DOM 将与数据保持同步。每当修改了数据,DOM 便相应地更新。这样我们应用中的逻辑就几乎都是直接修改数据了,不必与 DOM 更新搅在一起。这让我们的代码更容易撰写、理解与维护。

Object.defineProperty 是 ES5 中一个无法shim 的特性,这也就是为什么Vue 不支持 IE8 以及更低版本浏览器。

这些 getter/setter对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。

这里需要注意的问题是流览器控制台在打印数据对象时 getter/setter 的格式化并不同,所以你可能需要安装 vue-devtools 来获取更加友好的检查接口。

每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter 被调用时,会通知watcher 重新计算,从而致使它关联的组件得以更新。

组件化

  • 页面上每个独立的可交互的区域视为一个组件
  • 每个组件都对应着一个工程目录,组件所需要的各种资源在这个目录下就近维护
  • 页面不过是组件的容器,组件可以嵌套自由结合(复用)的形式完整的页面

第一个Vue程序

介绍 — Vue.js (vuejs.org)

GitHub - bearbrick0/Vue-demo: Vue入门的demo

Vue学习笔记_第14张图片

Vue实例的生命周期

05-Vue入门系列之Vue实例详解与生命周期 - FlyDragon - 博客园

Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、卸载等一系列过程,我们称这是Vue的生命周期。

通俗说就是Vue实例从创建到销毁的过程,就是生命周期。

在Vue的整个生命周期中,它提供了一系列的事件,可以让我们注册js方法,可以让我们达到控制整个过程的目的地,哇赛,如果你搞过Asp.Net WebForm的话,你会发现整个就是WebForm的翻版嘛哈哈。

值得注意的是,在这些事件响应方法中的this直接指向的是vue的实例。

首先看看下面官网的一张生命周期的图,我做一下标注,看看整体的流程,后面我们上代码做一下效果。

Vue学习笔记_第15张图片

beforeCreate和created,就很想我们Spring中的Aop的环绕通知。还是有很多的AOP的思想。

Vue的语法

条件渲染




    
    Vue语法
    
    


Vue is awesome

Oh no

Now you see me
Now you don't
A
B
C
Not A/B/C

列表渲染




    
    Title
    
    



  • {{ item.message }}

事件处理




    
    Title
    
    


使用Axios实现异步通信

Axios 中文文档 | Axios 中文网 | Axios 是一个基于 promise 的网络请求库,可以用于浏览器和 node.js (axios-http.cn)

什么是Axios

Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。

特性

  • 从浏览器创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换JSON数据
  • 客户端支持防御XSRF

安装

使用 npm:

$ npm install axios

为什么要使用Axios

由于 vuejs 是一个视图层框架 并且作者(尤雨溪)严格准守 SoC(关注分离原则),所以vue.js 并不包含AJAX 的通信功能,为了解决通信问题,作者单独开发了一个名为 vue-resource 的插件,不过在进入2.0 版本以后停止了对该插件的维护并推荐了 Axios 框架

第一个Axios的程序

Data.json

{
  "name": "百度",
  "url": "http://www.baicu.com",
  "page": 66,
  "isNonProfit": true,
  "address": {
    "street": "海定区",
    "city": "北京市",
    "country": "中国"
  },
  "links": [
    {
      "name": "Google",
      "ur": "http://www.google.com"
    },
    {
      "name": "Baidu",
      "ur]": "http://www.baidu.com"
    },
    {
      "name": "Sougou",
      "url": "http://www.sougou.com"
    }
  ]
}



    
    Title
    
    
    
    


name:{{info.name}}
  • {{item.name}}---->{item.url}}

表单输入绑定

什么是双向数据绑定

vue.js 是一个MVVM 框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是 vue js 的精髓之处了。值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的,非UI控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用 vuex,那么数据流也是单项的,这时就会和双向数据绑定有冲突。

为什么要实现数据的双向绑定

在vuejs 中,如果使用vuex,实际上数据还是单向的,之所以说是数据双向绑定,这是用的UI控件来说,对于我们处理表单,vuejs 的双向数据绑定用起来就特别舒服了。即两者并不互斥,在全局性数据流使用单项,方便跟踪;局部性数据流使用双向,简单易操作。

在表单中使用双向数据绑定

你可以用 v-model 指令在表单 input、textarea及 select元素上创建双向数据绑定。它会根据控件类到自动选取正确的方法来更新元素,尽管有些神奇,但 v-model 本质上不过是语法糖,它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

Vue.js 教程

你可以用 v-model 指令在表单