Logan 如果前面还有路,答应我,跑下去...

Vue.js小白入门

2018-01-16
Logan
VUE

实例化Vue对象

<div id="app1">
    <h1>{ { name } }</h1>
    <p>{ { job } }</p>
    <p>{ { sayHi("methods 方法") } }</p>
    <a :href="website">logan个人博客</a><br>
    <p v-html="websiteTag"></p> <br>
    <button @click = "greet">欢迎</button>
</div>

<script>
    var app1 = new Vue({ 
        el : "#app1",
        data : { 
            name : "logan",
            job : "fronted enginner",
            website : "http://logan70.github.io",
            websiteTag : "<a href='http://logan70.github.io'>v-html</a>"
         },
        methods : { 
            greet: function(){ 
                alert("Hello Vue!")
             },
            sayHi : function(txt){ 
                return "hello " + this.name + " ! " + txt
             }
         }
     })
</script>

事件及事件修饰符

  • .stop 阻止冒泡
  • .prevent 阻止默认行为
  • .capture 使用事件捕获模式,即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理
  • .self 只当在 event.target 是当前元素自身时触发处理函数,即事件不是从内部元素触发的
  • .once 事件将只会触发一次
<div id="app2">
    <h1>Event</h1>
    <p>I am { { age } } years old.</p>
    <button @click="addAge(1)">大一岁</button>
    <button @click="reduceAge(1)">小一岁</button>
    <button @dblclick="addAge(10)">双击大十岁</button>
    <button @dblclick="reduceAge(10)">双击小十岁</button>
    <div id="canvas" @mousemove="updateXY">{ { x } },{ { y } } - <span id="stopMoving" @mousemove.stop>Stop Moving</span></div>
    <a href="http://logan70.github.io" @click.prevent>logan个人博客</a>
</div>

<script>
    var app2 = new Vue({ 
        el : "#app2",
        data : { 
            age : 25,
            x : 0,
            y : 0
         },
        methods : { 
            addAge : function(num){ 
                this.age += num
             },
            reduceAge : function(num){ 
                this.age -= num
             },
            updateXY : function(event){ 
                this.x = event.offsetX;
                this.y = event.offsetY;
             }
         }
     })
</script>

键盘事件、按键修饰符及系统修饰键

全部的按键别名:

  • .enter
  • .tab
  • .delete (捕获“删除”和“退格”键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

系统修饰键

  • .ctrl
  • .alt
  • .shift
  • .meta

事件触发时修饰键必须处于按下状态

<div id="app3">
    <h1>键盘 Event</h1>
    <label for="">姓名:</label>
    <input type="text" @keyup="logName">
    <label for="">年龄:</label>
    <input type="text" @keyup.enter="logAge">
</div>

<script>
    var app3 = new Vue({ 
        el : "#app3",
        data : { 

         },
        methods : { 
            logName : function(){ 
                console.log("你正在输入名字")
             },
            logAge : function(){ 
                console.log("你正在输入年龄")
             }
         }
     })
</script>

双向数据绑定

<div id="app4">
    <h1>双向数据绑定</h1>
    <label for="">姓名:</label>
    <input type="text" @keyup="logName" ref="name" placeholder="edit me">
    <span>{ { name } }</span>
    <label for="">年龄:</label>
    <input type="text" v-model="age" placeholder="edit me">
    <span>{ { age } }</span>
</div>

<script>
    var app4 = new Vue({ 
        el : "#app4",
        data : { 
            name : "",
            age : ""
         },
        methods : { 
            logName : function(){ 
                this.name = this.$refs.name.value
                console.log("你正在输入名字")
             }
         }
     })
</script>

计算属性computed

  • computed 计算属性是基于它们的依赖进行缓存的。

  • methods 每当触发重新渲染时,调用方法将总会再次执行函数。

<div id="app5">
    <h1>计算属性 Computed</h1>
    <button @click="a++">Add to A</button>
    <button @click="b++">Add to B</button>
    <p>A - { { a } }</p>
    <p>B - { { b } }</p>
    <p>Age + A = { { AgeA } }</p>
    <p>Age + B = { { AgeB } }</p>
</div>

<script>
    var app5 = new Vue({ 
        el : "#app5",
        data : { 
            a : 0,
            b : 0,
            age : 35
         },
        computed : { 
            AgeA : function(){ 
                return this.age + this.a
             },
            AgeB : function(){ 
                return this.age + this.b
             }
         }
     })
</script>

Class 与 Style 绑定

<div id="app6">
    <h1>动态 CSS Class</h1>
    <h2 :class="{ color:changeColor, length:changeLength }" :style="styleObject" @click="changeColor=!changeColor">示例1</h2>
    <h2>示例2</h2>
</div>

<script>
    var app6 = new Vue({ 
        el : "#app6",
        data : { 
            changeColor : false,
            changeLength : false,
            styleObject : { 
                border : "1px solid #000"
             }
         }
     })
</script>

v-if 条件渲染

v-if 是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

v-show 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。

<div id="app7">
    <h1>v-if 条件</h1>

    <button @click="error = !error" >Toggle error</button>
    <button @click="success = !success">Toggle success</button>
    <button @click="isShow = !isShow">Toggle isShow</button>

    <p v-if="error">Now you can see me(v-if) (error = true)</p>
    <p v-else-if="success">Now you can see me(v-else-if) (success = true && error = false)</p>
    <p v-else>Now (error and success) = false</p>
    <p v-show="isShow">Now you can see me(v-show) (isShow = true)</p>
</div>

<script>
    var app7 = new Vue({ 
        el : "#app7",
        data : { 
            error : false,
            success : false,
            isShow: false
         }
     })
</script>

v-for 列表渲染

<div id="app8">
    <h1>{ { title } }</h1>

    <ul>
        <li v-for="character in characters">名字:{ { character } }</li>
    </ul>
    <ul>
        <li v-for="(user,index) in users">{ { index + 1 + "." } } 名字:{ { user.name } } &nbsp;&nbsp;年龄:{ { user.age } }</li>
    </ul>

    <template v-for="(user,index) in users">
        <p>{ { index + 1 } } . { { user.name } }</p>
        <p>{ { user.age } }</p>
    </template>
    
    <template v-for="user in users">
        <ul>
            <li v-for="(value,key,index) in user">{ { index } }-{ { key } }-{ { value } }</li>
        </ul>
    </template>
</div>

<script>
    var app8 = new Vue({ 
        el : "#app8",
        data : { 
            characters : ["logan","leo","nancy"],
            users : [
                { name:"henry",age:"25" },
                { name:"jack",age:"20" },
                { name:"tom",age:"23" }
            ],
            title : "v-for 循环"
         }
     })
</script>

实战DEMO

<!-- 根容器 -->
<div id="vue-app">
    <!-- 图片容器,根据ended的变化动态改变class -->
    <div id="bag" :class="{ broken: ended }"></div>
    <!-- 进度条容器,根据progress变化动态改变红条长度 -->
    <div id="progress">
        <div :style="{ width: progress + '%' }"></div>
    </div>
    <!-- 按钮组,点击减少/重置progress -->
    <div id="btn-group">
        <button @click="punch" v-show="!ended">可劲儿砸</button>
        <button @click="restart">重新开始</button>
    </div>
</div>
var vm = new Vue({ 
    el : "#vue-app",
    data : { 
        progress : 100,
        ended : false
     },
    methods : { 
        punch : function(){ 
            this.progress -= 10;
            if (this.progress <= 0) { 
                this.ended = true;
             }
         },
        restart : function(){ 
            this.progress = 100;
            this.ended = false;
         }
     }
 })

初始化多个Vue对象

<div id="app9">
    <h1>初始化多个Vue实例对象</h1>
    <button @click="changeTitle">改变v-for标题</button>
</div>

<script>
    var app9 = new Vue({ 
        el : "#app9",
        data : { 

         },
        methods : { 
            changeTitle :function(){ 
                app8.title = "已经改名了";
             }
         }
     })
</script>

初始Vue组件

<div id="app10">
        <greeting></greeting>
        <greeting></greeting>
</div>

<script>
    Vue.component("greeting",{ 
        template : `<p>
                        { { name } },初识Vue组件(模板)
                        <button @click="changeName">改名</button>
                    </p>`,
        data : function(){ 
            return { 
                name : "Logan"
             }
         },
        methods : { 
            changeName : function(){ 
                if (this.name == "Logan") { 
                    this.name = "Lee"
                 } else { 
                    this.name = "Logan";
                 }
             }
         }
     })

    var app10 = new Vue({ 
        el : "#app10"
     })
</script>

Vue - 搭建脚手架CLI

Vue-CLI 脚手架

  • 脚手架是通过webpack搭建的开发环境
  • 使用ES6语法
  • 打包和压缩js为一个文件
  • 项目文件在环境中编译,而不是浏览器
  • 实现页面自动刷新

搭建过程

# 全局安装 vue-cli
$ npm install --global vue-cli
# 创建一个基于 webpack 模板的新项目
$ vue init webpack my-project
# 安装依赖,走你
$ cd my-project
$ npm install
$ npm run dev

介绍SRC文件流程及根组件APP

  • assets文件夹:存放图片
  • components文件夹:存放组件
  • App.vue:根组件
  • main.js:
  • index.html:入口文件

index.html => main.js => App.vue => HelloWorld.vue

Vue 组件嵌套

全局注册嵌套

// 在main.js内
import Users from './components/Users'
    // 全局注册组件
Vue.component('users',Users)

局部注册嵌套

// 在App.vue内
<script>
    // 引入组件
import Users from './components/Users'

export default { 
  name: 'App',
  data(){ 
    return { 
      msg : '这是我的第一个Vue脚手架'
     }
   },
  // 注册组件,将只在父组件模板中可用
  components : { 
    users : Users
   }
 }
</script>

组件 CSS 作用域

<style scoped>

scoped表示限制CSS只在自身组件内起作用

不加scoped则各组件通用此组件的样式

实战DEMO2

App.vue

<!-- 1模板:html结构 -->
<template>
  <div id="app">
    <app-header></app-header>
    <users></users>
    <app-footer></app-footer>
  </div>
</template>

<!-- 2行为:处理逻辑 -->
<script>
import Users from './components/Users'
import Header from './components/Header'
import Footer from './components/Footer'

export default { 
  name: 'App',
  data(){ 
    return { 
      msg : '这是我的第一个Vue脚手架'
     }
   },
  components : { 
    'users' : Users,
    'app-header' : Header,
    'app-footer' : Footer
   }
 }
</script>

Users.vue

<template>
  <div class="users">
    <ul>
        <li v-for="user in users" @click="user.show = !user.show">
            <h2>{ { user.name } }</h2>
            <h3 v-show="user.show">{ { user.position } }</h3>
        </li>
    </ul>
  </div>
</template>

<style scoped>
.users{ 
    width: 100%;
    max-width: 1200px;
    margin: 40px auto;
 }
ul{ 
    padding: 0;
    display: flex;
    flex-wrap: wrap;
 }
li{ 
    flex-grow: 1;
    flex-basis: 200px;
    padding: 40px 0;
    margin: 20px;
    border: 1px solid #222;
    box-sizing: border-box;
    text-align: center;
    list-style: none;
 }
</style>

属性传值Props(父To子)

  • 先在父组件内定义要传的值
data(){ 
    return { 
      users : [
        { name : 'Logan', position : 'Fronted Enginner', show : false },
        { name : 'Logan', position : 'Fronted Enginner', show : false },
        { name : 'Logan', position : 'Fronted Enginner', show : false },
        { name : 'Logan', position : 'Fronted Enginner', show : false },
        { name : 'Logan', position : 'Fronted Enginner', show : false },
        { name : 'Logan', position : 'Fronted Enginner', show : false },
        { name : 'Logan', position : 'Fronted Enginner', show : false },
        { name : 'Logan', position : 'Fronted Enginner', show : false },
        { name : 'Logan', position : 'Fronted Enginner', show : false },
        { name : 'Logan', position : 'Fronted Enginner', show : false },
        { name : 'Logan', position : 'Fronted Enginner', show : false }
      ]
     }
 },      
  • 在父组件内插入子组件的地方传入值
<template>
  <div id="app">
    <app-header></app-header>
    <users :users="users"></users>
    <app-footer></app-footer>
  </div>
</template>
  • 在子组件内通过props传值
export default { 
  name: 'users',
  props : ['users'],
  data: function(){ 
    return { 
        
     }
   }
 }
  • prop验证(推荐写法)
export default { 
  name: 'users',
  props : { 
    users : { 
        type : Array,
        required : true
     }
   },
  data: function(){ 
    return { 
        
     }
   }
 }

传值和传引用

传值:(Number,String,Boolean),在子组件内对其进行改变时,其他组件内不会发生变化

传引用:(Array,Object),在子组件内对其进行改变时,其他组件内会发生变化

不应该在子组件内部改变 prop。正确做法是

  • Prop 作为初始值传入后,子组件想把它当作局部数据来用
// 定义一个局部变量,并用 prop 的值初始化它:
props: ['initialCounter'],
data: function () { 
  return {  counter: this.initialCounter  }
 }
  • rop 作为原始数据传入,由子组件处理成其它数据输出。
// 定义一个计算属性,处理 prop 的值并返回:
props: ['size'],
computed: { 
  normalizedSize: function () { 
    return this.size.trim().toLowerCase()
   }
 }

事件传值(子To父)

  • 第一步:在子组件内触发事件
<template>
  <header>
    <h1 @click="changeTitle">{ { tittle1 } } { { title } }</h1>
  </header>
</template>

methods : { 
    changeTitle : function(){ 
        // 在子组件内触发事件
        this.$emit('titleChanged','通过事件子传父')
     }
 }
  • 第二步:在父组件内接受事件及参数
<template>
  <div id="app">
    <!-- 在父组件内接受事件及参数 -->
    <app-header :title="title" @titleChanged="changeTitleFn($event)"></app-header>
    <users :users="users"></users>
    <app-footer :title="title"></app-footer>
  </div>
</template>
  • 第三步:在父组件内定义事件函数
methods : { 
  changeTitleFn : function(title){ 
    this.title = title
   }
 }

生命周期(钩子函数)

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/vue/2.1.3/vue.js"></script>
</head>
<body>

<div id="app">
     <p>{ {  message  } }</p>
</div>

<script type="text/javascript">
    
  var app = new Vue({ 
      el: '#app',
      data: { 
          message : "xuxiao is boy" 
       },
       beforeCreate: function () { 
                console.group('beforeCreate 创建前状态===============》');
               console.log("%c%s", "color:red" , "el     : " + this.$el); //undefined
               console.log("%c%s", "color:red","data   : " + this.$data); //undefined 
               console.log("%c%s", "color:red","message: " + this.message)  
         },
        created: function () { 
            console.group('created 创建完毕状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el); //undefined
               console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化 
               console.log("%c%s", "color:red","message: " + this.message); //已被初始化
         },
        beforeMount: function () { 
            console.group('beforeMount 挂载前状态===============》');
            console.log("%c%s", "color:red","el     : " + (this.$el)); //已被初始化
            console.log(this.$el);
               console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化  
               console.log("%c%s", "color:red","message: " + this.message); //已被初始化  
         },
        mounted: function () { 
            console.group('mounted 挂载结束状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el); //已被初始化
            console.log(this.$el);    
               console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化
               console.log("%c%s", "color:red","message: " + this.message); //已被初始化 
         },
        beforeUpdate: function () { 
            console.group('beforeUpdate 更新前状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);   
               console.log("%c%s", "color:red","data   : " + this.$data); 
               console.log("%c%s", "color:red","message: " + this.message); 
         },
        updated: function () { 
            console.group('updated 更新完成状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el); 
               console.log("%c%s", "color:red","data   : " + this.$data); 
               console.log("%c%s", "color:red","message: " + this.message); 
         },
        beforeDestroy: function () { 
            console.group('beforeDestroy 销毁前状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);    
               console.log("%c%s", "color:red","data   : " + this.$data); 
               console.log("%c%s", "color:red","message: " + this.message); 
         },
        destroyed: function () { 
            console.group('destroyed 销毁完成状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);  
               console.log("%c%s", "color:red","data   : " + this.$data); 
               console.log("%c%s", "color:red","message: " + this.message)
         }
     })
</script>
</body>
</html>

create 和 mounted 相关

咱们在chrome浏览器里打开,F12看console就能发现

  • beforecreated:el 和 data 并未初始化
  • created:完成了 data 数据的初始化,el没有
  • beforeMount:完成了 el 和 data 初始化
  • mounted :完成挂载

beforeMount阶段el还是 { { message } },这里就是应用的 Virtual DOM(虚拟Dom)技术,先把坑占住了。到后面mounted挂载的时候再把值渲染进去。

mounted内的方法执行完后页面显示

update 相关

数据发生改变时,将会触发update的操作。

updated内的方法执行完后更新内容显示

destroy 相关

执行了destroy操作,原先生成的dom元素还存在,但是后续DOM就不再受vue控制了。

路由和HTTP

路由

1.路由的安装

npm install vue-router

2.在main.js中安装路由功能

import VueRouter from 'vue-router'

Vue.use(vueRouter)

3.配置路由

const router = new VueRouter({ 
    routes : [
        { path:'/',component:Home }
        { path:'/helloworld',component:HelloWorld }
    ]
 })

4.引入组件

import HelloWorld from './comonents/HelloWorld'
import Home from './comonents/Home'

5.创建挂载根实例

/* eslint-disable no-new */
new Vue({ 
  router,
  el: '#app',
  components: {  App  },
  template: '<App/>'
 })

6.添加html结构

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

7.去除路径中#号

在main.js中router实例中配置

const router = new VueRouter({ 
    routes : [
        { path:'/',component:Home },
        { path:'/helloworld',component:HelloWorld }
    ],
    mode : 'history'
 })

8.加入<router-link>导航

<template>
  <div id="app">
    <ul>
      <li><router-link to="/">Home</router-link></li>
      <li><router-link to="/helloworld">Hello</router-link></li>
    </ul>
    <router-view></router-view>
  </div>
</template>

http

使用vue-resource

1.安装vue-resource

npm install vue-resource --save-dev

2.在main.js中安装

import VueResource from 'vue-resource'

Vue.use(VueResource)

3. Home.vue中添加created钩子函数 请求http

created(){ 
  this.$http.get('http://jsonplaceholder.typicode.com/users').then((data) => { 
    // console.log(data)
    this.users = data.body
   })
 }

4.在user.vue中添加html结构

<template>
  <div class="users">
    <ul>
        <li v-for="user in users" >
            <h2>{ { user.name } }</h2>
            <h3>{ { user.email } }</h3>
        </li>
    </ul>
  </div>
</template>

下一篇 MVC、MVP、MVVM

留言

目录