Vue基础

2019-10-21 | 阅读:93次 Vue

Vue基础

准备

  • 浏览器插件:Vue.js devtools
  • VsCode 和 VsCode 插件
  • WebStorm
  • Nodejs
  • vue-cli
  • git

起飞

  1. 安装vue-cli3

    1. npm install -g @vue/cli
  2. npm install -g @vue/cli-service-global

    1. 慢?

      npm config set registry https://registry.npm.taobao.org
  3. 新建项目 vue create vue-demo

  4. 选择配置

Vue CLI v3.9.2
┌───────────────────────────┐
│  Update available: 3.9.3  │
└───────────────────────────┘
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, CSS Pre-processors, Linter
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Stylus
? Pick a linter / formatter config: Standard
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N) n
  1. Bable 代码转义

  2. Linter 代码风格

  1. 运行 npm run serve

  2. 项目结构

npm 基础

npm i module_name  -S         ==    npm install module_name --save
--save 表示将用到的模板保存到 package.json 中
npm i module_name  -D         ==    npm install module_name --save-dev 
写入到 devDependencies 对象
npm i module_name  -g  全局安装

组件大写开头

使用小写加 -

组件data必须是个function

mode:"history" 可以避免hash路由

MVVM

- M => Model(数据模型)
- V => View(视图模型,负责将数据模型转化成UI展现出来,就是那些DOM结构)
- VM => ViewModel(一个同步View和Model的对象)

Vue常用系统指令

插值表达式

    数据绑定最常见的形式,其中最常见的是使用插值表达式,写法是{{}} 中写表达式
    例如:<span>Message: {{ msg }}</span>
    Mustache 标签将会被替代为对应数据对象上 msg 属性(msg定义在data对象中)的值。
    无论何时,绑定的数据对象上 msg 属性发生了改变,插值处的内容都会更新。

    {{}}对JavaScript 表达式支持,例如:
    {{ number + 1 }}
    {{ ok ? 'YES' : 'NO' }}
    {{ message.split('').reverse().join('') }}

    但是有个限制就是,每个绑定都只能包含单个表达式,如下表达式无效:
    <!-- 这是语句,不是表达式 -->
    {{ var a = 1 }}

    <!-- 这也是语句,不是表达式 -->
    {{ number++ }} 会报警告:vue2.js:482 [Vue warn]: You may have an infinite update loop in a component render function.

    <!-- 流控制也不会生效,请使用三元表达式 -->
    {{ if (ok) { return message } }}

v-text

  <!-- v-text可以将一段文本渲染到指定的元素中,例如: -->
  <div v-text="msg"></div>
  new Vue({
      data:{
          msg:'hello world'
      }
  });

  <!-- 输出结果:-->
  <div>hello world</div>

v-html

  差值表达式和v-text会将数据解释为纯文本,而非 HTML 。
  为了输出真正的 HTML ,你需要使用 v-html 指令:
  例如:
  <div v-html="rawHtml"></div>
      new Vue({
          data:{
              rawHtml:'<h1>hello world</h1>'
          }
  })

  被插入的内容都会被当做 HTML,但是对于没有HTML标签的数据绑定时作用同v-text和{{}}

v-bind

  1、作用:可以给html元素或者组件动态地绑定一个或多个特性,例如动态绑定style和class

  2、举例:
      1、img的src从imageSrc变量中取得
          <img v-bind:src="imageSrc" >

          2、从classA, classB两个变量的值作为class的值,
          结果是:<div class="A B">classA, classB</div>        
          <div v-bind:class="[classA, classB]">classA, classB</div>

          3、isRed变量如果为true,则class的值为red,否则没有
          <div v-bind:class="{ red: isRed }">isred</div>

          4div的class属性值一定有classA变量的值,而是否有classB和classC变量的值取决于isB和isC是否为true,二者一一对应
          <div v-bind:class="[classA, { classB: isB, classC: isC }]">数组对象</div>

          5、变量加常量
          <div v-bind:style="{ fontSize: size + 'px' }">size22</div>

          6、变量加常量的另一种写法
          <img v-bind="{src:imageSrc+'?v=1.0'}" >

          7、对象数组
          <div v-bind:style="[styleObjectA, styleObjectB]">styleObjectA, styleObjectB</div>

  3、缩写形式
      <img :src="imageSrc">
      <div :class="[classA, classB]">classA, classB</div>
      <div v-bind:class="{ red: isRed }">isred</div>
      <div v-bind:class="[classA, { classB: isB, classC: isC }]">数组对象</div>
      <div v-bind:style="{ fontSize: size + 'px' }">size22</div>
      <img v-bind="{src:imageSrc+'?v=1.0'}" >
      <div v-bind:style="[styleObjectA, styleObjectB]">styleObjectA, styleObjectB</div>


    vue对象初始化
    <script>
      // 实例化vue对象(MVVM中的View Model)
      new Vue({
          // vm控制的区块为id为app的div,此div中的所有vue指令均可以被vm解析
          el:'#app',
          data:{
          // 数据 (MVVM中的Model)   
          imageSrc:'http://157.122.54.189:8998/vue/vuebase/chapter1/imgs/d1-11.png',
          isRed:true,
          classA:'A',
          classB:'B',
          isB:true,
          isC:true,
          size:22,
          styleObjectA:{color:'red'},
          styleObjectB:{fontSize:'30px'}
          },
          methods:{

          }
      })
  </script>

v-for

  <!-- 
    v-for用法:
      item in Array
      (item, index) in Array
      value in Object
      (value, key, index) in Object

    :key属性具有唯一性,不能重复,它能够唯一标识数组的每一项
    将来数据中的某一项的值发生了改变,则v-for只会更新当前项对应的这个dom元素的值,而不是更新整个数据,从而提高效率,参考https://www.zhihu.com/question/61064119/answer/183717717

    注意:以下变动不会触发视图更新
      1. 通过索引给数组设置新值
      2. 通过length改变数组
    解决:
      1. Vue.set(arr, index, newValue)
      2. arr.splice(index, 1, newValue)
    -->
    <ul>
      <li v-for="item in user">{{item.name}}</li>
      <li v-for="(item, index) in user" :key="index">{{index}}.{{item.name}}</li>
      <li>---------------华丽的分割线---------------</li>
      <li v-for="value in boss">{{value}}</li>
      <li v-for="(value, key, index) in boss"> {{index}}.{{key}}:{{value}}</li>
    </ul>
    <script>
    var vm = new Vue({
      el: '#app',
      data: {
        user: [
          {name: 'jack'},
          {name: 'neil'},
          {name: 'rose'}
        ],
        boss: {
          name: '马云',
          age: 50,
          money: 1000000002030
        }
      }
    })
    </script>

v-model

  1、在表单控件或者组件上创建双向绑定
  2、v-model仅能在如下元素中使用:
    input
    select
    textarea
    components(Vue中的组件)

  3、举例:
    <input type="text" v-model="uname" />

  new Vue({
      data:{
          uname:'' //这个属性值和input元素的值相互一一对应,二者任何一个的改变都会联动的改变对方
        }
  })

v-on

  1、作用:绑定事件监听,表达式可以是一个方法的名字或一个内联语句,
  如果没有修饰符也可以省略,用在普通的html元素上时,只能监听 原生
  DOM 事件。用在自定义元素组件上时,也可以监听子组件触发的自定义事件。

  2、常用事件:
      v-on:click
      v-on:keydown
      v-on:keyup
      v-on:mousedown
      v-on:mouseover
      v-on:submit
      ....

  3、示例:
    <!-- 方法处理器 -->
    <button v-on:click="doThis"></button>
    <!-- 内联语句 -->
    <button v-on:click="doThat('hello', $event)"></button>

    <!-- 阻止默认行为,没有表达式 -->
    <form v-on:submit.prevent></form>

   5、v-on的缩写形式:可以使用@替代 v-on:
    <button @click="doThis"></button>


  6、按键修饰符
    触发像keydown这样的按键事件时,可以使用按键修饰符指定按下特殊的键后才触发事件

    写法:
      <input type="text" @keydown.enter="kd1">  当按下回车键时才触发kd1事件

      由于回车键对应的keyCode是13,也可以使用如下替代
      <input type="text" @keydown.13="kd1">  当按下回车键时才触发kd1事件

      但是如果需要按下字母a(对应的keyCode=65)才触发kd1事件,有两种写法:
      1、由于默认不支持a这个按键修饰符,需要Vue.config.keyCodes.a = 65 添加一个对应,所以这种写法为:

      Vue.config.keyCodes.a = 65
      <input type="text" @keydown.a="kd1">  这样即可触发

      2、也可以之间加上a对应的数字65作为按键修饰符
      <input type="text" @keydown.65="kd1">  这样即可触发

      键盘上对应的每个按键可以通过 http://keycode.info/ 获取到当前按下键所对应的数字

v-on按键修饰符

  • 作用说明
    文档地址:https://cn.vuejs.org/v2/guide/events.html#键值修饰符

    在监听键盘事件时,我们经常需要监测常见的键值。 Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:
    .enter
    .tab
    .delete (捕获 “删除” 和 “退格” 键)
    .esc
    .space
    .up
    .down
    .left
    .right
  • 可以自定义按键别名
    // 在Vue2.0版本中扩展一个f1的按键修饰符写法:
    Vue.config.keyCodes.f1 = 112

    // 使用
    <button @keyup.f1="someFunc"></button>

v-if

  1、作用:根据表达式的值的真假条件来决定是否渲染元素,如果条件为false不渲染(达到隐藏元素的目的),为true则渲染。在切换时元素及它的数据绑定被销毁并重建

  2、示例:
    <!-- Handlebars 模板 -->
    {{#if isShow}}
      <h1>Yes</h1>
    {{/if}}

    通常我们使用写法居多:
    <h1 v-if="isShow">Yes</h1>

    也可以用 v-else 添加一个 “else” 块:
    <h1 v-if="isShow">Yes</h1>
    <h1 v-else>No</h1>

    注意:v-else 元素必须紧跟在 v-if 元素否则它不能被识别。

    new Vue({
        data:{
          isShow:true
        }
    });

v-show

  1、根据表达式的真假值,切换元素的 display CSS 属性,如果为false,则在元素上添加 display:none来隐藏元素,否则移除display:none实现显示元素

  2、示例:
      <h1 v-show="isShow">Yes</h1>

      new Vue({
          data:{
            isShow:true
              }
      });

  3、v-if和v-show的总结:
      v-if和v-show 都能够实现对一个元素的隐藏和显示操作,但是v-if是将这个元素添加或者移除到dom中,而v-show
      是在这个元素上添加 style="display:none"和移除它来控制元素的显示和隐藏的

v-cloak

  v-cloak指令保持在元素上直到关联实例结束编译后自动移除,v-cloak和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。
  通常用来防止{{}}表达式闪烁问题
  例如:
  <style>
  [v-cloak] { display: none }
  </style>

  <!-- 在span上加上 v-cloak和css样式控制以后,浏览器在加载的时候会先把span隐藏起来,知道 Vue实例化完毕以后,才会将v-cloak从span上移除,那么css就会失去作用而将span中的内容呈现给用户 -->
  <span v-cloak>{{msg}}</span>    

  new Vue({
      data:{
          msg:'hello ivan'
        }
  })

组件化

.vue是vue的单文件组件由三部分组成

computed

有一个缓存 不会重新计算值 不要修改值

computed:{
name:{
get(){
returen   
},
set(){

}

}
}

Watch

监听数据变换 做出操作

组件间的双向绑定

props:[],
<input @input="handleInput">

methods:
handleInput(e){
this.$emit('input',e.target.value)

动态传值

用emit

子组件

            <span class="cart" @click="addToCart">加入购物车</span>

        methods: {
            addToCart() {
               this.$emit('addCart')
            }
        },

父组件

            <detail-bottom-bar @addCart="addToCart"/>
        methods: {
            addToCart() {
                console.log('---');
            }
        },

用props

父组件

            <detail-bottom-bar :title="title"/>
data{
title:'ss'
}

子组件

props{
}

用插槽

插槽

子组件HeaderTop

        <slot name="left"></slot>
        <!--        title-->
        <span class="header-title">{{title}}</span>
        <slot name="right"></slot>

父组件

        <HeaderTop :title="title">
            <span class="header-search" slot="left">
                    <i class="iconfont icon-search"></i>
            </span>
            <span class="header-login" slot="right">
                    登陆/注册
            </span>
        </HeaderTop>

Provide

爷爷

provide(){
retuen{
yeye:this,
value:this.value
}
}

inject:['yeye','value']

Render

v-on

Click

路由(vue-router)

# 安装
npm i vue-router -D
  1. 定义(路由 )组件 Home Me Cart Explorer.vue
   <template>
   <div>
     {{msg}}
   </div>
   </template>

   <script>
     export default {
       name: "Home", data() {
         return {
           msg: "home"
         }
       }

     }
   </script>

   <style scoped>

   </style>
  1. . 定义路由

router/index.js

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import HelloVue from '@/components/HelloVue'
//导入创建的界面
import Home from '@/components/Home'
import Cart from '@/components/Cart'
import Me from '@/components/Me'
import Explorer from '@/components/Explorer'

//使用路由
Vue.use(Router);

export default new Router({
  routes: [
    // 将页面组件与path指定的路由关联
    {
      path: '/1',
      name: 'HelloWorld',
      component: HelloWorld
    },
    //我定义的路由
    {
      path: '/hello',
      name: '/hellovue',
      component: HelloVue
    },
    {path: '/home', component: Home},
    {path: '/me', component: Me},
    {path: '/cart', component: Cart},
    {path: '/explorer', component: Explorer},
  ]
})
  1. routes配置

App.vue

<template>
  <div id="app">
<!--    <img src="./assets/logo.png" alt="图片">-->
    <router-view/>
  </div>
</template>

直接引用路由

<li>  
    <router-link to="/home">    
        <div> <img src="../assets/images/home.svg" alt="主页">
        </div>    
        <div>首页</div>  
    </router-link>
</li>

不直接引用路由定义

        <li>
          <router-link :to="{name:'Home'}">
            <div> <img src="../assets/images/home.svg" alt="主页"></div>
            <div>首页</div>
          </router-link>
        </li>

虽然命名路由的方式会比直接引用path多写一些代码,但这是值得的,因为一旦遇到路径的修改只需要在main.js的全局路由设置中进行修改而不用在每个用到的地方都改一次!

动态路由

    routes: [{
        name:'BookDetails',
        path:'/books/:id'
        component: BookDetails
       }
    ]

路由跳转

 @click="goto('/search')"
        methods: {
            goto(path) {
                this.$router.replace(path)
            }
        }

this.$router.push(path)

返回上一个界面

 @click="$router.back(-1)"
 或者
 this.$router.go(-1)

路由传参

1

设置路由

{
            path: '/detail/:iid',
            name: 'detail',
            component: Detail
        },

设置跳转方法

itemClick(){
                this.$router.push('/detail/'+this.goodsItem.iid)
            }

接收的组件

        created() {
            this.iid = this.$route.params.iid
            console.log(this.iid);
        }

o了

2

设置路由

 {
     path: '/describe',
     name: 'Describe',
     component: Describe
   }
  this.$router.push({
          path: '/describe',
          query: {
            id: id
          }
        })
$route.query.id

3

父组件中:通过路由属性中的 name 来确定匹配的路由,通过 params 来传递参数。

   this.$router.push({
      name: 'Describe',
      params: {
        id: id
      }
    })

对应路由配置:注意这里不能使用:/id 来传递参数了,因为父组件中,已经使用 params 来携带参数了。

{ path: '/describe', name: 'Describe', component: Describe } 子组件中:这样来获取参数

$route.params.id

阿里图标

主页引入
 <link rel="stylesheet" href="http://at.alicdn.com/t/font_wyhhdpv5lhvbzkt9.css">
图片使用
<i class="icon iconfont icon-hanbao"></i>

Element UI

安装
npm  install element-ui --save

完整引入

import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';

Vue.use(ElementUI);

new Vue({
  el: '#app',
  render: h => h(App)
});

Cube-ui

vue add cube-ui

✔  Successfully installed plugin: vue-cli-plugin-cube-ui

? Use post-compile? Yes
? Import type Partly
? Custom theme? Yes
? Use rem layout? No
? Use vw layout? No

Mock数据

vue.congif.js

// 1.声明数据变量
const appData = require('./data.json')
const seller = appData.seller
const goods = appData.goods
const ratings = appData.ratings
module.exports = {
  css: {
    loaderOptions: {
      stylus: {
        'resolve url': true,
        'import': [
          './src/theme'
        ]
      }
    }
  },
  pluginOptions: {
    'cube-ui': {
      postCompile: true,
      theme: true
    }
  },
  // 2.数据请求
  devServer: {
    before (app) {
      app.get('/api/seller', function (req, res) {
        res.json({
          errno: 0,
          data: seller
        })
      })
      app.get('/api/goods', function (req, res) {
        res.json({
          errno: 0,
          data: goods
        })
      })
      app.get('/api/ratings', function (req, res) {
        res.json({
          errno: 0,
          data: ratings
        })
      })
    }
  }
}

访问http://localhost:8080/api/seller

FastClick

安装npm install fastclick --save

在main.js引用

import FastClick from 'fastclick'

使用

FastClick.attach(document.body);

stylus

npm i stylus stylus-loader --save

引用

Jsonp

安装npm install jsonp

Axios

async loginClick(){
    const res = await axios.get('');
    const data =res.data
}
axios.all(
[
axios.get(''),
axios.get('')
]})
//把结果单独拿出来
.then(axios.spread(res1,res2)=>{
console.log(res1),console.log(res2)
})

全局配置

axios.defaults.baseURL=''
axios.defaults.timeout=''

axios的封装

request.js

import axios from 'axios'

export function request(config) {
//    1. 创建实例
    const instance = axios.create({
        baseURL: "http://123.207.32.32:8000",
        timeout: 5000
    })
//    2. 配置拦截器
    instance.interceptors.request.use(config => {
        return config
    }, error => {
        console.log(error);
    })

//    3. 相应拦截
    instance.interceptors.response.use(res => {
        return res.data
    }, error => {
        console.log(error);
    })

//    4. 发送请求
    return instance(config)
}

home.js

import {request} from "./request";

export function getHomeMultidata() {
    return request({
        url:"/home/multidata"
    })
}
export function getHomeGoods(type, page) {
    return request({
        url: '/home/data',
        params: {
            type,
            page
        }
    })
}

Vue中使用

            getHomeMultidata() {
                getHomeMultidata().then(res => {
                    this.banners = res.data.banner.list;
                    this.recommends = res.data.recommend.list;
                })
            }

normalize

npm install --save normalize.css

better-scroll

npm install better-scroll --save

Vant

npm i vant -S

引入组件

  • 自动按需引入
npm i babel-plugin-import -D
// 在.babelrc 中添加配置
// 注意:webpack 1 无需设置 libraryDirectory
{
  "plugins": [
    ["import", {
      "libraryName": "vant",
      "libraryDirectory": "es",
      "style": true
    }]
  ]
}

// 对于使用 babel7 的用户,可以在 babel.config.js 中配置
module.exports = {
  plugins: [
    ['import', {
      libraryName: 'vant',
      libraryDirectory: 'es',
      style: true
    }, 'vant']
  ]
};
// 接着你可以在代码中直接引入 Vant 组件
// 插件会自动将代码转化为方式二中的按需引入形式
import { Button } from 'vant';

如果你在使用 TypeScript,可以使用 ts-import-plugin 实现按需引入

viewpoint

<meta name="viewport"     content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no">

移动端屏幕适配

iPhone5 1rem=16px 20rem=320

html font-size=16px

在index下

<script>
    let htmlwidth = document.documentElement.clientWidth || document.body.clientWidth;
    let htmlDom = document.getElementsByTagName('html')[0];
    if (htmlwidth > 750) {
        htmlwidth = 750
    }
    htmlDom.style.fontSize = htmlwidth / 20 + 'px';
    console.log(htmlwidth)
</script>

vue-awesome-swiper

 npm install vue-awesome-swiper --save
  • 全局引入

可以直接使用全局引入,引入代码如下:

import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper'

// require styles
import 'swiper/dist/css/swiper.css'

Vue.use(VueAwesomeSwiper, /* { default global options } */)
  • 以组件形式引入

这种方式是在需要的页面以 component 的形式引入,好处就是依赖性不强。

import 'swiper/dist/css/swiper.css'

import { swiper, swiperSlide } from 'vue-awesome-swiper'

export default {
  components: {
    swiper,
    swiperSlide
  }
}

使用

        <!--swiper-->
        <swiper :options="swiperOption">
            <swiper-slide v-for=" (item ,index) in recommendGoods" :key="index">
                <div class="recommend-item">

                    <img :src="item.image" width="80%"/>
                    <div>{{item.goodsName}}</div>
                    <div>{{item.price}} (¥{{item.mallPrice}})</div>
                </div>
            </swiper-slide>
        </swiper>
  • direction:'vertical' 设置竖排显示
  • slidesPerView:'auto' 设置同屏显示的数量,默认为 1,这里使用 auto 是随意的意思。
  • freeMode:true 默认为 false,普通模式:slide 滑动时只滑动一格,并自动贴合 wrapper,设置为 true 则变为 free 模式,slide 会根据惯性滑动可能不止一格且不会贴合。
  • mousewheel:true 开启鼠标滚轮控制 Swiper 切换。可设置鼠标选项,或 true 使用默认值。

获取div里面的值

      <li
        class="item"
        v-for="(item ,index) of cities"
        :key="index"
        @click="handleLetterClick"
      >
        {{index}}
      </li>
------------------------------------------
    methods: {
      handleLetterClick(e) {
        console.log(e.target.innerHTML)
      }
    }

flex

display: flex;
align-items: center;         /* 弹性盒子flex 元素位于容器的中心 
设置弹性盒子元素在垂直方向上(纵轴)的对齐方式。*/
justify-content: center;     /* 弹性盒子flex 元素位于容器的中心 
设置弹性盒子元素在主轴(横轴)的对齐方式*/

$Even

e.srcElement ==dom节点

保存主页的位置

        activated() {
            this.$refs.scroll.scrollTo(0, this.saveY, 0)
            console.log('ac');
        },
        deactivated() {
            this.saveY = this.$refs.scroll.y
            console.log('deac');
        },

nav-Bar顶置

    .nav-bar{
        position: relative;
        z-index:9 ;
        background-color: white;
    }
0条评论
  • 1