生命周期
1.npm安装:
(1)安装vue:npm install vue
(2)安装vue-cli:npm install -g vue-cli
(3)创建基于webpack新项目my-project:vue init webpack my-project
(4)进入项目,安装运行:cd my-project
npm install
npm run dev
2.Vue组件包含三个模板:
template:视图
script:逻辑
style:样式
3.vue基本指令:
Mustache语法:{{}}:用于js单行语句,且不适用于html属性
v-html:渲染html
v-text:渲染文本
v-bind:绑定属性值
4.条件渲染:
v-if:<p v-if="seen">我可以显示或隐藏</p>
v-if,v-else
v-if,v-else-if
v-show
v-if与v-show区别:v-if为false元素根本不加载,v-show为false元素加载但是display:none。
如果频繁的切换则用v-show,条件很少改变则用v-if
5.循环:
v-for:每个列表最好添加key,给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素。
(1)对与数组中的对象:list:[
{name:'John',age:12},
{name:'Amy',age:12},
{name:'vskd',age:12}
];
有两个参数(数据,索引):<li v-for="(person,index) in list" v-bind:key="index">{{person.name}}:{{index}}</li>
(2)对于对象:object: {
firstName: 'John',
lastName: 'Doe',
age: 30
}
有三个参数(值,键名,索引):<li v-for="(item,name,index) in object">{{person.name}}:{{index}}</li>
6.事件监听:v-on
v-on:click="btnChange"
7.创建组件:
(1)在components文件夹中创建Events.vue文件:
<template>
<!-- template中只能存在一个根组件 -->
<div id="events">
<p>{{msg}}</p>
</div>
</template>
<script>
export default {
data() {
return {
msg:'信息'
}
}
}
</script>
<style>
</style>
(2)在App.vue的script中导入组件:
import Events from './components/Events';
export default {
name: 'App',
components:{
Events
}
}
(3)在App.vue的template中加载组件:
<template>
<div id="app">
<Events />
</div>
</template>
8.数组更新检测:
(1)变异方法,都是改变原数组,所以能响应更新:push(),pop(),shift(),unshift(),splice(),sort(),reverse()
(2)替换数组,都是生成新数组,所以不能响应更新:filter(), concat() 和 slice()
filter():对数组进行过滤。lists.filter(function(item){return item >= 10;});
9.计算属性:
计算属性computed会有缓存,没有改变时直接使用上次的计算结果,而methods里的函数每次都会重新计算。
computed中的方法调用时不需要加括号,methods中的需要括号
10.v-model:
v-model.lazy:失去焦点后才会反应
v-model.number:将输入值转为数值
v-model.trim:自动去除首尾空白
11.组件内容:
template:只能有一个根元素
script:需导出组件export default {...}
style:添加scoped 属性是表示样式只作用于当前组件
12.子父级交互:
父 ->子:props
子 -> 父:emit Event
13.插槽:slot:子组件给父组件传递数据
(1)子组件: 在想插入html 的地方加上<slot></slot>标签,可以使用name属性设置名字来区分
<header>
<slot name="header"></slot>
</header>
<main>
<slot>我是默认插槽</slot>
</main>
<footer>
<slot name="footer"></slot>
<slot name="test">我是test插槽</slot>
<slot name="msgTest"></slot>
</footer>
<header>
<slot name="header"></slot>
</header>
<main>
<slot>我是默认插槽</slot>
</main>
<footer>
<slot name="footer"></slot>
<slot name="test">我是test插槽</slot>
<slot name="msgTest"></slot>
</footer>
父组件:在将插到子组件的内容最外层标签中加上slot属性且值为子组件设置的name属性值
<template slot="header">
<h4>我是header</h4>
</template>
<template>
<h4>我是main</h4>
</template>
<template slot="footer">
<h4>我是footer</h4>
<p slot="test">我是test插槽覆盖物</p>
<p slot="msgTest">{{msg}}</p>
</template>
<template>
<h4>我是main</h4>
</template>
<template slot="footer">
<h4>我是footer</h4>
<p slot="test">我是test插槽覆盖物</p>
<p slot="msgTest">{{msg}}</p>
</template>
(2)子组件给父组件传递数据
子组件:
<div>
<slot name="s1" text="我是传递给父组件的数据"></slot>
</div>
text="我是传递给父组件的数据"></slot>
</div>
父组件:
<div slot="s1" slot-scope="jie">
<p>{{jie.text}}</p>
</div>
slot-scope="jie">
<p>{{jie.text}}</p>
</div>
14.动态组件切换:
<template>
<div class="active">
<h3>active</h3>
<button @click="changeView1">菜单1</button>
<button @click="changeView2">菜单2</button>
<keep-alive> <compont :is="currentView"></compont> </keep-alive> //存放组件的地方 //keep-alive是缓存失活的组件
</div>
</template>
<script type="text/javascript">
import Fu from './AFu.vue'
import BSlot from './BSlot.vue'
export default {
data() {
return {
currentView:"BSlot"
}
},
components:{
Fu,
BSlot
},
methods:{
changeView1:function() {
this.currentView = "BSlot";
},
changeView2:function() {
this.currentView = "Fu";
}
}
}
</script>
<style type="text/css"></style>
<keep-alive> <compont :is="currentView"></compont> </keep-alive> //存放组件的地方 //keep-alive是缓存失活的组件
</div>
</template>
<script type="text/javascript">
import Fu from './AFu.vue'
import BSlot from './BSlot.vue'
export default {
data() {
return {
currentView:"BSlot"
}
},
components:{
Fu,
BSlot
},
methods:{
changeView1:function() {
this.currentView = "BSlot";
},
changeView2:function() {
this.currentView = "Fu";
}
}
}
</script>
<style type="text/css"></style>
15.自定义指令:
<template>
<div class="active">
<input type="text" name="" v-myfocus>
<p v-mycss>会上讲话精神</p>
</div>
</template>
<script type="text/javascript">
export default {
data() {
return {
}
},
directives:{
myfocus: {
inserted:function(el) {
el.focus();
}
},
mycss:{ bind:function(el,binding,vnode) {
el.style.background="yellow";
},
inserted:function(el) {
el.style.color="red";
}
}
}
}
</script>
<style type="text/css"></style>
v-myfocus>
<p v-mycss>会上讲话精神</p>
</div>
</template>
<script type="text/javascript">
export default {
data() {
return {
}
},
directives:{
myfocus: {
inserted:function(el) {
el.focus();
}
},
mycss:{ bind:function(el,binding,vnode) {
el.style.background="yellow";
},
inserted:function(el) {
el.style.color="red";
}
}
}
}
</script>
<style type="text/css"></style>
16.过滤器:
用于文本格式化,例如:¥10,ajax获取到10后过滤成¥10
<template>
<div class="active">
<h3>过滤器:文本格式化</h3>
<p>{{price | moneyChange }}</p>
</div>
</template>
<script type="text/javascript">
export default {
data() {
return {
price:10
}
},
filters:{
moneyChange:function(value) {
return value = '¥' + value;
}
}
}
</script>
<style type="text/css"></style>
{{price | moneyChange }}</p>
</div>
</template>
<script type="text/javascript">
export default {
data() {
return {
price:10
}
},
filters:{
moneyChange:function(value) {
return value = '¥' + value;
}
}
}
</script>
<style type="text/css"></style>
17.axios
(1)安装:npm install axio
(2)在main.js中 :
import Axios from 'axios'
Vue.prototype.$axios = Axios;
(3)在组件(如:HelloWorld.vue)中就可以使用:
this.$axios.get(url)
18.axios跨域访问:(此方法仅用于测试环境,不用于生产环境,生产环境中跨域问题由后端解决)
(1)项目中的config/index.js中的proxyTable添加:
proxyTable: {
"/api": {
target:"http://localhost:80", //target中写入需要访问的域名
changeOrigin:true,
pathRewrite:{
'^/api':'/api'
}
}
},
(2)在main.js中:设置HOST,指向index中的“/api”
Vue.prototype.HOST = '/api'
(3)使用:在组件中:
<template>
<div class="hello">
<div class="qw">{{msg}}</div>
<ul>
<li v-for="item in msg">{{ item.username }} - {{ item.psw }} - {{ item.age }} </li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: ''
}
},
created: function() {
var url = this.HOST + '/mypro1';
// this.$axios.get("http://localhost:80/mypro1")
this.$axios.get(url)
.then(res => {
console.log(res.data);
this.msg = res.data;
})
.catch(error => {
console.log(error);
})
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
background: yellow;
}
a {
color: #42b983;
}
</style>
var url = this.HOST + '/mypro1';
// this.$axios.get("http://localhost:80/mypro1")
this.$axios.get(url)
.then(res => {
console.log(res.data);
this.msg = res.data;
})
.catch(error => {
console.log(error);
})
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
background: yellow;
}
a {
color: #42b983;
}
</style>
(4)跨域访问:豆瓣电影:
豆瓣开发者官网查找所需的接口:如豆瓣电影top250的接口:http://api.douban.com/v2/movie/top250
在config/index.js中设置
proxyTable: {
"/api": {
target:"http://api.douban.com/v2",//豆瓣
changeOrigin:true,
pathRewrite:{
'^/api':''
}
}
},
创建新组件Douban.vue:
<template>
<div class="douban">
<ul>
<li v-for="film in films">
<img :src="film.images.small">
<div class="right">
<p class="title">{{ film.title}}</p>
<p>{{ film.original_title}}</p>
<p>{{ film.year}}</p>
<p>{{ film.subtype}} </p>
<p><span v-for="genre in film.genres">{{genre}},</span></p>
<p>{{ film.id}}</p>
</div>
</li>
</ul>
</div>
</template>
<script type="text/javascript">
export default {
data() {
return {
films:''
}
},
created:function() {
var url = this.HOST + '/movie/top250';
console.log(url);
this.$axios.get(url)
.then(res => {
console.log(res);
this.films = res.data.subjects;
})
.catch(error => {
console.log(error);
})
}
}
</script>
<style type="text/css">
ul {
list-style: none;
margin: 0;
padding:0;
}
li {
width: 600px;
height: 400px;
display: inline-block;
border: 2px solid #ccc;
padding: 20px;
text-align: left;
margin: 20px;
}
img {
vertical-align: top;
}
.right {
display: inline-block;
margin-left: 10px;
}
.title {
font-size: 30px;
font-weight: bold;
}
</style>
效果图如下:
19.mockjs使用:
(1)安装:npm install mockjs
(2)使用:(在组件中):
<template>
<div class="mock">
msg:{{ msg }}
</div>
</template>
<script type="text/javascript">
export default {
data() {
return {
msg:''
}
},
created() {
var Mock = require('mockjs')
var data = Mock.mock({
'list|1-10.2-3':1
})
// 输出结果
console.log(JSON.stringify(data, null, 4))
var res = data; //JSON.stringify(data, null, 4);
this.msg = res.list;
console.log(this.msg);
}
}
</script>
<style type="text/css">
</style>
20.路由:
在router/index.js中:载入要设置路由的组件,设置路由地址:
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Logo from '@/components/BLogo'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path:'/logo',
name:'logo',
component: Logo
}
]
})
在父组件中引用路由<router-link to="/"></router-link>
<template>
<div class="navlist">
<ul>
<li>
<router-link to="/">Hello</router-link>
<router-link to="/logo">logo</router-link>
</li>
</ul>
</div>
</template>
21.嵌套路由:
(1)在router/index.js中:
import Vue from 'vue'
import Router from 'vue-router'
import Index from '@/components/page/Index'
import Wall from '@/components/third/Wall'
import Cj from '@/components/third/Cj'
import Jb from '@/components/third/Jb'
import Tp from '@/components/third/Tp'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Index',
component: Index,
redirect:"/Wall", //重定向:设置默认显示哪页
children:[ //index中的子路由
{
path:"Wall",
name:"Wall",
component:Wall
},
{
path:"Cj",
name:"Cj",
component:Cj
},
{
path:"Jb",
name:"Jb",
component:Jb
},
{
path:"Tp",
name:"Tp",
component:Tp
}
]
}
]
})
(2)index.vue中依旧使用<router-link to=""></router-link>标签指示路由
<template>
<div class="index">
<ul>
<li><router-link to="Wall">上墙</router-link></li>
<li><router-link to="Tp">投票</router-link></li>
<li><router-link to="Cj">抽奖</router-link></li>
<li><router-link to="Jb">机霸</router-link></li>
</ul>
<div class="right">
<router-view></router-view>
</div>
</div>
</template>
22.vuex
作用:管理共享状态(当组件之间没有关系又想引用共同的数据时使用,但它附带了更多的概念和框架,如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的)
(1)安装:npm install vuex --save-dev
(2)在src文件夹中创建store文件夹 => index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 创建store仓库
export default new Vuex.Store({
state:{
count:10
}, //state设置数据
mutations:{
increment(state) {
state.count ++;
},
descrement(state) {
state.count --;
}
}, //mutations:修改数据,使用时用commit
actions:{
increment(context) { //context:承上启下
context.commit("increment");
},
descrement(context) {
context.commit("descrement");
}
}, //与mutations作用基本一致,都是修改数据,一般用于异步
getters:{
getState(state) {
return state.count > 0 ? state.count : 0
}
} //getters对count数据进行限制
})
(3)在main.js中引入store.js,要在vue实例中引入store
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
(4)组件中使用:
<template> <div class="hello"> <p>{{getCount}}</p> <button @click="incre">自增</button> <button @click="desc">自减</button> </div> </template> <script> export default { name: 'HelloWorld', data () { return { msg: '' } }, computed:{ getCount() { // return this.$store.state.count; //直接调用state中的count return this.$store.getters.getState; //调用getters中getState处理过后返回的数据 } }, methods:{ incre:function() { // this.$store.commit('increment'); //mutations用commit
this.$store.dispatch('increment'); //actions用dispatch }, desc:function() { // this.$store.commit('descrement'); this.$store.dispatch('descrement'); } }} </script>
(5)组件中获取并使用state的三种方式
- 直接在模板中使用this.$store.state.count
- 在计算属性中将this.$store.state.count赋值给组件中的变量
- 使用mapState简洁的将this.$store.state.count赋值给组件中的变量
<template> <div> <p>this.$store.state:{{this.$store.state.count}}</p> <p>computed中将this.$store.state.count赋值给count1:{{count1}}</p> <p>mapState:{{count}}</p> </div> </template> <script type="text/javascript"> import {mapState} from 'vuex'; export default { data() { return { } }, computed: { count1(){ return this.$store.state.count }, ...mapState({ count:state=>state.count }) } } </script>
(6) 组件中修改状态
- 直接在组件方法中调用修改状态
- 将修改方法赋值给组件中的方法
<template> <div> <p>mapState:{{count}}</p> <button @click="add1">直接在组件方法中调用修改状态</button> <button @click="add2">将修改方法赋值给组件中的方法(对象形式)</button> <button @click="add">将修改方法赋值给组件中的方法(数组形式)</button> </div> </template> <script type="text/javascript"> import {mapState, mapMutations} from 'vuex'; export default { data() { return { } }, computed: { ...mapState({ count:state=>state.count }) }, methods:{ // 直接在组件方法中调用修改状态 add1() { this.$store.commit('add'); }, // 将修改方法赋值给组件中的方法(参数可为对象亦可为数组) ...mapMutations({ add2: 'add' // 组件中方法: mutations中方法 }), ...mapMutations(['add', 'reduce']) } } </script>
(7)组件中获取Getter的三种方式
- 通过this.$store.getter.newCount属性获取
- 通过this.$store.getter.newCount方法获取
- 通过mapGetters获取
<template> <div> <p>mapState:{{count}}</p> <p>通过this.$store.getter.newCount属性获取:{{this.$store.getters.newCount}}</p> <p>通过this.$store.getter.newCount方法获取:{{this.$store.getters.newCount1(10000)}}</p> <p>通过mapGetters获取:{{newCount}}, {{newCount1(10000)}}</p> <button @click="add">将修改方法赋值给组件中的方法(数组形式)</button> </div> </template> <script type="text/javascript"> import {mapState, mapMutations, mapGetters} from 'vuex'; export default { data() { return { } }, computed: { ...mapState({ count:state=>state.count }), ...mapGetters(['newCount', 'newCount1']) }, methods:{ ...mapMutations(['add', 'reduce']) } } </script>