vue的详解

vue一些基本语法

1、初始化一个vue项目

> cnpm install -g vue-cli # 全局安装vue-cli 
> vue -V #检查vue版本
> vue init webpack vue-project #初始化一个vue项目
> cnpm install #进入项目目录 安装需要的依赖
> cnpm run dev #启动项目
> npm config set registry https://registry.npm.taobao.org
> npm config get registry
  • 父组件

    <Todo
     :message="我是父数据传给子组件"  #可以通过:message="父传子的数据"
     v-for="(item) in groceryList"
     v-bind:todo="item"  #可以通过v-bind 将数据传给子组件 todo是子组件的props
     v-bind:key="item.id"
    ></Todo>
    <script>
    import Todo from '@/components/Todo' #引入子组件
    export default {
     name: 'HelloWorld',
     data () {
     
    },
     components: {
       Todo #组件见
    }
    }  
    </script>
  • 子组件

    <template>
     <div class="hello">
      我是子组件
       <li>{{ todo.text }}</li>
     </div>
    </template>
    <script>
    export default {
     name: 'Todo',
     props: ['todo'] #父组件要一致
    }
    </script>
    • 子组件 子组件拥有自己的生命周期

      <template>
       <div class="hello">
        我是子组件
         <li @click="emitToparent">点击我传数据给父组件</li>
       </div>
      </template>

      <script>
      export default {
       name: 'Todo',
       methods: {
         emitToparent () {
           this.$emit('child-event', '我是子组件传数据给父组件')  #child-event是父组件绑定标示
        }
      }
      }
      </script>
    • 父组件

      <template>
       <div class="hello">
         <Todo
           @child-event="parentEvent"
         ></Todo>
       </div>
      </template>
      <script>
      import Todo from '@/components/Todo'
      export default {
       name: 'HelloWorld',
       data () {
         return {
        }
      },
       components: {
         Todo
      },
       methods: {
         parentEvent (data) {
           console.log('接入数据', data)
        }
      }
      }
      </script>
      - v-if   绑定判断关系 eg:<p v-if="seen">现在你看到我了</p>
      - v-bind 绑定html标签属性 eg:<a v-bind:href="url">...</a>
      - v-on 绑定on事件 eg:<a v-on:click="doSomething">...</a>
      - <a v-bind:[attributeName]="url"> ... </a> 动态绑定参数 data属性需有attributeName 其值为 "href",那么这个绑定将等价于 v-bind:href
      <input type="text" v-model.lazy="value"> #lazy这个修饰符会在光标离开input框才会更新数据
      <input type="text" v-model.trim="value"> #trim是输入框过滤首尾的空格
      <input type="text" v-model.number="value"> #number的功能是先输入数字就会限制输入只能是数字
      <button @click.stop="test">test</button> #stop是阻止事件冒泡
      <a @click.prevent="test">test</a> #prevent 阻止默认行为,相当于调用了event.preventDefault()方法,比如表单的提交、a标签的跳转就是默认事件
      <div @click.self="test"></div> #self 只有元素本身触发时才触发方法,就是只有点击元素本身才会触发
      <div @click.once="test"></div> #once 只能用一次,无论点击几次,执行一次之后都不会再执行
      - v-bind 缩写
      <!-- 完整语法 -->
      <a v-bind:href="url">...</a>
      <!-- 缩写 -->
      <a :href="url">...</a>
      - v-on 缩写
      <!-- 完整语法 -->
      <a v-on:click="doSomething">...</a>
      <!-- 缩写 -->
      <a @click="doSomething">...</a>
      <div id="example">
       <p>Original message: "{{ message }}"</p>
       <p>Computed reversed message: "{{ reversedMessage }}"</p>
      </div>
      var vm = new Vue({
      el: '#example',
      data: {
        message: 'Hello'
      },
      computed: {
        // 计算属性的 getter
        reversedMessage: function () {
          // `this` 指向 vm 实例
          return this.message.split('').reverse().join('')
        }
      }
      })
      new Vue({
       data: {
         n: 0,
         obj: {
           a: "a"
        }
      },
       template: `
         <div>
           <button @click="n += 1">n+1</button>
           <button @click="obj.a += 'hi'">obj.a + 'hi'</button>
           <button @click="obj = {a:'a'}">obj = 新对象</button>
         </div>
       `,
       watch: {
         n() {
           console.log("n 变了");
        },
         obj:{
           handler: function (val, oldVal) {
           console.log("obj 变了")
        },
           deep: true // 该属性设定在任何被侦听的对象的 property 改变时都要执行 handler 的回调,不论其被嵌套多深
        },
         "obj.a":{
           handler: function (val, oldVal) {
           console.log("obj.a 变了")
        },
           immediate: true // 该属性设定该回调将会在侦听开始之后被立即调用
        }
      }
      }).$mount("#app");
      • deep 控制是否要看这个对象里面的属性变化

      • immediate 控制是否在第一次渲染是执行这个函数

        vm.$watch() 的用法和 watch 回调类似

        • vm.$watch('data属性名', fn, {deep: .., immediate: ..})

        vm.$watch("n", function(val, newVal){
            console.log("n 变了");
        },{deep: true, immediate: true})
        vue.esm.js?efeb:628 [Vue warn]: Error in callback for watcher "fullName": "TypeError: Cannot read property 'call' of undefined"
        <div v-bind:class="[{ active: isActive }, errorClass]"></div>
        <my-component v-bind:class="{ active: isActive }"></my-component>
        <h1 v-show="ok">Hello!</h1>
        <ul id="example-1">
             <li v-for="(item,i) in items" :key="i"> #其中in可以使用of代替
              {{ item.message }}
             </li>
        </ul>
        <div v-for="(value, name, index) in object">
        {{ index }}. {{ name }}: {{ value }}
        </div>
        <li v-for="n in even(numbers)">{{ n }}</li>
        <div id="example-2">
         <!-- `greet` 是在下面定义的方法名 -->
         <button v-on:click="greet">Greet</button> #也可以传递数据 v-on:click="greet('abc',$event)"
        </div>
        methods: {
          greet: function (event) {
            // `this` 在方法里指向当前 Vue 实例
            alert('Hello ' + this.name + '!')
            // `event` 是原生 DOM 事件
            if (event) {
              alert(event.target.tagName) #得到原生事件
            }
          }
        }
        computed: {
        fullName: {
          // getter
          get: function () {
            return this.firstName + ' ' + this.lastName
          },
          // setter
          set: function (newValue) {
            var names = newValue.split(' ')
            this.firstName = names[0]
            this.lastName = names[names.length - 1]
          }
        }
        }
        <input v-on:keyup.enter="submit"> #按键修饰符
        <input v-on:keyup.13="submit"> #按键码
        <input v-on:keyup.k="submit" #k键
        <input v-model="message" placeholder="edit me">
        <p>Message is: {{ message }}</p>
        <!-- 在“change”时而非“input”时更新 -->
        <input v-model.lazy="msg" >  
        输入值转为数值类型
        <input v-model.number="age" type="number">
        如果要自动过滤用户输入的首尾空白字符
        <input v-model.trim="msg">
        <h3>{{ title }}</h3>
        <div v-html="content"></div> 这样会报错的 # every component must have a single root element
        正确 eg:
        <div class="blog-post">
         <h3>{{ title }}</h3>
         <div v-html="content"></div>
        </div>
        <div :style="{fontSize: postFontSize + 'em'}"></div> #在绑定的样式中要使用大小写
        <blog-post
               v-for="post in posts"
               v-bind:key="post.id"
               v-bind:post="post"
               v-on:enlarge-text="postFontSize += 1"
             ></blog-post>
        <input v-model="searchText"> 
        这里雷同于:
        <div id="app">
           <custom-input :value="searchText" @input="searchText = $event"></custom-input>
        </div>

        <template>
         <div>
           <input :value="value" @input="$emit('input', $event.target.value)"/>
         </div>
        </template>
        <script>
        export default {
         name: 'BlogPost',
         props: ['post', 'value'],
         data () {
           return {
             seen: true,
             obj: {
               content: '这个是子组件'
            }
          }
        }
        }
        </script>
        Vue.component('my-component-name', { /* ... */ })
        Vue.component('MyComponentName', { /* ... */ })
        Vue.component('component-a', { /* ... */ })
        Vue.component('component-b', { /* ... */ })
        Vue.component('component-c', { /* ... */ })
        new Vue({ el: '#app' })
        <div id="app">
         <component-a></component-a>
         <component-b><component-a></component-a></component-b>
         <component-c></component-c>
        </div>
        #笔者经过测试 只能后加载能使用前面加载的 比如在a使用b组件会报错的,应该是顺序加载的原因吧
        props: {
        title: String,
        likes: Number,
        isPublished: Boolean,
        commentIds: Array,
        author: Object,
        callback: Function,
        contactsPromise: Promise // or any other constructor
        }
        父组件
        <base-checkbox :checked="lovingVue"  @change="lovingVueFunc" ></base-checkbox> #checked接收是一个bool值的变量,change接收是一个影响lovingVue的方法,
        子组件
        Vue.component('base-checkbox', {
        model: {
          prop: 'checked',
          event: 'change'
        },
        props: {
          checked: Boolean
        },
        template: `
           <input
             type="checkbox"
             v-bind:checked="checked"
             v-on:change="$emit('change', $event.target.checked)"
           >
        `
        })
        [Vue warn]: Error in v-on handler: "TypeError: handler.apply is not a function
        eg:
        this.checked = this.checked === false ? true : false; #报错Unnecessary use of boolean literals in conditional expression
        应该替代为:
        this.checked = !this.cheked
         12% building modules 22/31 modules 9 active ...pace/vue_demo/Vue-Project/src/App.vue{ parser: "babylon" } is deprecated; we now treat it as { parser: "babel" }.
        95% emitting
        > 这个是因为 prettier版本有问题导致的 更换版本即可
        > 在当前项目中直接cnpm install prettier@~1.12.0 -D 或者cnpm install prettier@~1.12.0 --save-dev 然后重新npm run dev
        <template>
         <div id="example">
           <button @click="decrement">-</button>
           {{count}}
           {{dataCount}}
           <button @click="increment">+</button>
           <div>{{sex}}</div>
           <div>{{from}}</div>
           <div>{{myCmpted}}</div>
         </div>
        </template>
        <script>
        import { mapState } from 'vuex'
        export default {
         data () {
           return {
             str: '国籍',
             dataCount: this.$store.state.count
          }
        },
         computed: mapState({
           count: 'count', // 第一种写法
           sex: (state) => state.sex, // 第二种写法
           from: function (state) { // 用普通函数this指向vue实例,要注意
             return this.str + ':' + state.from
          },
           // 注意下面的写法看起来和上面相同,事实上箭头函数的this指针并没有指向vue实例,因此不要滥用箭头函数
           // from: (state) => this.str + ':' + state.from
           myCmpted: function () {
             // 这里不需要state,测试一下computed的原有用法
             return '测试' + this.str
          }
        }),
         methods: {
           increment () {
             this.$store.commit('increment')
          },
           decrement () {
             this.$store.commit('decrement')
          }
        },
         created () {
           // 写个定时器,发现computed依旧保持了只要内部有相关属性发生改变不管是当前实例data中的改变,还是vuex中的值改变都会触发dom和值更新
           setTimeout(() => {
             this.str = '国家'
          }, 1000)
        }
        }
         computed也可以写
         computed: mapState([
           // 映射 this.count 为 store.state.count
           'count'
        ])
        </script>
        const store = new Vuex.Store({
        state: {
          todos: [
            { id: 1, text: '...', done: true },
            { id: 2, text: '...', done: false }
          ]
        },
        getters: {
          doneTodos: state => {
            return state.todos.filter(todo => todo.done)
          }
        }
        })
        其他组件可以使用:
        store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
        mapGetters 辅助函数
        import { mapGetters } from 'vuex'
        export default {
        // ...
        computed: {
        // 使用对象展开运算符将 getter 混入 computed 对象中
          ...mapGetters([
            'doneTodosCount',
            'anotherGetter',
            // ...
          ])
        }
        }
        // ...
        mutations: {
        increment (state, n) { #n为increment的第一个参数
          state.count += n
        }
        }
        store.commit('increment', 10) #直接调用传入参数
        import { mapMutations } from 'vuex'
        export default {
        // ...
        methods: {
          ...mapMutations([
            'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
            // `mapMutations` 也支持载荷:
            'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
          ]),
          ...mapMutations({
            add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
          })
        }
        }
        const store = new Vuex.Store({
        state: {
          count: 0
        },
        mutations: {
          increment (state) {
            state.count++
          }
        },
        actions: {
          increment (context) { #context则代表是所有的store 但不是store
            context.commit('increment')
          }
        }
        })
        <template>
         <div id="app">
          Hello app.vue!
           <!-- 显示路由组件的位置 -->
           <router-view></router-view>
         </div>
        </template>
        export default new Router({
        // mode: 'history', #默认是使用history模式的 在new VueRouter的时候配置mode值为history来改变路由模式,本质使用H5的histroy.pushState方法来更改url,不会引起刷新 ,直接访问路由是默认是首页,关闭即可
        routes: [
          {
            path: '/',
            name: 'HelloWorld',
            component: HelloWorld
          }
        }]
        <div>
             <router-link to = "/home">首页</router-link>
        </div>
        // 路由的懒加载方式
          { path :"/home",component:()=>import("../views/Home")},// 当我访问/home首页时,页面才去加载Home组件,减少首页加载的时长
          { path :"/list",component:()=>import("../views/List")}, //也可以使用 component:()=>import('@/views/List')
          { path :"/mine",component:()=>import("../views/Mine")}
        { path :"/list",component:()=>import("../views/List"),children:[
              // 二级路由前不需要加“/”
            { path: "audio", component: () => import("../views/Audio") },
            { path: "video", component: () => import("../views/Video") }
          ]}
        <div>
         <router-link to = "/list/audio">音频</router-link>
         <router-link to = "/list/video">视频</router-link>
        </div>
        <router-view></router-view>
        <router-link tag = "li" :to = "{name:'detail',params:{id:'1'},query:{title:'最近播放'}}">我的歌单</router-link>

         

         

         

         

         

         

        路由跳转中 路由1,2同个路由节点,路由1设置了replace ,则先点击路由2再到路由1 ,用户点击浏览器退回按钮在路由2会被替换

        路由跳转到不同的url默认是push的过程,当用户点击浏览器后退按钮式时,则回到之前url,replace属性可以控制router-link的跳转不被记录。

        7、replace

        注解:name是要跳转的路由的名字,也可以写path来指定路径,但是用path的时候就不能使用params传参,params是传路由参数,query传queryString参数

        router-link的to属性,默认写的是path(路由的路径),可以通过设置一个对象,来匹配更多。

        6、to

        注:二级路由组件的切换位置依然由router-view来指定(指定在父级路由组件的模板中)。

        在创建路由表的时候,可以为每一个路由对象创建children属性,值为数组,在这个里面又可以配置一些路由对象来使用多级路由,注意:一级路由path前加'/',二级路由前不需要加'/'。

        5、二级路由:

        懒加载也叫延迟加载,即在需要的时候进行加载,随用随载。在单页应用中,如果没有应用懒加载,运用webpack打包后的文件将会异常的大,造成进入首页时,需要加载的内容过多,延时过长,会出现长时间的白屏

        4、路由懒加载

        3、使用route-link来创建切换路由工具

        2、在route中使用的mode是history模式

        1、路由切换须使用route-view

        vue的路由

        6、分发action mutation 执行的都是同步,但是action则可以执行异步

        5、可以使用mapMutations映射到vue

        4、改变store且传入参数

        3、mapGetter使用

        2、vuex 的getter使用

        1、获取多个状态的时候可以使用mapstate处理

         

        vue官方调试工具:https://github.com/vuejs/vue-devtools

        Flux文档:https://facebook.github.io/flux/docs/overview

        Redux文档:https://redux.js.org/

        vuex课程:https://scrimba.com/learn/vuex

        一些link

        vuex的一些基本语法

        注:开发项目中遇到的bug处理

         

        37、在eslint中 当存在简单替代方案时,不允许使用三元运算符

        36、在vue中函数不能与变量名一致,否则报错

        35、checkbox 中替代v-model的写法

        34、子组件的prop数据是单向流动的,意味着不能通过子组件去改变父组件的元素

        33、在prop的子组件中可以传入动态或者静态的prop

        32、prop定义数据的类型

        31、在prop中使用大写 在浏览器中可以直接转为小写的

        30、组件的全局注册

        29、组件名称:短横线或者是驼峰命名

        28、在父子组件中使用事件 可以使用v-model 来绑定事件

        27、在元素中添加js事件

        26、在style中添加变量

        25、每个组件都是新的实例,每个实例可以维护一份被返回对象的独立的拷贝,因为每个组件数据互不影响,组件元素比较只有一个根元素、否则报错

        组件可与v-model使用

        24、修饰符

        23、表单输入使用v-model

        22、按键修饰符

          可以理解为该修饰符的作用就是把一个vue组件转化为一个普通的HTML标签,并且该修饰符对普通HTML标签是没有任何作用的。

            img

            此时点击就会弹窗:

            img

             添加修饰符:

           此时点击页面中的按钮无任何反应。

            img

        (7). native:在父组件中给子组件绑定一个原生的事件,就将子组件变成了普通的HTML标签,不加'. native'事件是无法触 发的。

        (6). passive:该修饰符大概意思用于对DOM的默认事件进行性能优化,根据官网的例子比如超出最大范围的滚动条滚动的。

        (5). once:设置事件只能触发一次,比如按钮的点击等。

        img

        img 此时点击最内层:

        (4). self:将事件绑定到自身,只有自身才能触发,通常用于避免冒泡事件的影响

            img

        点击最内层结果:

        多个获取事件 :     img

            img

        此时点击最内层div,结果如下:

            img

        (3). capture:捕获冒泡,即有冒泡发生时,有该修饰符的dom元素会先执行,如果有多个,从外到内依次执行,然后再按自然顺序执行触发的事件。

          默认事件指对DOM的操作会引起自动执行的动作,比如点击超链接的时候会进行页面的跳转,点击表单提交按钮时会重新加载页面等,使用".prevent"修饰符可以阻止这些事件的发生。     img 此时点击超链接不会进行页面的跳转。

        (2). prevent:阻止默认事件的发生

            img

          再次点击内层div的结果如下:

            img

          修改代码,为内层点击事件添加事件".stop"修饰符:

            img

          点击外层div的结果:

            img

        点击内层div的结果:

        img

        (1). stop:阻止冒泡(通俗讲就是阻止事件向上级DOM元素传递)

        21、修饰符

         

         

         

        20、v-on 在事件中获取元素属性

        19、v-for中可以使用方法

        18、对已有对象赋值多个新属性 使用Object.assign() 、_.extend()

        17、v-for 中使用对象

        16、v-for 进行循环

        15、如果频繁的话使用v-show 如果条件复杂则使用v-if

        14、v-show 判断元素是否显示 类似于display

        Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外

        13、用 key 管理可复用的元素

        12、html绑定class 可以使用object 、可以使用[]三元表达式、 {}做类似if判断

        11、在vue中属性data跟methods方法名称不一样

        watch 是可以有setter getter 方法的 笔者使用会报错

      注意:不应该使用箭头函数来定义 watcher 函数,因为箭头函数没有 this,它的 this 会继承它的父级函数,但是它的父级函数是 window,导致箭头函数的 this 指向 window,而不是 Vue 实例

      一个对象,键是 data 对应的数据,值是对应的回调函数。值也可以是方法名,或者包含选项的对象,当 data 的数据发生变化时,就会发生一个回调,他有两个参数,一个 val (修改后的 data 数据),一个 oldVal(原来的 data 数据) Vue 实例将会在实例化时调用$watch(),遍历 watch 对象的每一个属性

      10、watch

      9、computed 通过计算出来的属性不需要调用直接可以在 DOM 里使用 页面渲染就会执行的

      8、v-缩写

      7 、修饰符

      6、绑定指令

      {{ }} 可以进行简单的运算以及三运表达式 {{ message.split('').reverse().join('') }}

      5、插入数据中使用双大括号

    4、子组件传数据给父组件

3、父组件传数据给子组件

2、配置本地的vue的淘宝镜像

posted @ 2020-12-18 15:28  做人如水,做事如山  阅读(435)  评论(0编辑  收藏  举报