Vue2脚手架创建项目
Vue2脚手架创建项目一、使用脚手架1.安装@vue/cli简述cli ===> command line interface(命令行接口)// 安装npm install -g @vue/cli# ORyarn global add @vue/cli// 升级npm update -g @vue/cli# ORyarn global upgrade --latest @vue/cli//
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"
}
说明:
- 优点:配置简单,请求资源时直接发给前端(8080)即可。
- 缺点:不能配置多个代理,不能灵活的控制请求是否走代理。
- 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)
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
*/
说明:
- 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
- 缺点:配置略微繁琐,请求资源时必须加前缀。
12.插槽
-
作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件 。
-
分类:默认插槽、具名插槽、作用域插槽
-
保存:给插槽传递的节点保存在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.作用域插槽
-
理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
-
具体编码:
父组件中:
<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"],
};
}
更多推荐
所有评论(0)