创建脚手架
1 2
| 1. 如出现下载缓慢请配置 npm 淘宝镜像: npm config set registry https://registry.npm.taobao.org
|
脚手架官网https://cli.vuejs.org/zh/
具体步骤:
第一步(仅第一次执行):全局安装@vue/cli。
1 2 3 4
| # 如果安装过了, 需要先卸载再次安装 # 卸载命令 # npm uninstall -g vue-cli npm install -g @vue/cli
|
第二步:切换到你要创建项目的目录,然后使用命令创建项目
如果普通用户cmd无法创建, 使用管理员cmd试试
第三步:启动项目
访问http://localhost:8080/, 可以看见脚手架为我们默认创建一个 HelloWorld 组件
脚手架文件结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ├── node_modules ├── 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:包版本控制文件
|
脚手架运行项目的报错
xxx should always be multi-word vue/multi-word-component-names 报错
修改 vue.config.js 文件
1 2 3 4 5
| const { defineConfig } = require("@vue/cli-service"); module.exports = defineConfig({ transpileDependencies: true, lintOnSave: false, });
|
如果编写了代码, 左侧行数会出现一个红色小箭头, 这是 git 在记录
可以按 Ctrl+, 打开设置, 搜索 git:Enabled, 关闭 Git
部署自己的项目到脚手架
School.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <template> <div> <h2>学校名称: {{ name }}</h2> <h2>学校地址: {{ address }}</h2> <button @click="showName">点我显示名称</button> </div> </template>
<script> export default { name: "School", data() { return { name: "尚硅谷", address: "北京", }; }, methods: { showName() { alert(this.name); }, }, }; </script>
<style></style>
|
Student.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <template> <div> <h2>学生姓名: {{ name }}</h2> <h2>学生年龄: {{ age }}</h2> </div> </template>
<script> export default { name: "Student", data() { return { name: "肉豆蔻", age: 18, }; }, }; </script>
<style></style>
|
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <template> <div> <School></School> <Student></Student> </div> </template>
<script> import Student from "./components/Student.vue"; import School from "./components/School.vue";
export default { name: "App", components: { Student, School, }, }; </script>
<style></style>
|
main.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
import Vue from "vue";
import App from "./App.vue";
Vue.config.productionTip = false;
new Vue({ el: "#app", render: (h) => h(App),
});
|
import Vue from ‘vue’中引入的是 vue 文件夹, 它是由 vue 文件夹中的 module 配置项来决定导入的是哪一个 vue.js
runtime.js 相比于 vue.js, 精简了模板解析器, 模板解析器也不会在 webpack 打包的时候被打包进去
关于不同版本的 Vue
- vue.js 与 vue.runtime.xxx.js 的区别:
- vue.js 是完整版的 Vue,包含:核心功能 + 模板解析器。
- vue.runtime.xxx.js 是运行版的 Vue,只包含:核心功能;没有模板解析器。
- 因为 vue.runtime.xxx.js 没有模板解析器,所以不能使用 template 这个配置项,需要使用 render 函数接收到的 createElement 函数去指定具体内容。
render 函数
使用 render 渲染函数就可以在 runtime.js 的环境中解析模板, template 在 runtime.js 的环境中没法解析模板, 因为 runtime 剔除了模板引擎
1 2 3 4 5 6 7 8 9 10 11 12 13
|
render: (a) => a("h1", "你好啊");
|
修改默认配置(vue.config.js 配置文件)
vue.config.js
在 pages 选项中配置的 entry 可以指明 main.js 作为程序的入口, 当然可以设置成其他的, 一般保持默认既可
1 2 3 4 5 6 7 8 9 10 11
| const { defineConfig } = require("@vue/cli-service"); module.exports = defineConfig({ pages: { index: { entry: "src/main.js", }, }, transpileDependencies: true, lintOnSave: false, });
|
- 使用 vue inspect > output.js 可以查看到 Vue 脚手架的默认配置。
- 使用 vue.config.js 可以对脚手架进行个性化定制,详情见:https://cli.vuejs.org/zh
ref 属性
- 被用来给元素或子组件注册引用信息(id 的替代者)
- 应用在 html 标签上获取的是真实 DOM 元素,应用在组件标签上是组件实例对象(vc)
- 使用方式:
- 打标识:
…..
或
- 获取:this.$refs.xxx
Student.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <template> <div class="school"> <h2>学校名称:{{ name }}</h2> <h2>学校地址:{{ address }}</h2> </div> </template>
<script> export default { name: "School", data() { return { name: "尚硅谷", address: "北京·昌平", }; }, }; </script>
<style> .school{ background-color: gray; } </style>
|
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <template> <div> <h1 v-text="msg" ref="title"></h1> <button ref="btn" @click="showDOM">点我输出上方的DOM元素</button> <School ref="sch" /> </div> </template>
<script> //引入School组件 import School from "./components/School";
export default { name: "App", components: { School }, data() { return { msg: "欢迎学习Vue!", }; }, methods: { showDOM() { console.log(this.$refs.title); //真实DOM元素 console.log(this.$refs.btn); //真实DOM元素 console.log(this.$refs.sch); //School组件的实例对象(vc) }, }, }; </script>
|
props 配置
- 功能:让组件接收外部传过来的数据
- 传递数据:
<Demo name="xxx"/>
- 接收数据:
- 第一种方式(只接收):
props:['name']
- 第二种方式(限制类型):
props:{name:String}
- 第三种方式(限制类型、限制必要性、指定默认值):
1 2 3 4 5 6 7
| props:{ name:{ type:String, required:true, default:'老王' } }
|
备注:props 是只读的,Vue 底层会监测你对 props 的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制 props 的内容到 data 中一份,然后去修改 data 中的数据。
Student.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <template> <div> <h1>{{ msg }}</h1> <h2>学生姓名: {{ name }}</h2> <h2>学生性别: {{ sex }}</h2> <h2>学生年龄: {{ MyAge + 1 }}</h2> <button @click="updateAge">点我修改年龄</button> </div> </template>
<script> export default { name: "Student", data() { return { msg: "我是一个尚硅谷的学生", MyAge: this.age, }; }, methods: { updateAge() { this.MyAge++; }, }, //简单声明接收 // props: ['name', 'sex', 'age'] //接收的同时对数据进行类型限制 // props: { // name: String, // sex: String, // age: Number // } //接收的同时对数据:进行类型限制+默认值的指定+必要性的限制 props: { name: { type: String, //name的类型是字符串 required: true, //name是必要的 }, sex: { type: String, default: "男", //默认值 }, age: { type: Number, default: 20, }, }, }; </script>
|
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <template> <div> <Student :age="18" name="尚硅谷" sex="男" /> </div> </template>
<script> import Student from "./components/Student.vue"; export default { name: "App", components: { Student, }, }; </script>
<style></style>
|
mixin 混入
- 功能:可以把多个组件共用的配置提取成一个混入对象
- 使用方式:
第一步定义混合:
1 2 3 4 5
| { data(){....}, methods:{....} .... }
|
第二步使用混入:
全局混入:Vue.mixin(xxx)
局部混入:mixins:['xxx']
School.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <template> <div> <h2 @click="showName">学校名称: {{ name }}</h2> <h2>学校地址: {{ address }}</h2> </div> </template>
<script> // import {mixin} from "../mixin" export default { name: "School", data() { return { name: "尚硅谷", address: "北京", }; }, // mixins: [mixin] }; </script>
|
Student.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <template> <div> <h2 @click="showName">学生姓名: {{ name }}</h2> <h2>学生性别: {{ sex }}</h2> </div> </template>
<script> // import {mixin} from "../mixin" export default { name: "Student", data() { return { name: "张三", sex: "男", }; }, // mixins: [mixin], mounted() { // console.log("你好啊!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); }, }; </script>
|
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <template> <div> <Student /> <hr /> <School /> </div> </template>
<script> import Student from "./components/Student.vue"; import School from "./components/School.vue";
export default { name: "App", components: { Student, School, }, }; </script>
<style></style>
|
mixin.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| export const mixin = { methods: { showName() { alert(this.name); }, }, mounted() { }, };
export const mixin2 = { data() { return { x: 999, y: 666, }; }, };
|
main.js
1 2 3 4 5 6 7 8 9 10 11 12
| import Vue from "vue"; import App from "./App";
import { mixin, mixin2 } from "./mixin"; Vue.config.productionTip = false; Vue.mixin(mixin); Vue.mixin(mixin2);
new Vue({ el: "#app", render: (h) => h(App), });
|
插件
- 功能:用于增强 Vue
- 本质:包含 install 方法的一个对象,install 的第一个参数是 Vue,第二个以后的参数是插件使用者传递的数据。
- 定义插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 对象.install = function (Vue, options) { Vue.filter(....)
Vue.directive(....)
Vue.mixin(....)
Vue.prototype.$myMethod = function () {...} Vue.prototype.$myProperty = xxxx }
|
- 使用插件:
Vue.use()
Student.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <template> <div> <h2>学生姓名: {{ name }}</h2> <h2>学生性别: {{ sex }}</h2> <input type="text" v-fbind:value="name" /> </div> </template>
<script> export default { name: "Student", data() { return { name: "张三", sex: "男", }; }, }; </script>
|
School.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <template> <div> <h2 @click="test">学校名称: {{ name | mySlice }}</h2> <h2>学校地址: {{ address }}</h2> </div> </template>
<script> export default { name: "School", data() { return { name: "尚硅谷atguigu", address: "北京", }; }, methods: { test() { this.hello(); }, }, }; </script>
|
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <template> <div> <Student /> <hr /> <School /> </div> </template>
<script> import Student from "./components/Student.vue"; import School from "./components/School.vue";
export default { name: "App", components: { Student, School, }, }; </script>
<style></style>
|
main.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import Vue from "vue"; import App from "./App.vue";
import plugins from "./plugins";
Vue.use(plugins, 1, 2, 3);
Vue.config.productionTip = false;
new Vue({ el: "#app", render: (h) => h(App), });
|
plugins.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| export default { install(Vue, x, y, z) { console.log(x, y, z); Vue.filter("mySlice", function (value) { return value.slice(0, 4); });
Vue.directive("fbind", { bind(element, binding) { element.value = binding.value; }, inserted(element, binding) { element.focus(); }, update(element, binding) { element.value = binding.value; }, });
Vue.mixin({ data() { return { x: 100, y: 200, }; }, });
Vue.prototype.hello = () => { alert("你好啊"); }; }, };
|
scoped 样式
- 作用:让样式在局部生效,防止冲突。
- 写法:
<style scoped>
School.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <template> <div class="demo"> <h2 class="title">学校名称: {{ name }}</h2> <h2>学校地址: {{ address }}</h2> </div> </template>
<script> export default { name: "School", data() { return { name: "尚硅谷atguigu", address: "北京", }; }, }; </script>
<style scoped> .demo { background-color: lightpink; } </style>
|
Student.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <template> <div class="demo"> <h2 class="title">学校名称: {{ name }}</h2> <h2 class="qwe">学校地址: {{ address }}</h2> </div> </template>
<script> export default { name: "School", data() { return { name: "尚硅谷atguigu", address: "北京", }; }, }; </script>
<style lang="less" scoped> .demo { background-color: lightpink; .qwe { font-size: 50px; } } </style>
|
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <template> <div> <h2 class="title">标题</h2> <School /> <hr /> <Student /> </div> </template>
<script> import Student from "./components/Student.vue"; import School from "./components/School.vue";
export default { name: "App", components: { Student, School, }, }; </script>
<style scoped> .title { color: red; } </style>
<style></style>
|
main.js
1 2 3 4 5 6 7 8 9
| import Vue from "vue"; import App from "./App.vue";
Vue.config.productionTip = false;
new Vue({ el: "#app", render: (h) => h(App), });
|
在组件中的 style 标签中定义了 scoped, 会在使用的 class 类上加上随机的 id, 在选择器中配合 id 来选择, 用来解决 css 选择器重名的问题
但是在 App.vue 组件中, 一般不用这个, 主要是 App 组件中写了样式, 就说明是很多组件都在使用的, 就不需要用 scoped 的
Module not found: Error: Can’t resolve ‘less-loader’ in ‘E:\Code\Vue\vue_test’