vue.js
介绍
生态圈
挂载点/模板/实例
vue只会对它所对应的挂载点(el)内的内容产生作用。
挂载点里的内容称为模版(template),模版可以通过template写在vue中,和写在挂载点下面的作用是一样的。
vue实例(new Vue({}))绑定到挂载点后会自动对模版和数据内容进行处理,生成要最终展示的内容。
<div id="root"></div> <script> /*vue实例*/ new Vue({ el:"#root", //挂载点(dom) template: '<h1>hello {{message}}!</h1>', //模板 data:{ message:"world" } }) </script>
$访问vue实例属性
vue实例变量.$属性 可以访问vue实例的属性。
<div id="app"> {{a}} </div> <script type="text/javascript"> var data = { a : 1 }; var vm = new Vue({ el : "#app", data : data }); vm.$watch('a', function(newVal, oldVal){ console.log(newVal, oldVal); }) vm.$data.a = "test...." </script>
生命周期
<div id="app"> {{msg}} </div> <script type="text/javascript"> var vm = new Vue({ el : "#app", data : { msg : "hi vue", }, //在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。 beforeCreate:function(){ console.log('beforeCreate'); }, /* 在实例创建完成后被立即调用。 在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。 然而,挂载阶段还没开始,$el 属性目前不可见。 */ created :function(){ console.log('created'); }, //在挂载开始之前被调用:相关的渲染函数首次被调用 beforeMount : function(){ console.log('beforeMount'); }, //el 被新创建的 vm.$el 替换, 挂在成功 mounted : function(){ console.log('mounted'); }, //数据更新时调用 beforeUpdate : function(){ console.log('beforeUpdate'); }, //组件 DOM 已经更新, 组件更新完毕 updated : function(){ console.log('updated'); } }); setTimeout(function(){ vm.msg = "change ......"; }, 3000); </script>
模板语法-数据展示
{{}}插值表达式
{{ }} 用于输出对象属性和函数返回值,表达式内可以做运算和函数操作。
<div id="app"> {{msg}} <p>Using mustaches: {{ rawHtml }}</p> <p v-html="rawHtml"></p> <div v-bind:class="color">test...</div> <p>{{ number + 1 }}</p> <p>{{ 1 == 1 ? 'YES' : 'NO' }}</p> <p>{{ message.split('').reverse().join('') }}</p> </div> <script type="text/javascript"> var vm = new Vue({ el : "#app", data : { msg : "hi vue", rawHtml : '<span style="color:red">this is should be red</span>', color:'blue', number : 10, ok : 1, message : "vue" } }); vm.msg = "hi...."; </script>
v-text/v-html指令显示数据
<div id="root"> <div v-text="message"></div> <!--v-text以文本形式显示data中指定数据--> <div v-html="content"></div> <!--v-html以html形式解析data中指定数据--> </div> <script> /*vue实例*/ new Vue({ el:"#root", //挂载点(dom) data:{ message:"world", content:"<h1>hello world<h1>" } }) </script>
模板语法-事件
v-on:click事件和方法(@)
v-on:click(@click)调用vue的methods中声明的方法,v-on:可以简写成@符号
<div id="root"> <div v-on:click="this.handleClick">{{content}}</div> <!--v-on:可以写成 @click="this.handleClick"--> </div> <script> /*vue实例*/ new Vue({ el:"#root", //挂载点(dom) data:{ content:"hello", }, methods:{ handleClick: function(){ this.content = 'world'; } } }) </script>
@click.stop.stop阻止点击事件传播,只触发click方法
<div id="app"> <p v-if="seen">现在你看到我了</p> <a v-bind:href="url">...</a> <div @click="click1"> <div @click.stop="click2"><!-- .stop阻止点击事件传播,只触发click方法, --> click me </div> </div> </div> <script type="text/javascript"> var vm = new Vue({ el : "#app", data : { seen : false, url : "https://cn.vuejs.org/v2/guide/syntax.html#%E6%8C%87%E4%BB%A4" }, methods:{ click1 : function () { console.log('click1......'); }, click2 : function () { console.log('click2......'); } } }); </script>
事件绑定
<div id="app"> <div id="example-1"> <button v-on:click="counter += 1"> 数值 : {{ counter }} </button><br /> <button v-on:dblclick="greet('abc', $event)">Greet</button> </div> </div> <script type="text/javascript"> var vm = new Vue({ el : "#app", data : { counter: 0, name : "vue" }, methods:{ greet : function (str, e) { alert(str); console.log(e); } } }); </script>
修饰符
修饰符是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault(),这样只会执行绑定的方法,不会执行事件默认的操作。
<form v-on:submit.prevent="onSubmit"></form>
其他事件修饰符
Vue.js 为 v-on 提供了事件修饰符来处理 DOM 事件细节,如:event.preventDefault() 或 event.stopPropagation()。
Vue.js通过由点(.)表示的指令后缀来调用修饰符。
.stop
.prevent
.capture
.self
.once
<!-- 阻止事件传播 --> <a v-on:click.stop="doThis"></a> <!-- 提交事件时不再重载页面 --> <form v-on:submit.prevent="onSubmit"></form> <!-- 修饰符可以串联 --> <a v-on:click.stop.prevent="doThat"></a> <!-- 只有修饰符,阻止submit事件默认操作 --> <form v-on:submit.prevent></form> <!-- 添加事件侦听器时使用事件捕获模式,带此关键字会优先执行,然后执行子组件在执行父组件 --> <div v-on:click.capture="doThis">...</div> <!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 --> <div v-on:click.self="doThat">...</div> <!-- click 事件只能点击一次,2.1.4版本新增 --> <a v-on:click.once="doThis"></a>
按键修饰符
Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:
<!-- 只有在 keyCode 是 13 时调用 vm.submit() --> <input v-on:keyup.13="submit">
记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:
<!-- 同上 --> <input v-on:keyup.enter="submit"> <!-- 缩写语法 --> <input @keyup.enter="submit">
属性绑定和双向数据绑定
v-bind:属性绑定(:)
v-bind:属性绑定可以简写为:,属性双引号中的值是js表达式可以用js操作符操作。
class和style通过v-bind:修改
<div id="app"> <div class="test" v-bind:class="[ isActive ? 'active' : '', isGreen ? 'green' : '']" style="width:200px; height:200px; text-align:center; line-height:200px;"> hi vue </div> <div :style="{color:color, fontSize:size, background: isRed ? '#FF0000' : ''}"> hi vue </div> </div> <script type="text/javascript"> var vm = new Vue({ el : "#app", data : { isActive : true, isGreen : true, color : "#FFFFFF", size : '50px', isRed : true } }); </script> <style> .test{font-size:30px;} .green{color:#00FF00;} .active{background:#FF0000;} </style>
v-model双向绑定
双向绑定是指vue实例中的data和挂载点中的dom属性绑定,可以实现属性的值改变vue实例中的数据,不仅仅是vue实例的data数据影响dom。
<div id="root"> <div v-bind:title="title">{{content}}</div> <!--v-bind:缩写成:,意思是title属性值绑定为vue实例data中的title的值--> <input v-model="content" /> </div> <script> /*vue实例*/ new Vue({ el:"#root", //挂载点(dom) data:{ content:"hello", title:"this is hello world" } }) </script>
表单数据绑定
通过data属性和v-model绑定表单数据。
<div id="app"> <div id="example-1"> <input v-model="message" placeholder="edit me"> <p>Message is: {{ message }}</p> <textarea v-model="message2" placeholder="add multiple lines"></textarea> <p style="white-space: pre-line;">{{ message2 }}</p> <br /> <div style="margin-top:20px;"> <input type="checkbox" id="jack" value="Jack" v-model="checkedNames"> <label for="jack">Jack</label> <input type="checkbox" id="john" value="John" v-model="checkedNames"> <label for="john">John</label> <input type="checkbox" id="mike" value="Mike" v-model="checkedNames"> <label for="mike">Mike</label> <br> <span>Checked names: {{ checkedNames }}</span> </div> <div style="margin-top:20px;"> <input type="radio" id="one" value="One" v-model="picked"> <label for="one">One</label> <br> <input type="radio" id="two" value="Two" v-model="picked"> <label for="two">Two</label> <br> <span>Picked: {{ picked }}</span> </div> <button type="button" @click="submit">提交</button> </div> </div> <script type="text/javascript"> var vm = new Vue({ el : "#app", data : { message : "test", message2 :"hi", checkedNames : ['Jack', 'John'], picked : "Two" }, methods: { submit : function () { console.log(this.message); } } }); </script>
computed计算属性watch监听属性
<div id="root"> 姓:<input v-model="firstName" /> 名:<input v-model="lastName" /> <div>{{fullName}}</div> <div>{{count}}</div> </div> <script> /*vue实例*/ new Vue({ el:"#root", //挂载点(dom) data:{ firstName:"", lastName:"", count:0 }, computed:{ //计算属性,通过已有的data数据计算出新的属性,依赖变更时会重新计算 fullName:function(){ return this.firstName +' '+this.lastName; } }, watch:{ //监听器,监听数据的变化,当数据发生变化时执行 fullName:function(){ //当fullName属性值变化时 this.count++; } } }) </script>
过滤器
过滤器函数接受表达式的值作为第一个参数。
<div id="app"> {{ message | capitalize }} </div> <script> new Vue({ el: '#app', data: { message: 'abcd' }, filters: { capitalize: function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } } }) </script>
v-if、v-show标签
v-if值为ture,将元素插入dom,false删除dom。
v-show值为ture是显示dom,false时不显示,通过css样式,style="display: none;"。(性能高一点,不用每次新建dom)
<div id="root"> <div v-if="show">hello</div> <div v-show="show">world</div> <button @click="handleClick">toggle</button> </div> <script> /*vue实例*/ new Vue({ el:"#root", //挂载点(dom) data:{ show:true }, methods:{ handleClick:function(){ this.show = !this.show; } } }) </script>
多个v-if
<div id="app"> <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> </div> <script> new Vue({ el: '#app', data: { type: 'C' } }) </script>
v-for标签
v-for 指令可以用来遍历数组(val,index)、对象(val,key,index)、整数。
遍历每一个数据
<div id="root"> <ul> <!-- 遍历list中的每一项放入item中,index为下标,:key的作用是用来加速渲染一定要唯一 --> <li v-for="(item,index) of list" :key="index">{{item}}</li> </ul> </div> <script> /*vue实例*/ new Vue({ el:"#root", //挂载点(dom) data:{ list:['a','b','c'] } }) </script>
v-for遍历数组/对象
<div id="app"> <ul> <li v-for="item,index in items" :key="index"> {{index}}{{ item.message }} </li> </ul> <ul> <li v-for="value, key in object"> {{key}} : {{ value }} </li> </ul> </div> <script type="text/javascript"> var vm = new Vue({ el : "#app", data : { items : [ { message: 'Foo' }, { message: 'Bar' } ], object: { title: 'How to do lists in Vue', author: 'Jane Doe', publishedAt: '2016-04-10' } } }); </script>
动态修改数组
<div id="root"> <div> <input v-model="inputVal"/> <button @click="handleSubmit">提交</button> <!-- 通过提交事件的handleSubmit方法操作vue.$list数据,下面会自动显示list数据.(vue是数据驱动型,操作的是数据不是dom) --> </div> <ul> <!-- 仅仅是显示list中的值,当list中的值变化时这里也会跟着变 --> <li v-for="(item,index) of list" :key="index">{{item}}</li> </ul> </div> <script> /*vue实例*/ new Vue({ el:"#root", //挂载点(dom) data: { inputVal: '', //input双向绑定的值 list:[] //list数组 }, methods: { handleSubmit: function(){ //按钮绑定的方法 this.list.push(this.inputVal); this.inputVal = '' } } }) </script>
自定义指令
<div id="app"> <p>页面载入,input 元素自动获取焦点:</p> <input v-focus> </div> <script> // 注册一个全局自定义指令 v-focus Vue.directive('focus', { // 当绑定元素插入到 DOM 中。 inserted: function (el) { // 聚焦元素 el.focus() } }) // 创建根实例 new Vue({ el: '#app' }) </script>
组件
组件其实也是一个实例,注册一个全局组件语法格式如下:
Vue.component(tagName, options)
组件基础
<div id="app"> <!-- title属性是为了向子组件传参,@clicknow事件是为了被子组件触发执行clicknow函数接收子组件传来的参数 --> <button-counter title="title1 : " @clicknow="clicknow"> <h2>hi...h2</h2> </button-counter> <!-- 没有绑定子组件的@clicknow事件,并不会接收子组件传来的数据 --> <button-counter title="title2 : "></button-counter> </div> <script type="text/javascript"> Vue.component('button-counter', { props: ['title'], /* props是父组件向子组件传值 */ data: function () { return { count: 0 } }, /* <slot>标签为原有数据 */ template: '<div><h1>hi...</h1><button v-on:click="clickfun">{{title}} You clicked me {{ count }} times.</button><slot></slot></div>', methods:{ clickfun : function () { //1.模板内容点击绑定的事件 this.count ++; this.$emit('clicknow', this.count); //2.$emit将触发当前实例上的事件clicknow } } }) var vm = new Vue({ el : "#app", data : { }, methods:{ clicknow : function (data) { //3.clicknow为被子组件触发的事件,并接收子组件传来的参数 console.log(data); } } }); </script>
组件注册
<div id="app"> <button-counter></button-counter> <test></test> </div> <script type="text/javascript"> /* 全局注册 */ Vue.component('button-counter', { props: ['title'], data: function () { return {} }, template: '<div><h1>hi...</h1></div>', methods:{ } }) /* 局部注册 */ var vm = new Vue({ el : "#app", data : { }, methods:{ clicknow : function (e) { console.log(e); } }, components:{/* 局部注册,只能在挂载点使用组件 */ test : { template:"<h2>h2...</h2>" } } }); </script>
简单组件
<ol id="app"> <!-- 使用组件,创建一个todo-item组件的实例 --> <todo-item></todo-item> </ol> <!-- 这里的script一定要写在最后写在前面不行 --> <script> // 定义名为 todo-item 的新组件,tagName为todo-item(html中直接使用) Vue.component('todo-item', { template: '<li>这是个待办项</li>' }); //声明式渲染不能少 new Vue({ el: '#app' }) </script>
父组件传值子组件props
v-for遍历多次调用全局组件,动态添加数据。
父组件(vue实例)向子组件传值,通过属性绑定的方式传值,子组件通过props接收属性的值。
父组件 -> 将值绑定(v-bind:)在子组件的挂载点上 -> 子组件通过props获取挂载点上的属性值。
props是单向数据流: 避免了子组件意外修改父组件的状态;如需修改可以在data()中新定义一个局部数据属性;如果需要对props传过来的数值进行进一步的转换可以再computed中定义一个计算属性。
prop校验: type、required、default、validator
<div id="root"> <div> <input v-model="inputVal"/> <button @click="handleSubmit">提交</button> <!-- 通过提交事件的handleSubmit方法操作vue.$list数据,下面会自动显示list数据.(vue是数据驱动型,操作的是数据不是dom) --> </div> <ul> <!-- vue实例中的值每次改变dom也会跟着变动,这里把item作为参数传给组件了--> <todo-item v-for="(item,index) of list" :key="index" :param="item"> <todo-item/> </ul> </div> <script> /*全局组件,相当于一个li标签,中间的内容由父级实例传入,props接收父级实例传过来的数据*/ Vue.component('todo-item',{ props: ['param'], template:'<li @click="handleClick">{{param}}</li>', methods: { handleClick: function(){ alert('cl'); } } }); /*vue实例*/ new Vue({ el:"#root", //挂载点(dom) data: { inputVal: '', //input双向绑定的值 list:[] //list数组 }, methods: { handleSubmit: function(){ //按钮绑定的方法 this.list.push(this.inputVal); this.inputVal = '' } } }) </script>
子组件向父组件传值
要通过发布订阅的方式实现。
子组件通过this.$emit(事件,参数)方法触发事件 -> 父组件在子组件上通过v-on:方式监听事件 -> 父组件找到事件绑定的方法(带参数)并执行.
<div id="root"> <div> <input v-model="inputVal"/> <button @click="handleSubmit">提交</button> <!-- 通过提交事件的handleSubmit方法操作vue.$list数据,下面会自动显示list数据.(vue是数据驱动型,操作的是数据不是dom) --> </div> <ul> <!-- vue实例中的值每次改变dom也会跟着变动,这里把item作为参数传给组件了;监听组件的delete事件,如果被触发执行vue实例的handleDelete--> <todo-item v-for="(item,index) of list" :key="index" :param="item" :index="index" @delete="handleDelete"> <todo-item/> </ul> </div> <script> /*全局组件,相当于一个li标签,中间的内容由参数(遍历的item)传入并展示*/ Vue.component('todo-item',{ props: ['param','index'], template:'<li @click="handleClick">{{param}},下标{{index}}</li>', methods: { handleClick: function(vlue){ this.$emit('delete',this.index); //方法触发delete事件并传值 } } }); /*vue实例*/ new Vue({ el:"#root", //挂载点(dom) data: { inputVal: '', //input双向绑定的值 list:[] //list数组 }, methods: { handleSubmit: function(){ //按钮绑定的方法 this.list.push(this.inputVal); this.inputVal = '' }, handleDelete: function(index){ this.list.splice(index,1); } } }) </script>
1、父组件可以使用 props 把数据传给子组件。
2、子组件可以使用 $emit 触发父组件的自定义事件。
vm.$emit( event, arg ) //触发当前实例上的事件 vm.$on( event, fn );//监听event事件后运行fn;
vue单文件组件
安装单文件环境
安装 `npm`
`npm` 全称为 `Node Package Manager`,是一个基于`Node.js`的包管理器,也是整个`Node.js`社区最流行、支持的第三方模块最多的包管理器。
npm -v
由于网络原因 安装 `cnpm`
npm install -g cnpm --registry=https://registry.npm.taobao.org
安装 `vue-cli`
cnpm install -g @vue/cli
安装 `webpack`
`webpack` 是 `JavaScript` 打包器(module bundler)
cnpm install -g webpack
文件以.vue结尾的是
的 single-file components (单文件组件),用webstorm新建一个vue文件格式如下。
练习: 点击列表高亮显示,点击添加按钮把元素移动到另外一个列表
新建Info.vue文件
<template> <ul> <!--@click点击选中样式--> <!--:class选中样式,仅在current等于某个索引时且current不为空时生效--> <li v-for="(item,index) in lists" @click="choose(index)" :class="{active: index == current && current !== ''}" :key="index"> {{item}} </li> </ul> <button type="button" @click="add()">添加</button> <!--输出target--> <ul> <li v-for="(item,index) in target" :key="index">{{item}}</li> </ul> </template> <script> export default { name: 'Info', data () { return { current: '', lists: [1,2,3,4,5,6,7,8,9], target: [] } }, methods:{ //选中时改变current的值 choose (index){ this.current = index; console.info(index); }, //点击添加按钮时把当前选中值加到目标数组 add(){ if(this.current === ''){ //为空时不添加 return; } this.target.push(this.lists[this.current]); /*添加后清空*/ this.current = ''; } } } </script> <style scoped> /*选中的li加背景色*/ li.active{ background:green; } </style>
官方示例
<html> <head> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> window.onload=function (){ //声明式渲染 app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) //v-bind:title给标签动态绑定提示 app2 = new Vue({ el: '#app-2', data: { message: '页面加载于 ' + new Date().toLocaleString() } }) //v-if条件 app3 = new Vue({ el: '#app-3', data: { seen: true } }) //v-for循环 app4 = new Vue({ el: '#app-4', data: { todos: [ { text: '学习 JavaScript' }, { text: '学习 Vue' }, { text: '整个牛项目' } ] } }) //v-on:click点击事件 app5 = new Vue({ el: '#app-5', data: { message: 'Hello Vue.js!' }, methods: { reverseMessage: function () { this.message = this.message.split('').reverse().join('') } } }) //v-model双向绑定 app6 = new Vue({ el: '#app-6', data: { message: 'Hello Vue!' } }) } </script> </head> <body> <!--显示文本--> <div id="app">{{ message }}</div> <!--显示悬浮框--> <div id="app-2"> <span v-bind:title="message"> 鼠标悬停几秒钟查看此处动态绑定的提示信息! </span> </div> <!--条件--> <div id="app-3"> <p v-if="seen">现在你看到我了</p> </div> <!--循环--> <div id="app-4"> <ol> <li v-for="todo in todos"> {{ todo.text }} </li> </ol> </div> <!--点击事件--> <div id="app-5"> <p>{{ message }}</p> <button v-on:click="reverseMessage">逆转消息</button> </div> <!--表单输入和文本状态之间的双向绑定--> <div id="app-6"> <p>{{ message }}</p> <input v-model="message"> </div> </body> </html>
Vue-Router
https://router.vuejs.org/zh/
vue-cli的项目创建后添加Vue Router,但是会覆盖你的App.vue
vue add router
注册路由
用 Vue.js + Vue Router 创建单页应用
javascript
// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter) // 1. 定义(路由)组件。 // 可以.vue文件import进来 const Foo = { template: '<div>foo</div>' } const Bar = { template: '<div>bar</div>' } // 2. 定义路由 // 每个路由应该映射一个组件。 其中"component" 可以是 // 通过 Vue.extend() 创建的组件构造器, // 或者,只是一个组件配置对象。 // 我们晚点再讨论嵌套路由。 const routes = [ { path: '/foo', component: Foo }, { path: '/bar', component: Bar } ] // 3. 创建 router 实例,然后传 `routes` 配置 // 你还可以传别的配置参数, 不过先这么简单着吧。 const router = new VueRouter({ routes // (缩写) 相当于 routes: routes }) // 4. 创建和挂载根实例。 // 记得要通过 router 配置参数注入路由, // 从而让整个应用都有路由功能 const app = new Vue({ router }).$mount('#app') // 现在,应用已经启动了!
HTML
<script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> <div id="app"> <h1>Hello App!</h1> <p> <!-- 使用 router-link 组件来导航. --> <!-- 通过传入 `to` 属性指定链接. --> <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 --> <router-link to="/foo">Go to Foo</router-link> <router-link to="/bar">Go to Bar</router-link> </p> <!-- 路由出口 --> <!-- 路由匹配到的组件将渲染在这里 --> <router-view></router-view> </div>
或者在全局router.js里面注册好路由,然后在vue文件中使用<router-link to="/info">Info</router-link>的方式调用路由,<router-view/>展示组件内容。
模块中使用Vue Router
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter)
编程式导航
// 字符串 router.push('home') // 对象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user', params: { userId: '123' }}) // 带查询参数,变成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
Vue Router路由元信息
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, children: [ { path: 'bar', component: Bar, // a meta field meta: { requiresAuth: true } } ] } ] })
Vuex
state
就是Vue应用中需要使用的所有公共数据,在Vue通常放在应用的顶层组件上,通过父子组件通信的方式进行传递和修改。
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); //实例化一个vuex const store = new Vuex.Store({ state: { count: 0 } }); //通过this.$store.state.属性 访问vuex new Vue({ el: '#app', store, computed: { count () { return this.$store.state.count } } });
getters
getters可以认为,是store的计算属性。
mapGetters
辅助函数仅仅是将 store 中的 getter 映射到局部计算属性
const store = createStore({ state: { todos: [ { id: 1, text: '...', done: true }, { id: 2, text: '...', done: false } ] }, getters: { doneTodos: (state) => { return state.todos.filter(todo => todo.done) }, //通过属性访问 doneTodosCount (state, getters) { return getters.doneTodos.length }, //通过方法访问 getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id) } } }) //调用 this.$store.getters.doneTodosCount
mutation
const store = createStore({ state: { count: 1 }, mutations: { //Payload传对象参数 increment (state, payload) { state.count += payload.amount } } }) //调用 store.commit('increment', { amount: 10 })
action
Action与mutation基本相同,区别在以下两个方面:
- Action是通过提交mutation来改变state,而不是直接改变state
- Action可以执行异步操作,而mutation只能为同步操作
vue-cli
npm安装及配置
https://www.cnblogs.com/aeolian/p/12457284.html
安装
#安装vue-cli npm install --global vue-cli #或者 npm install -g @vue/cli
构建项目
命令构建
#cli方式(vue-cli3才有的命令),vuecli集成webpack vue create hello-world #基于webpack vue init webpack hello-world
UI构建
vue ui #vue-cli3才有
启动后浏览器自动打开。
运行
cd hello-world
npm run serve
npm run XXX,XXX是package.json中的scripts的内容。
webstorm可以右击package.json -》 show Package Scripts调出来命令窗口。
结构
index.html为首页,main.js为index中挂载点的实例,main.js中导入组件并使用组件。
main.js
import Vue from 'vue' import TodoList from './TodoList' /* index.html中挂载点的实例 */ new Vue({ el: '#app', /* index.html中的根结点 */ components: { App: TodoList }, /* 以APP标签使用引入的TodoList组件 */ template: '<App/>' })
TodoList.vue
<!--父组件--> <template> <div id="app"> <div> <input v-model="inputVal"/> <button @click="handleSubmit">提交</button> <!-- 通过提交事件的handleSubmit方法操作vue.$list数据,下面会自动显示list数据.(vue是数据驱动型,操作的是数据不是dom) --> <ul> <!--使用子组件,通过:绑定属性传值给子组件,通过@监听事件接收子组件传值--> <todo-item v-for="(item,index) of list" :content="item" :index="index" :key="index" @delete="handleDelete"> </todo-item> </ul> </div> </div> </template> <script> /* 引入子组件TodoItem组件 */ import TodoItem from './components/TodoItem' export default { components: { 'todo-item': TodoItem }, /* 引用导入的组件,声明通过todo-item标签的方式使用TodoItem */ name: 'App', data: function () { return { inputVal: '', list: [] } }, methods: { handleSubmit () { this.list.push(this.inputVal) this.inputVal = '' }, handleDelete (index) { /* 监听子组件触发的事件方法,并接收参数 */ this.list.splice(index, 1) /* 从index位置删除1个数据 */ } } } </script> <!--不加scope会变成全局--> <style scoped> #app { color: #2c3e50; } </style>
TodoItem.vue
<!--子组件--> <template> <!--监听li标签的单击事件,执行handleDelete方法--> <li @click="handleDelete">{{content}}</li> </template> <script> export default { props: ['content', 'index'], /* 通过属性接收父组件的数据 */ methods: { handleDelete () { this.$emit('delete', this.index) /* 触发父组件的delete监听事件,并传递参数index */ // alert(this.index) } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> </style>
浏览器调试工具vue-devtools
下载地址: https://github.com/vuejs/devtools/releases,下载发布版本
manifest.json并把json文件里的"persistent":false改成true
打开chrome浏览器,打开更多工具>扩展程序,添加解压文件夹;
重启浏览器