Vue

145 阅读1分钟

渐进式框架(数据驱动)

vue.js 是一套用于构建用户界面的渐进式框架

vue使用

  • 通过 <script> 的方式来引入 vue,开发版及生产版本

    ```html
     <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    ```
    
  • 通过cli来构建项目

  • 栗子

<body>
    <div id="app">
        <!-- 
            app 内:作用域

            {{ }}:插值表达式,内部是一个类js环境,可以做简单的逻辑运算;if else 不可以写
        -->
        {{message}}
        <br>
        {{message + '这里'}}
        <br>
        {{'message'}}
        <br>
        {{flag? 'yes': 'no'}}
    </div>
    <script>
        let app = new Vue({
            el: '#app', 
            // el 挂载点, 不能挂载html/body上
            // css 选择器
            data: {
                message: 'test',
                flag: false
            }
        })

        // 修改数据则视图会发生改变
        // app.message = '修改'
        // app.$data.message = '修改'

        // $ / _ 开头的为预定义的属性和方法
        // app.$data 做了代理proxy,循环app.$data这里的数据,并添加到app上


        // 延迟挂载
        // 不想在实例化的时候挂载,想要在后面挂载
        // app.$mount("#app");
    </script>
</body>
  • 运行结果

vue 组件

全局注册

  • 组件没有挂载点,挂载点是在实例里面
  • 组件里的data一定要是返还函数;(传值)(实例里用不用返还函数都可以)
<body>
    <div id="app">
        
        <!-- 调用组件 -->
        <!-- 单标签、双标签都可以,区别在于要不要传参 -->
        <my-component ></my-component>
        <hr>
        {{mydata}}
        <hr>
        {{arr}}
        <hr>
        {{obj}}
    </div>
</body>
全局注册组件

Vue.component("MyComponent",{
    data:function(){
        return {
            message:"组件里的数据"
        }
    },
    // 最外层一定 要 一个 标签容器包裹 ;
    template:`<div>我是my-component里的内容</div>`
   
    
render优先渲染;
    // render(createElement){
    //     // 渲染视图  (虚拟dom:vdom)
    //    let Vdom =  createElement("div","我是div里的内容");
    // // console.log(Vdom);
    //     // 有特殊标识的对象
    //    return Vdom;
    // }
})

局部注册

let ComponentA = {
    template:`<div>我是A组件</div>`
}


// 局部组件
let MyComponent = {
    components:{
        ComponentA
    },
    data:function(){
        return {
            message:"MyComponent内容"
        }
    },
    template:`<div>我是MyComponent里的内容{{message}} <component-a /> </div>`
}


// vue实例
let app = new Vue({
    el:"#app",
    components:{
        myComponent:MyComponent
    },
    data:{
        mydata:"数据",
        arr:["张三","李四","王五"],
        obj:{
            name:"王二",
            age:23
        }
    }
})
// 数据渲染Object.defineProperty (数据观察):更新视图;

// 几种情况不能更新视图;
// 组件和实例中的data都会有同样的问题
// 1. 数组操作不能更新(length) 
// 2. 对象的新增属性
// 强制更新视图  Vue.set

setTimeout(()=>{
    console.log("....");
    // 重写数组方法(变异方法);
    // 数组方法:push、pop、shift、unshift、splice、sort、reverse
    // app.arr.push("王小二");
    
    // 数组不能更新视图,强制更新
    // Vue.set(app.arr,1,"王小二");
    
    // app.arr[1] = "王小二";
    // console.log(app.arr);
    
    // 对象可以更改;
    // app.obj.name = "修改的名字";
    
    // 对象新增属性不能更改;
    // app.obj.height = "178cm";
    // 强制更改
    // Vue.set(app.obj,"height","178cm");
},1000)

// let that = this;
// that

指令

vue 动画

vue动画专栏

transition 组件

通过 transition 组件包裹的元素或组件,会在上面定义的几个场景中触发过渡,并添加指定的 class 样式

过渡类名
  • v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除
  • v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数
  • v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除
  • v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除
  • v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数
  • v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除

原生js实现动画

<style>
        .box{
            width: 100px;
            height: 100px;
            background: red;
            transition: all 3s;
            position: absolute;
            left: 0px;
        }
    </style>
    
    body>
    <button class="btn">点击</button>
    <div class="box">

    </div>
</body>
<script>
document.querySelector(".btn").onclick = function(){
    document.querySelector(".box").style.left = "500px";
}

</script>

vue实现css动画

<style>
        .box{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 300px;
        }
        <!--name = move-->
        .move-enter{
            left: 0px;
            opacity: 0;
        }
        .move-enter-to{
            left: 300px;
            opacity: 1;
        }
        .move-enter-active,.move-leave-active{
            transition: all 3s;
        }
        .move-leave{
            left: 300px;
            opacity: 1;
        }
        .move-leave-to{
            left: 600px;
            opacity: 0;
        }
    </style>
    
    <body>
    <div id="app">
        <button @click="judge=!judge">点击我显示隐藏div</button>
        <transition name="move">
            <div class="box" v-show="judge"></div>
        </transition>
       
    </div>
</body>
<script>
    new Vue({
        el:"#app",
        data:{
            judge:true
        }
    })


</script>

组件切换动画

<style>
        .box{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 300px;
        }
        .move-enter{
            left: 0px;
            opacity: 0;
        }
        .move-enter-to{
            left: 300px;
            opacity: 1;
        }
        .move-enter-active,.move-leave-active{
            transition: all 1s;
        }
        .move-leave{
            left: 300px;
            opacity: 1;
        }
        .move-leave-to{
            left: 600px;
            opacity: 0;
        }

    </style>
    
    <body>
    <!--模式:先进后出还是先出后进,不给的时候是同时的
        mode="out-in" / "in-out"-->
    <div id="app">
        <button @click="changeCom">点击我切换</button>
        <transition name="move" mode="out-in">
            <div :is="comName"></div>
        </transition>
        
    </div>
</body>
<script>
    let ComA = {
        template: `<div class="box">我是Coma组件</div>`
    }
    let ComB = {
        template: `<div class="box">组件Comb</div>`
    }

    new Vue({
        el: "#app",
        data: {
            comName: 'com-a'
        },
        components: {
            ComA,
            ComB
        },
        methods: {
            changeCom() {
                if(this.comName=="com-a"){
                    this.comName = "com-b";
                }else{
                    this.comName = "com-a";
                }
            }
        },
    })
</script>

vue实现js动画

 <style>
        .box{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 300px;
        }
    </style>
    
    <body>
    <div id="app">
        <button @click="judge=!judge">点击切换</button>
        <transition
            :css="false" 
            // transition会优先走css动画如果用js动画可以跳过检测提高性能
            @before-enter="beforeEnter"
            @enter="enter"
            @leave="leave"
        >
            <div class="box" v-if="judge">

            </div>
        </transition>
       
    </div>
</body>
<script>

new Vue({
    el:"#app",
    data:{
        judge:true
    },
    methods: {
        beforeEnter(el){
            console.log(el); 
            $(el).css({
                left:"0px",
                opacity:0
            })
        },
        enter(el,done){
            <!--通过done 转交到下一个-->
            // 异步情况要把done放在回调里
            $(el).animate({left:"300px",opacity:1},done);
            
            //done() 不能在这里写,因为animate是异步的
        },
        leave(el,done){
            $(el).animate({left:"600px",opacity:0},done);
        }
        
        // https://cn.vuejs.org/v2/guide/transitions.html
        // leave/enter 都有done
        
    },
})
</script>

vue 插件

html:

body>
    <div id="app">

    </div>
</body>
<script type="module">
    import Fn from './myfn.js';
    // Vue.prototype.fn = Fn;
    Vue.use(Fn);
    // 用use 加入,不会影响原型
    new Vue({
        el:"#app",
        data:{
            message:"数据"
        },
        created(){
            // Fn();
            this.fn();
        },
        mounted(){
            console.log("mounted");
        }
    })
</script>


myfn:
// 用了use 具体做了什么事
function fn(){
    console.log("一些逻辑");
}
export default function install(_Vue){
    // console.log(_Vue);
    _Vue.prototype.fn = fn;
    _Vue.mixin({
        mounted(){
            console.log("混入的mounted逻辑");
        }
    })
};

vue-cli

安装

npm install -g @vue/cli
# OR
yarn global add @vue/cli

package.json

// 运行时命令:npm run server / yarn server
// 上线前: npm run build 打包到dist目录,可以不仅仅在node环境下运行
"scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build"
 },
// 开发时需要用,上线后也需要  --save/-S
  "dependencies": {
    "core-js": "^3.6.5",
    "vue": "^2.6.11",
    "vue-router": "^3.3.3"
  },
  // 开发时需要,上线后不需要 --save-dev/-D
  "devDependencies": {   
    "@vue/cli-plugin-babel": "~4.4.0",
    "@vue/cli-service": "~4.4.0",
    "vue-template-compiler": "^2.6.11"
  },

vue文件

<template>
// 最外层容器——根元素
 <div>
     <my-com></my-com>
     // <MyCom></MyCom> 也会被容错
 </div>
</template>

<script>
 export default {
   data () {
     return {

     }
   },
   components: {
        MyCom
   }
 }
</script>

<style scoped>

 
</style>

注意:
  • template 也可以用src引入
<template src="">

</template>
  • lang
<template lang="pug/ejs">

</template>
  • scope
// scope不加会影响全局
<style scoped>

 
</style>

<template>
 <div>
     我是mycom组件
     <span>内容</span> 
     
     <!--@ 相对于路径src-->
     <!-- <img src="@/assets/logo.png" /> -->
     
     <!--用相对路径-->
     <!-- <img src="../assets/logo.png" /> -->
     <!-- <img src="./assets/logo.png" /> -->
     
     <!--找不到路径,默认会向前拼接服务器地址-->
     <!-- <img src="/assets/logo.png" /> --> 
 </div>
</template>

<script>
// spa 单页面应用
 export default {
   data () {
     return {

     }
   },
   components: {

   }
 }
</script>

<style scoped>
    /* span{
        color:red
    } */
 
</style>

注意:

@ -> webpack resolve 编译 -> /src 方便不同地方引用

hash history 都不会往服务器发请求

vue-router

/* router.js */

import Vue from 'vue'
import VueRouter from 'vue-router'
import AddNews from '@/components/AddNews'
import NewsShow from '@/components/NewsShow'
Vue.use(VueRouter)
let router = new VueRouter({
  mode:"history", // hash 
  routes:[
    {
      path:'/',
      redirect:'/addNews'
    },
    {   name:"addnews",
        path:"/addNews",
        component:AddNews
    },{
      name:"newshow",
      path:"/newsShow",
      component:NewsShow
    }
  ],
  linkActiveClass:"myActive"
})
export default router;

router-link

:to='" "' / {name: '', params: {id: item.id}}
默认生成a标签 tag= 指定生成标签
拦截点击 click 事件,内部哈希跳转/hsitory