2, vuejs-进阶

简单示例

  • html
<div id="app">
    <button-counter></button-counter>
    <button-counter></button-counter>
    <button-counter></button-counter>
</div>
  • js
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  methods:{
    add(){
        this.count++;
    }
  },
  template: '<button @click="add">You clicked me {{ count }} times.</button>'
})

var vm = new Vue({
    el: '#app',
    data: {
    }
});

注意: data必须是一个函数, 返回对象, 而不是之前的对象

vue生命周期

0hbvM8.png
0hLn6f.jpg

组件的创建

方式一-直接定义注册

Vue.component('my-component-name', { /* ... */ })

方式二-定义成对象

var compA =  {
    template: `<lable><slot></slot></lable>`
}

var vm = new Vue({
    el: '#app',
    components:{
       'my-span':compA
    },
    data: {
        mytext:"hello world!!!",
    }
});

方式三-模板文件

  • html
<body>
    <div id="app">
        <my-span :msg="msg"></my-span>
    </div>
   
</body>

<template id="tp1">
    <a>{{msg}}</a>
</template>
  • js
Vue.component("my-span",{
    props:['msg'],
    template:'#tp1'
});

var vm = new Vue({
    el:'#app',
    data:{
        msg:'hello world!!!'
    }
});

组件注册

组件名

推荐使用kebab-case, 多个单词用 - 隔开

​ Vue.component('my-component-name', { /* ... */ })

全局注册

Vue.component('my-component-name', {
  // ... 选项 ...
})

这些组件是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中。

局部注册

  • html
<div id="app">
  <my-span>{{mytext}}</my-span>
  <my-lable>{{mytext}}</my-lable>
</div>

  • js
var compA =  {
    props: ['value'],
    template: `<span><slot></slot></span>`
}

var compB =  {
    props: ['value'],
    template: `<lable><slot></slot></lable>`
}

var vm = new Vue({
    el: '#app',
    components:{
       'my-span':compA
    },
    data: {
        mytext:"hello world!!!",
    }
});

由于compB没有注册时vue中, 所以页面上没有正确显示

0R7G9S.jpg

通过prop向子组件专递数据

  • html
<div id="app">
    <blog-tags title="java"></blog-tags>
    <blog-tags title="php"></blog-tags>
    <blog-tags title="android"></blog-tags>
</div>
  • js
Vue.component('blog-tags', {
    props: ['title'],
    template: '<h3>{{ title }}</h3>'
})

var vm = new Vue({
    el: '#app',
    data: {
    }
});

单个根元素

由prop接收属性数据变为接收一个对象

  • html
<div id="app">
    <blog-tags v-for="tag in tags" :key="tag.id" :detail="tag"></blog-tags>
</div>
  • js
Vue.component('blog-tags', {
    props: ['detail'],
    template: '<div><h3>{{detail.title}}</h3><br/><div>{{detail.info}}</div></div>'
})

var vm = new Vue({
    el: '#app',
    data: {
        tags:[
            {id:1,title:'java',info:'good language'},
            {id:2,title:'php',info:'best good language'},
            {id:3,title:'js',info:'populate language'}
        ]
    }
});

监听子组件

简单来说: 通过$emit来绑定一个事件, 当事件触发时, 会传给外部组件 (不一定正确, 但这样理解起来方便)

  • html
<div id="app" >
    <div :style="{fontSize: fontsize+'px'}">
    	<blog-tags v-for="tag in tags" :key="tag.id" :detail="tag" v-on:enlarge-text='fontsize++'></blog-tags>
	</div>
</div>
  • js
Vue.component('blog-tags', {
    props: ['detail'],
    template: '<div><span>{{detail.title}}</span><button v-on:click="$emit(\'enlarge-text\')">点我放大</button></div>'
})

var vm = new Vue({
    el: '#app',
    data: {
        fontsize:10,
        tags:[
            {id:1,title:'java',info:'good language'},
            {id:2,title:'php',info:'best good language'},
            {id:3,title:'js',info:'populate language'}
        ]
    }
});

抛出一个值

  • html
<div id="app">
    <div :style="{fontSize: fontsize+'px'}">
        <blog-tags v-for="tag in tags" :key="tag.id" :detail="tag" v-on:enlarge-text='plustext'></blog-tags>
    </div>
</div>
  • js
Vue.component('blog-tags', {
    props: ['detail'],
    template: '<div><span>{{detail.title}}</span><button v-on:click="$emit(\'enlarge-text\', 10)">点我放大</button></div>'
})

var vm = new Vue({
    el: '#app',
    data: {
        fontsize:10,
        tags:[
            {id:1,title:'java',info:'good language'},
            {id:2,title:'php',info:'best good language'},
            {id:3,title:'js',info:'populate language'}
        ]
    },
    methods:{
        plustext:function(size){
            this.fontsize += size;
        }
    }
});

在组件上使用v-model

  • html
<div id="app">
   <my-input v-model="input"></my-input> 
   <span>input:{{input}}</span>
</div>
  • js
Vue.component('my-input', {
    props: ['value'],
    template: `<input type="text"  v-bind:value="value" v-on:input="$emit('input', $event.target.value)">`
})

var vm = new Vue({
    el: '#app',
    data: {
        input:"hello world!!!",
    }
});

通过插槽分发内容

简单点来说: 自定义内容, 那我们自定义的标签自定义内容, 我们如何显示我们自定义的内容

通过在组件中添加 ****来显示

  • html
<div id="app">
  <my-span>{{mytext}}</my-span>
</div>
  • js
Vue.component('my-span', {
    props: ['value'],
    template: `<span><slot></slot></span>`
})

var vm = new Vue({
    el: '#app',
    data: {
        mytext:"hello world!!!",
    }
});

vue-resource实现网络请求

  • 引入
 <script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>

get请求

  • html
<div id="app">
    <button value="get请求" @click="get">get请求</button>
</div>
  • js
var vm = new Vue({
    el:'#app',
    data:{
        msg:''
    },
    methods:{
        get(){
            this.$http.get("http://httpbin.org/get").then(
                function(result){
                    console.log(result.body);
                },
                function(error){
					console.log(error.body);
                }
            )
        }
    }
});

post请求

  • html
<div id="app">
    <button value="get请求" @click="postJson">post json请求</button>
    <button value="get请求" @click="postForm">post 表单请求</button>
</div>
  • js
var vm = new Vue({
    el:'#app',
    data:{
        msg:''
    },
    methods:{
        postJson(){
            this.$http.post("http://httpbin.org/post", {'a':'b'}).then(
                function(result){
                    console.log(result.body);
                },
                function(error){
                    console.log(error.body);
                }
            )
        },
        postForm(){
            this.$http.post("http://httpbin.org/post", {'a':'b'},{emulateJSON:true}).then(
                function(result){
                    console.log(result.body);
                },
                function(error){
                    console.log(error.body);
                }
            )
        }
    }
});

jsonp请求

  • html
<div id="app">
    <button value="get请求" @click="jsonp">jsonp请求</button>
</div>
  • js
var vm = new Vue({
    el:'#app',
    data:{
        msg:''
    },
    methods:{
        jsonp(){
            this.$http.jsonp("https://www.baidu.com/sugrec?ie=utf-8&prod=pc&from=pc_web&wd=tomcat").then(
                function(result){
                    console.log(result.body);
                },
                function(error){
                    console.log(error.body);
                }
            )
        }
    }
});

配置

域名配置

  • html
<div id="app">
    <button value="get请求" @click="postJson">post json请求</button>
    <button value="get请求" @click="postForm">post 表单请求</button>
</div>
  • js
// 方式一
// Vue.http.options.root='http://httpbin.org/';

var vm = new Vue({
    el:'#app',
    // 方式二
    http:{
        root:'http://httpbin.org/',
        headers:{
            'a':'b'
        }
    },
    data:{
        msg:''
    },
    methods:{
        postJson(){
            this.$http.post("post", {'a':'b'}).then(
                function(result){
                    console.log(result.body);
                },
                function(error){
                    console.log(error.body);
                }
            )
        },
        postForm(){
            this.$http.post("post", {'a':'b'},{emulateJSON:true}).then(
                function(result){
                    console.log(result.body);
                },
                function(error){
                    console.log(error.body);
                }
            )
        }
    }
});

全局启用emulateJSON

  • js
Vue.http.options.emulateJSON=true;

http:{
    root:'http://httpbin.org/',
    emulateJSON:true,
    headers:{
    	'a':'b'
    }
},

过滤器

全局定义

  • html
<div id="app">
    <span>{{date|reverse}}</span>
</div>
  • js
Vue.filter('reverse', function (value) {
    if (!value) return ''
    let re = value.toString().split('').reverse().join('');
    console.log(re);
    return re;
})

var vm = new Vue({
    el: '#app',
    data: {
        date: 1602640485294
    }
});

局部定义

  • html
<div id="app">
    <span>{{date|capitalize|reverse}}</span>
</div>
  • js
var vm = new Vue({
    el: '#app',
    data: {
        date: 'abcdefg'
    },
    filters: {
        reverse(value) {
            if (!value) return ''
            // 倒叙
            let re = value.toString().split('').reverse().join('');
            console.log(re);
            return re;
        },
        capitalize: function (value) {
            if (!value) return ''
            value = value.toString()
            // 首字母大写
            return value.charAt(0).toUpperCase() + value.slice(1)
        }
    }
});

vue动画

0I5YfP.jpg

入门

  • style
<style>
    .fade-enter,.fade-leave-to {
        opacity: 0;
        transform: translateX(150px);
    }
    .fade-enter-active,.fade-leave-active {
        transition: all 2s ease;
    }
</style>
  • html
<div id="app">
    <button @click="flag=!flag">点我</button>
    <transition name="fade" mode="out-in">
        <h3 v-show="flag">hello world!!!</h3>
    </transition>
</div>
  • js
var vm = new Vue({
    el:'#app',
    data:{
        flag:false
    },
    methods:{
    }
});

使用第三方类animate实现动画

  • style
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
  • html
<div id="app">
    <button @click="flag=!flag">点我</button>
    <transition enter-active-class="animate__animated animate__backInDown" 
        leave-active-class="animate__animated animate__backOutDown" :duration="{ enter: 600, leave: 800 }">
        <h3 v-show="flag">hello world!!!</h3>
    </transition>
</div>
  • js
var vm = new Vue({
    el: '#app',
    data: {
        flag: false
    },
    methods: {
    }
});

javascript动画钩子

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"

  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>
  • html
<div id="app">
    <button @click="flag=!flag">点我</button>
    <transition 
        @before-enter="beforeEnter"
        @enter="enter" 
        @after-enter="afterEnter">
        <div class="ball" v-show="flag"></div>
    </transition>
</div>
  • js
var vm = new Vue({
    el: '#app',
    data: {
        flag: false
    },
    methods: {
        beforeEnter(el) {
            el.style.transform="translate(0, 0)"
        },
        enter(el, done) {
            // 没有实际作用,但是不写没有效果
            el.offsetWidth
            el.style.transform="translate(150px, 150px)";
            el.style.transition="all 2s ease";
            // done其实就是afterEnter的引用
            done();
        },
        afterEnter(el) {
            this.flag=!this.flag;
        },
    }
});

v-move的使用

注意: v-move设置的同时, 还要设置

.my-leave-active{
	position: absolute;
}
  • html
<div id="app">
    <div class="tool">
        <label for="">id:</label><input type="text" name="" id="" v-model="id">
        <label for="">name:</label> <input type="text" name="" id="" v-model="name">
        <button @click="add">添加</button>
    </div>
    <ul>
        <transition-group name="my">
            <li v-for="(item,i) in list" :key="item.id" @click="del(i)">
                {{item.id}} -- {{item.name}}
            </li>
        </transition-group>
    </ul>
</div>
  • style
li {
    border: 1px dashed black;
    margin: 5px;
    line-height: 30px;
    padding-left: 5px;
    width: 500px;
}

.tool {
    margin: 20px;
    line-height: 30px;
    padding-left: 10px;
    font-size: 20px;
}
li:hover {
    background-color: hotpink;
    transition: all 0.8s ease;
}

.my-enter,
.my-leave-to {
    transform: translateY(80px);
}

.my-enter-active,
.my-leave-active {
    transition: all 0.8s ease;
}

/* 设置元素在移除后, 其他元素的位置变换过度 */
.my-move{
    transition:all 0.8s ease;
}
.my-leave-active{
    position: absolute;
}
</style>
  • js
var vm = new Vue({
    el: '#app',
    data: {
        list: [
            { id: 1, name: '赵高' },
            { id: 2, name: '秦桧' },
            { id: 3, name: '严嵩' },
        ],
        id: '',
        name: ''
    },
    methods: {
        add() {
            this.list.push({ id: this.id, name: this.name });
            this.id = this.name = '';
        },
        del(i){
            this.list.splice(i, 1);
        }
    }
});

transition-group中 appear 及tag属性

  • html
<ul>
    <transition-group name="my">
        <li v-for="(item,i) in list" :key="item.id" @click="del(i)">
       		{{item.id}} -- {{item.name}}
        </li>
    </transition-group>
</ul>

通过appear和tag的改造, 如果不指定tag,会默认给li添加span的父节点:

<transition-group name="my" appear tag="ul">
    <li v-for="(item,i) in list" :key="item.id" @click="del(i)">
        {{item.id}} -- {{item.name}}
    </li>
</transition-group>

路由

基础使用

  • script
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  • style
/* 路由选中样式 */
.router-link-active {
    color: pink;
}
  • html
<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>
    <!-- 路由出口 -->
    <!-- 路由匹配到的组件将渲染在这里, 可以使用transition包裹实现动画过度效果 -->
    <router-view></router-view>
</div>
  • js
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

// 2. 定义路由
const routes = [
 // redirect: 默认首页打开跳转为foo
  { path: '/', redirect: '/foo' },
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]
// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
  routes // (缩写) 相当于 routes: routes
})

// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
  el:'#app',
  router: router
})

参数传递

query传递

  • html
<div id="app">
    <h1>Hello App!</h1>
    <p>
        <router-link to="/foo?id=10">Go to Foo</router-link>
        <router-link to="/bar">Go to Bar</router-link>
    </p>
    <router-view></router-view>
</div>
  • js
const Foo = { 
    template: '<div>foo -- {{$route.query.id}}</div>',
    created(){
        console.log(this.$route);
    } }
const Bar = { template: '<div>bar</div>' }


// 2. 定义路由
const routes = [
    // redirect: 默认首页打开跳转为foo
    { path: '/', redirect: '/foo' },
    { path: '/foo', component: Foo },
    { path: '/bar', component: Bar }
]

const router = new VueRouter({
    routes // (缩写) 相当于 routes: routes
})


const app = new Vue({
    el: '#app',
    router: router
})
0zteC6.jpg

params传参

  • js
 const Foo = { 
        template: '<div>foo -- {{$route.params.id}}</div>',
        created(){
            console.log(this.$route);
        } }
    const Bar = { template: '<div>bar</div>' }

    // 2. 定义路由
    const routes = [
        // redirect: 默认首页打开跳转为foo
        { path: '/', redirect: '/foo' },
        { path: '/foo/:id', component: Foo },
        { path: '/bar', component: Bar }
    ]
    const router = new VueRouter({
        routes // (缩写) 相当于 routes: routes
    })

    const app = new Vue({
        el: '#app',
        router: router
    })
  • html
<div id="app">
    <h1>Hello App!</h1>
    <p>
        <router-link to="/foo/10">Go to Foo</router-link>
        <router-link to="/bar">Go to Bar</router-link>
    </p>
    <router-view></router-view>
</div>
0zt7Px.jpg

路由嵌套

  • html
<div id="app">
    <h1>Hello App!</h1>
    <p>
        <router-link to="/out">out</router-link>
    </p>
    <router-view></router-view>
</div>
  • template
<template id="out">
    <div>
        <p>
            <router-link to="/out/foo">Foo</router-link>
            <router-link to="/out/bar">Bar</router-link>
        </p>
        <router-view></router-view>
    </div>
</template>
  • js
const out = {
    template: '#out'
}

const Foo = {
    template: '<div>foo </div>'
}
const Bar = {
    template: '<div>bar</div>'
}

// 2. 定义路由
const routes = [
    {
        path: '/out',
        component: out,
        children: [
            { path: 'foo', component: Foo },
            { path: 'bar', component: Bar }
        ]
    }
]

const router = new VueRouter({
    routes // (缩写) 相当于 routes: routes
})


const app = new Vue({
    el: '#app',
    router: router
})

多布局视图

  • html
<div id="app">
    <router-view></router-view>
    <router-view name='left'></router-view>
    <router-view name='main'></router-view>
</div>
  • js
const header = {
    template: '<div>header </div>'
}

const left = {
    template: '<div>left </div>'
}
const main = {
    template: '<div>main</div>'
}


const router = new VueRouter({
    routes: [
        {
            path: '/', components: {
                'default': header,
                'left': left,
                'main': main
            }
        }
    ]
});

const app = new Vue({
    el: '#app',
    router: router
})