Vue2脚手架创建项目

一、使用脚手架

1.安装 @vue/cli

​ 简述 cli ===> command line interface (命令行接口)

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


// 升级
    npm update -g @vue/cli
    # OR
    yarn global upgrade --latest @vue/cli



// 版本查看 
	vue --version	或 vue -V

2…使用@vue/cli创建项目

// 创建项目
vue create hello-world

项目结构:

运行命名可查看具体的webpack配置: vue inspect > output.js

├── public 
│ ├── favicon.ico: 页签图标 
│ └── index.html: 主页面 
├── src 
│ ├── assets: 存放静态资源 
│ │ └── logo.png 
│ │── component: 存放组件 
│ │ └── HelloWorld.vue 
│ │── App.vue: 汇总所有组件 
│ │── main.js: 入口文件 
├── .gitignore: git 版本管制忽略的配置 
├── babel.config.js: babel 的配置文件 
├── package.json: 应用包配置文件 
├── README.md: 应用描述文件 
├── package-lock.json:包版本控制文件

index.html文件解释

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <!-- 针对IE浏览器的一个特殊配置,让IE浏览器一最高的渲染级别渲染也页面,因为 Vue 不支持 IE8 及以下版本 -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- 开启移动端的理想视口 -->
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <!-- <%= BASE_URL %> 永远指向 public 文夹下的目录 -->
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <!-- 使用package.json中的配置,配置标题 -->
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <!-- 当浏览器不支持js时,渲染soscript标签中的内容 -->
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

3.render配置项

import Vue from 'vue'
import App from './App.vue'

// 关闭Vue的生产提示
Vue.config.productionTip = false

new Vue({
  // 将 App组件渲染到容器中
  // render: h => h(App),
  components:{
    App
  },
  template:`<App />`
  // 这里不使用render函数会报错
}).$mount('#root')

不使用render函数报错:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jwArkaM1-1649689289671)(D:\Users\小江\Desktop\md_imgs\no_render_error.png)]

解决该问题:

方法一:引入完整版Vue

import Vue from 'vue/dist/vue'    //完整版Vue
import App from './App.vue'

new Vue({
  components:{
    App
  },
  template:`<App />`
}).$mount('#root')

方法二:使用render函数

import Vue from 'vue'
import App from './App.vue'

new Vue({
  // 将 App组件渲染到容器中 render函数(必须有返回值)返回一个虚拟节点 // 然后将返回的虚拟节点渲染到到页面
  // render(createElement){
  //   return createElement('h1','你好啊')
  // }

  // 简写
  render:h=>h(App)
    
}).$mount('#root')

createElement函数参数说明(摘自官网):

// @returns {VNode}
createElement(
  // {String | Object | Function}
  // 一个 HTML 标签名、组件选项对象,或者
  // resolve 了上述任何一种的一个 async 函数。必填项。
  'div',

  // {Object}
  // 一个与模板中 attribute 对应的数据对象。可选。
  {
     // 与 `v-bind:class` 的 API 相同,
     // 接受一个字符串、对象或字符串和对象组成的数组
     'class': {
         foo: true,
         bar: false
     },
     // 与 `v-bind:style` 的 API 相同,
     // 接受一个字符串、对象,或对象组成的数组
     style: {
         color: 'red',
         fontSize: '14px'
     }
      ...
  },

  // {String | Array}
  // 子级虚拟节点 (VNodes),由 `createElement()` 构建而成,
  // 也可以使用字符串来生成“文本虚拟节点”。可选。
  [
    '先写一些文字',
    createElement('h1', '一则头条'),
    createElement(MyComponent, {
      props: {
        someProp: 'foobar'
      }
    })
  ]
)

不同版本的Vue

1.	vue.js与vue.runtime.xxx.js的区别:
		(1) vue.js时完整版的vue,包含核心功能 + 模板解析器
		(2) vue.runtime.xxx.js时运行版的vue,只包含核心功能,没有模板解析器
2.	因为这里使用的是vue.runtime.js,没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函		数去指定具体内容

4.修改默认配置

与package.json同级目录下新建vue.config.js配置文件,具体配置参考 [vue.config.js](配置参考 | Vue CLI (vuejs.org))

module.exports = {
    pages: {
      index: {
        // page 的入口	修改entry
        entry: 'src/index.js',
      },
    }
  }

二、Vue在脚手架中的基础

1.ref属性

简述

1. 被用来给元素或子组件注册引用信息(id的替代者)
2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
3. 使用方式:
   1). 打标识:`<h1 ref="xxx">.....</h1>`或 `<School ref="xxx"></School>`
   2). 获取:`this.$refs.xxx`

编码:

<template>
  <div id="app">
    <input type="text" ref="usernameRef">
    <button @click="showMsg">展示信息</button>
  </div>
</template>

<script>

export default {
  name: 'App',
  methods:{
    showMsg(){
      console.log(this.$refs.usernameRef.value);
    }
  }
}
</script>

2.prop属性

简述

1. 功能:让组件接收外部传过来的数据 (优先级比data中的更高,最好不要修改props,用props初始化data中的数据后,再改变data中的值)
2. 传递数据:`<Demo name="xxx"/>`
3. 接收数据:
   1. 第一种方式(只接收):`props:['name'] `
   2. 第二种方式(限制类型):`props:{name:String}`
   3. 第三种方式(限制类型、限制必要性、指定默认值):
   		props:{
            name:{
                type:String, //类型
                required:true, //必要性
                default:'老王' //默认值
            }
        }
4.子组件向父组件传递数据时,需要父组件先给子组件传递一个函数,然后子组件调用
5.未被props接收的数据存在于this.$attrs中

编码:

// 父组件中传递porps
<Child name="小江"/>


//子组件中接收使用
<template>
  <div id="child">
    {{name}}
  </div>
</template>

<script>
export default {
  name: "Child",
  props:{
    name:{
      type:String,
      required:false,
      default:'张泽林'
    }
  }
};
</script>

3.混入(mixin)

简述

1. 功能:可以把多个组件共用的配置提取成一个混入对象
2. 使用方式:
   第一步定义混合:
       `{
           data(){....},
           methods:{....}
           ....
       }`
    第二步使用混入:
        全局混入:`Vue.mixin(xxx)`
        局部混入:`mixins:['xxx']`
        不贵改变原有配置,而是添加配置(当配置重复时,优先级比原有配置低)

编码:

// mixin 混入文件配置
export default {
    methods: {
        showName() {
            console.log(this.name)
        }
    }
}


// School组件中使用混入
<template>
  <div class="school" @click="showName">
    {{ name }}
  </div>
</template>

<script>
import {mixin1} from '../mixin'

export default {
  name: "Student",
  data() {
    return {
      name: "新东方",
    };
  },
  methods:{
      showName(){		// 配置重复,不会被覆盖
          alert('this.name');
      }
  },
  mixins:[mixin1]
};
</script>


// Student中使用组件
<template>
  <div class="student" @click="showName">
    {{ name }}
  </div>
</template>

<script>
import {mixin1,mixin2} from '../mixin'
export default {
  name: "Student",
  data() {
    return {
      name: "小三",
    };
  },
  mixins:[mixin1,mixin2]
};
</script>

4.插件

简述

1. 功能:用于增强Vue
2. 本质:包含 install 方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
3. 定义插件:
    对象.install = function (Vue, options) {
        // 1. 添加全局过滤器
        Vue.filter(....)

        // 2. 添加全局指令
        Vue.directive(....)

        // 3. 配置全局混入(合)
        Vue.mixin(....)

        // 4. 添加实例方法
        Vue.prototype.$myMethod = function () {...}
        Vue.prototype.$myProperty = xxxx
    }

编码:

// 在 plugins 文件中定义插件
export const Show = {
    install(Vue,...args){
        Vue.prototype.$show = ()=>alert(args[0]);
        console.log(Vue.prototype)
    }
}

// mian.js中引入插件
import {Show} from './plugins';

// 使用插件
Vue.use(Show,'小三')

5.scoped样式

1. 作用:让样式在局部生效,防止冲突。
2. 写法:`<style scoped>`
3. style语法 <style lang="css" />		使用less时,需要less-loader

编码:

<style lang="css" scoped>
.ft {
  color: yellow;
}
</style>

6.自定义事件

简述

1. 一种组件间通信的方式,适用于:子组件 ===> 父组件
2. 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。
3. 绑定自定义事件:
   1. 第一种方式,在父组件中:`<Demo @clickedschoolname="test"/>``<Demo v-on:clickedschoolname="test"/>`
   2. 第二种方式,在父组件中:
      <Demo ref="demo"/>
      ......
      mounted(){
         this.$refs.xxx.$on('clickedschoolname',this.test)
      }
   3. 若想让自定义事件只能触发一次,可以使用`once`修饰符,或`$once`方法。
4. 触发自定义事件:`this.$emit('clickedschoolname',数据)`	
5. 解绑自定义事件`this.$off('clickedschoolname')` 解绑多个自定义事件 `this.$off(['clickedschoolname','demo'])`
6. 组件上也可以绑定原生DOM事件,需要使用`native`修饰符。
7. 注意:通过`this.$refs.xxx.$on('clickedschoolname',回调)`绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!

编码

// 子组件
<template>
  <div class="school">
    <h3 @click="$emit('clickedschoolname',schoolName)">{{schoolName}}</h3>
  </div>
</template>

<script>
export default {
  name: "Student",
  data() {
    return {
      schoolName:'新东方'
    }
  },
  beforeDestroy(){
    this.$off('clickedschoolname');
  }
};
</script>


// 父组件
<template>
  <div id="app">
   <School @clickedschoolname="getSchoolName" ref="School" />
  </div>
</template>

<script>
import School from './components/School';

export default {
  name: 'App',
  components:{
    School
  },
 
  methods:{
    getSchoolName(schoolName){
      console.log('触发了',schoolName)
    }
  },

  // mounted() {
  //   this.$refs.School.$on('clickedschoolname',(schoolName)=>{
  //     console.log('触发了',schoolName);
  //   })
  // },

}
</script>

7.事件总线(GlobalEventBus)

简述

1. 一种组件间通信的方式,适用于 `任意组件间通信`
2. 安装全局事件总线:
       new Vue({
        ......
        beforeCreate() {
            Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
        }
           ......
       }) 

3. 使用事件总线:
   1. 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的 回调留在A组件自身。
      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.$bus.$on('xxxx',this.demo)
      }
   2. 提供数据:this.$bus.$emit('xxxx',数据)
          
4. 最好在beforeDestroy钩子中,用$off去解绑m当前组件所用到的 事件。

编码:

// 入口文件中
 beforeCreate(){
        // 安装全局事件总线	$bus就是当前应用的vm
        Vue.prototype.$bus = this;
    }


// School组件	监听$bus自定义事件,获取数据,解绑自定义事件
 mounted(){
    this.$bus.$on('msg',data=>{
      console.log('School获取到了StudentName',data)
    })
  },
  beforeDestroy(){
    this.$bus.$off('msg');
  }


// Student组件 触发$bus自定义事件,发送数据
 this.$bus.$emit("msg", this.studentName);

8.消息订阅与发布

简述:

1. 一种组件间通信的方式,适用于 任意组件间通信。
2. 使用步骤:
   1. 安装pubsub:npm i pubsub-js
   2. 引入: import pubsub from 'pubsub-js'
   3. 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的 回调留在A组件自身。
          mounted() {
            this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
          }

   4. 提供数据:pubsub.publish('xxx',数据)
   5. 最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)去 取消订阅。

编码:

// School组件	订阅消息,获取数据,取消订阅
 mounted(){
    this.pubsubId =  pubsub.subscribe('msg',(msgName,data)=>{
      console.log(msgName,data);
    })
  },
  beforeDestroy(){
    pubsub.unsubscribe(this.pubsubId);
  }


// Student组件 发布消息,发送数据
pubsub.publish('msg',this.studentName);

9.$nextTick

简介:

1. 语法:this.$nextTick(回调函数)
2. 作用:在下一次 DOM 更新结束后执行其指定的回调。
3. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。

编码:

<h3 @click="showInput">{{ schoolName }}</h3>
<input type="text" ref="inputRef" v-show="isShow">

data() {
    return {
      schoolName:'新东方',
      isShow:false
    }
  },
  methods:{
    showInput(){
      this.isShow = true; 
      // 会等函数代码执行完成之后再去重新渲染页面,但是这里input标签还未展示
      // ()=>this.$refs.inputRef.focus()

      // 方法一 使用一个定时器 利用事件轮询机制,在同步代码执行完成之后执行
      // setTimeout(()=>this.$refs.inputRef.focus());

      // 方法二 使用官方提供的方法,在下一次 DOM 更新结束后执行其指定的回调
      this.$nextTick(()=>{
        this.$refs.inputRef.focus();
      })
    }
  }

10.过渡与动画

作用:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。

a.动画

简述

1.将需要过度的元素用`<transition name="hello" appear>`元素包裹
2.多个元素开启动画使用`transition-group>`,且每个元素都要指定`key`值。
3.写好特定名字的动画样式(tempalte name的默认值是 v)
	.hello-enter-active{
        animation:show 1s;
	}
	.hello-leave-active{
        animation:show 1s reverse;
    }

编码:

<transition-group name="hello" appear>
    <h1 v-show="isShow" class="come" key="1">你好啊</h1>
    <h1 v-show="!isShow" class="come" key="2">尚硅谷</h1>
</transition-group>


data() {
    return {
      isShow: true,
    };
  }

<style scoped>
h1 {
  background-color: orange;
  color: red;
}
.hello-enter-active {
  animation: show 1s;
}
.hello-leave-active {
  animation: show 1s reverse;
}
@keyframes show {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0px);
  }
}
</style>
b.过度

各类名添加时机命名规则:
在这里插入图片描述
在这里插入图片描述

简述:

1.将需要过度的元素用`<template name="hello" appear>`元素包裹
2.多个元素开启动画使用`transition-group>`,且每个元素都要指定`key`值。
3.写好特定名字的动画样式(tempalte name的默认值是 v)
		/* 进入的起点,离开的终点 */
        .hello-enter-from,.hello-leave-to{
          transform: translateX(-100%);
        }
        /* 离开的终点,进入的起点 */
        .hello-enter-to,.hello-leave-from{
          transform: translateX(0);
        }

        .hello-enter-active,.hello-leave-active{
          transition: .5s linear;
        }

编码:

<transition name="hello" appear>
    <h1 v-show="isShow" class="come">你好啊</h1>
</transition>

 // 其它属性
   <transition name="zpj" type="transform" mode="out-in" appear>
      <component :is="isShow ? 'Home' : 'About'"></component>
    </transition>

data() {
    return {
    	isShow: true,
    };
}

<style scoped>
h1 {
  background-color: orange;
  color: red;
}
/* 进入的起点,离开的终点 */
.hello-enter,.hello-leave-to{
  transform: translateX(-100%);
}
/* 离开的终点,进入的起点 */
.hello-enter-to,.hello-leave{
  transform: translateX(0);
}

.hello-enter-active,.hello-leave-active{
  transition: .5s linear;
  
}
</style>
c.第三方库使用

使用css动画库animate.css
推荐 [Animate.css](Animate.css | A cross-browser library of CSS animations.)

简述:

在vue使用第三方封装的动画库

// 安装 
$ yarn add animate.css

// 引入
import 'animate.css'

方法一:使用css帧动画

// 使用
 <transition name="zpj" mode="out-in" appear>
  <component :is="isShow ? 'Home' : 'About'"></component>
</transition>

 <style>
 .zpj-enter-active {
    animation: bounceInUp 1s ease-in;
  }
   .zpj-leave-active {
    animation: bounceInUp 1s ease-in reverse;
  }
</style>

方法二:
使用transition组件自定义attribute结合animation动画类:
在这里插入图片描述
使用:

    enter-active-class="animate__animated animate__bounceInDown"
    leave-active-class="animate__animated animate__bounceOutDown">
      <component :is="isShow ? 'Home' : 'About'"></component>
</transition>

使用js动画库gsap,依赖于transition组件的钩子
在这里插入图片描述

安装:

yarn add gsap

使用:


<transition @enter="enter" @leave="leave" :class="css"> <!-- :class使用js动画时,用于忽略检测css动画-->
  <div v-if="isShow">
    <p>这是一个提示框</p>
  </div>
</transition>

import gsap from "gsap";

methods: {
enter(el, done) {
// done用于动画结束后的回调,当没有显示调用时,会被自动同步调用,该时动画可能还未结束
   console.log("enter");
   gsap.fromTo(
     el,
     { opacity: 0 },
     { opacity: 1, duration: 1, onComplete: done }
   );
},
leave(el, done) {
  console.log("leave");
  gsap.to(el, {
    opacity: 0,
    y: -100,
    duration: 0.5,
    ease: "power2.inOut",
    onComplete: done,
  });
},
},

使用gsap完成数字渐加动画:

<template>
  <div class="app">
    <input type="number" step="10" v-model="counter" />
    <p>当前计数:{{ showCounter }}</p>
  </div>
</template>

<script>
import gsap from "gsap";

export default {
  name: "App",
  data() {
    return {
      counter: 0,
      showNumber: 0,
    };
  },
  computed: {
    showCounter() {
      return this.showNumber.toFixed(0);
    },
  },
  watch: {
    counter(val) {
      gsap.to(this, {
        duration: 1,
        showNumber: val,
      });
    },
  },
};
</script>
d.transitiongroup使用
<transition-group tag="ul" name="zpj">
// 这里的ul使用包裹遍历的li,可选择包裹元素
   <li v-for="item in list" :key="item.id">
     {{ item.text }}
   </li>
 </transition-group>

<style>
.zpj-enter-from,
.zpj-leave-to {
  opacity: 0;
  transform: translateY(50px);
}

.zpj-enter-active,
.zpj-leave-active {
  transition: all 0.5s ease;
}
.zpj-leave-active{
  position: absolute; // 让元素在被移除运行动画时,不会占有原来层级的空间,并让后面的元素往上挤
}

.zpj-move {
	// 元素移动时使用的动画
  transition: transform 0.5s ease;
}
</style>

交替动画:

<transition-group
  tag="ul"
  name="zpj"
  @before-enter="beforeEnter"
  @enter="enter"
  @leave="leave"
  :class="false"
>
<!-- 传入下标,根据下标设置每个元素消失时的延迟时间,达到交替动画的效果 -->
  <li v-for="(item, index) in showNames" :key="index" :data-index="index">
    {{ item }}
  </li>
</transition-group>

import gsap from “gsap”;

export default {
name: “App”,
data() {
return {
keyword: “”,
names: [
“abs”,
“bcd”,
“efg”,
“hij”,

],
};
},
computed: {
showNames() {
return this.names.filter((name) => ~name.indexOf(this.keyword));
},
},
methods: {
beforeEnter(el) {
el.style.opacity = 0;
el.style.height = 0;
},
enter(el, done) {
gsap.to(el, {
opacity: 1,
height: “auto”,
delay: el.dataset.index * 0.1,
onComplete: done,
});
},
leave(el, done) {
gsap.to(el, {
opacity: 0,
height: 0,
onComplete: done,
});
},
},
};

11.配置代理

a.方法一

在vue.config.js中添加如下配置:

devServer:{
  proxy:"http://localhost:5000"
}

说明:

  1. 优点:配置简单,请求资源时直接发给前端(8080)即可。
  2. 缺点:不能配置多个代理,不能灵活的控制请求是否走代理。
  3. 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)
b.方法二

编写vue.config.js配置具体代理规则:

module.exports = {
	devServer: {
      proxy: {
      '/api1': {// 匹配所有以 '/api1'开头的请求路径
        target: 'http://localhost:5000',// 代理目标的基础路径
        changeOrigin: true,
        pathRewrite: {'^/api1': ''}
      },
      '/api2': {// 匹配所有以 '/api2'开头的请求路径
        target: 'http://localhost:5001',// 代理目标的基础路径
        changeOrigin: true,
        pathRewrite: {'^/api2': ''}
      }
    }
  }
}
/*
   changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
   changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
   changeOrigin默认值为true
*/

说明:

  1. 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
  2. 缺点:配置略微繁琐,请求资源时必须加前缀。

12.插槽

  1. 作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件

  2. 分类:默认插槽、具名插槽、作用域插槽

  3. 保存:给插槽传递的节点保存在this.$slots

a.默认插槽
父组件中:
        <Category>
           <div>html结构1</div>
        </Category>

子组件中:
        <template>
            <div>
               <!-- 定义插槽 -->
               <slot>插槽默认内容...</slot>
            </div>
        </template>
b.具名插槽
<!-- 默认的slot有一个名字为default -->
父组件中:
        <MyList>
            <div slot="main">
                江小江
            </div>
            <!--  <template v-slot:footer> -->
            <template slot="footer">
				<div>我是底部</div>
            </template>
        </MyList>

子组件中:
        <template>
          <div>
              <slot name="main"></slot>
              <slot name="footer"></slot>
          </div>
        </template>
c.作用域插槽
  1. 理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。

  2. 具体编码:

父组件中:
    <MyList>
        <!-- <template slot-scope="{fruits}"> -->
        <template scope="datas">
             {{datas.fruits}}
            <ul>
                <li v-for="(f,index) of datas.fruits" :key="index">
                    {{f}}
                </li>
            </ul>
        </template>
    </MyList>

子组件中:
    <slot :fruits="fruits"></slot>

        name: "MyList",
        data() {
        	return {
        		fruits: ["apple", "yali", "putao"],
        	};
        }
Logo

前往低代码交流专区

更多推荐