App.vue代码:
- <div>
- <h1 v-text="msg" ref="myTitle">h1>
- <button @click="showDom">点我输出上方的DOM元素button>
- <school ref="school" id="sch"/>
- div>
-
- <script>
- import School from "@/components/School";
- export default {
- name: "App",
- components: {School},
- data() {
- return { msg: "学习vue"}
- },
- methods: {
- showDom() {
- //通过ref绑定可以获得dom或者vue组件实例对象
- console.log(this)
- console.log(this.$refs)
- console.log(this.$refs.myTitle) //html标签,获得真实dom元素,
- console.log(this.$refs.school) //ref绑定组件,获得子组件的实例对象
- console.log(document.getElementById('sch')) //如果给绑定ID,通过document可以获取完整的dom对象
- }
- }
- }
- script>
样式:

通过控制台输出: 可以看到通过ref属性:可以非常方便的获得vue组件中子组件的实例对象,这个在后面组件之间通信非常重要;
一个组件被多次使用的时候,vue实例的数据不一致,实例化的时候传入数据
定义 Student.vue 组件
- <div class="student">
- <h1 v-text="msg">h1>
- <h2>学生姓名: {{name}}h2>
- <h2>学生性别: {{sex}}h2>
- <h2>学生年龄: {{age}}h2>
- div>
-
- <script>
- export default {
- // eslint-disable-next-line vue/multi-word-component-names
- name: "Student",
- data () {
- return {
- msg:"我在学习vue",
- }
- },
- props: ["name","age","sex"]
- }
- script>
初始化组件实例的时候
- <div>
- <student name="acong" age="19" sex="女"/>
- <hr/>
- <student name="azhu" age="20" sex="男"/>
- <hr/>
- div>
效果:

查看vue实例

数组方式接受的只能是字符串的类型:
age=”18+1“ 这种方式传递的也是字符串,不做运算。
如果通过`
- <div class="student">
- <h1 v-text="msg">h1>
- <h2>学生姓名: {{name}}h2>
- <h2>学生性别: {{sex}}h2>
- <h2>学生年龄: {{age}}h2>
- div>
-
- <script>
- export default {
- // eslint-disable-next-line vue/multi-word-component-names
- name: "Student",
- data () {
- console.log(this)
- return {
- msg:"我在学习vue",
- }
- },
- // props: ["name","age","sex"]
- props: {
- name: String,
- age: Number,
- sex: String,
- }
- }
- script>
标准的写法:
- //进行类型和默认值,是否必须的配置
- props: {
- name: {
- type:String,
- required: true,
- },
- age: {
- type: Number,
- default:18
- },
- sex: {
- type: String,
- required: true
- },
- }
外部接受的prop中参数是不建议更改的:
- methods: {
- changeAge() {
- // eslint-disable-next-line vue/no-mutating-props
- this.age = 30
- }
- }
增加点击事件修改: 刷新界面修改可以成功,但是控制台会报错,所以不建议修改props传入的值,可能会造成vue其他的一些位置问题。

如果业务需求就是要改: 点击年龄增加,需求: 重新定一个新的变量,接受传入的值,对新定义的值做修改,就是可以实现修改传入的值。
注意事项:
1、如果data中定义的属性名字和props中定义的一样,props中的会优先,覆盖data中定义的值,
2、props中定义的属性不能是key,ref等被vue使用的作为节点标识的属性,
Student.vue
- <div class="student">
- <h1 v-text="msg">h1>
- <h2>学生姓名: {{name}}h2>
- <h2>学生性别: {{sex}}h2>
- <h2>学生年龄: {{myage+1}}h2>
- <button @click="changeAge">尝试修改年龄button>
- div>
-
- <script>
- export default {
- // eslint-disable-next-line vue/multi-word-component-names
- name: "Student",
- data () {
- console.log(this)
- return {
- msg:"我在学习vue",
- myage: this.age
- }
- },
- // props: ["name","age","sex"]
- // props: {
- // name: String,
- // age: Number,
- // sex: String,
- // }
- //进行类型和默认值,是否必须的配置
- props: {
- name: {
- type:String,
- required: true,
- },
- age: {
- type: Number,
- default:18
- },
- sex: {
- type: String,
- required: true
- },
- },
- methods: {
- changeAge() {
- // eslint-disable-next-line vue/no-mutating-props
- this.myage++
- }
- }
- }
- script>
两个组件中的方法一样,可以优化提取为一个,分别引用;

可以定义个公共的js文件

在组件中引入:

刷新界面: 测试两个组件的绑定方法都正常的:
混合中可以写很多内容: 组件定义的中的都可以被混合
- export const common ={
- methods: {
- showName() {
- alert(this.name)
- }
- },
- mounted() {
- console.log("你好啊!")
- },
- }
-
- export const common2 = {
- data() {
- return {
- x:20,
- y:"yyy"
- }
- }
- }
导入混合

刷新界面可以看到: common2 中定义的 x,y属性与原来的data中的属性进行了合并:定义的钩子函数也被两个组件引用了。

如果混合定义了x,组件中data也有x, 有冲突情况下:以组件中定义的x为准,混合中定义的x被丢弃; 方法和data是这个标准,
但是如果混合中有生命周期钩子函数,钩子函数都会被执行。组件中定义的后执行,混合中定义的先执行。
在组件中不做任何引入混合,在main.js中引入
- import Vue from "vue";
- import App from "@/App";
-
- Vue.config.productionTip = false
-
- import {common,common2} from "@/common";
-
- Vue.mixin(common)
- Vue.mixin(common2)
-
- new Vue({
- render: h=> h(App),
- }).$mount("#app")
会让所有的组件都引入混合,刷新界面看到你好啊执行四次:为什么是四次呢?看vue

一共有四个组件实例,root上也绑定了,x,y属性

全局混合实际上有很多弊端,范围太大了,实际上最多使用的还是局部混合。
插件可以增强Vue,插件实际上就是对象。
定义插件

在main.js 中应用
- import Vue from "vue";
- import App from "@/App";
- //导入插件
- import plugin from "@/plugin";
-
- Vue.config.productionTip = false
-
- //应用插件
- Vue.use(plugin)
-
- new Vue({
- render: h=> h(App),
- }).$mount("#app")
在插件中传递参数
- export default {
- install(vue) {
- console.log("@@@install:",vue)
- }
- }
运行发现: 这个默认的参数vue是,vm的构造函数

在vm的构造函数中可以做很多事;
- export default {
- install(Vue) {
- console.log("@@@install:",Vue)
-
- //配置全局过滤器
- Vue.filter('myFilter',function (val) {
- return val.slice(0,4)
- })
-
- //定义全局指令
- Vue.directive('fbind', {
- bind(element, binding) {
- console.log('bind')
- element.value = binding.value
- },
-
- // eslint-disable-next-line no-unused-vars
- inserted(element, binding) {
- console.log('insert')
- element.focus()
- },
- update(element, binding) {
- console.log('update')
- element.value = binding.value
- }
- })
-
- //混入
- Vue.mixin({
- data() {
- return {
- x:20,
- y:"yyy"
- }
- }
- })
- //给Vue原型上添加一个方法,vm和vc都可以使用
- Vue.prototype.hello = ()=> {alert("你好啊! 哈哈")}
- }
- }
验证:
- # 组件中可以使用全局添加的过滤器
-
学校名字: {{name | myFilter }}
- # 组件中可以使用自定义的全局绑定
- "text" v-fbind:value="name">
- # 组件中使用hello方法
-
- test() {
- this.hello()
- }
混合检查

外部定义的插件,可以定义很多过滤器或者很多优秀的方法,可以直接使用。应用插件可以传递多个参数 Vue.use(plugin,x1,x2,x3) 都会被定义的 plugin.js 接收到
vue组件中的样式,最终会汇总到一起,class名字定义有可能冲突,谁后导入就是用谁的。
解决问题,style样式要加入scoped,就会不会冲突。
app组件中定义的style样式有可能不需要加scoped,app组件中定义的样式有可能是全局的样式。
lang指定默认是: css,可以指定为:less, less 编译需要报错。
安装:webpack 版本适配less-loader版本
需要安装 npm install less-loader
- <style scoped lang="less">
- .student{
- background-color: orange;
- .name-style {
- font-size: 40px;
- }
- }
- style>
效果:


github仓库:后面添加
子组件向父组件的传递数据
1、通过父亲组件定义一个方法,通过props传递给子组件,子组件调用传递的方法,可以将数据传递给父组件
2、父组件给子组件绑定一个自定义事件,在子组件通过 ths.$emit("自定义事件名",参数) , 触发父组件的事件回调绑定的方法,将子组件的数据传递给父组件
- # 1、绑定事件
- <Student v-on:getStudentName="getStudentName"/>
- # 简写 <Student v-on:getStudentName="getStudentName"/>
- # 2、定义事件方法
- methods: {
- getStudentName(name) {
- console.log("studentName",name)
- }
- }
- # 3、在子组件触发事件this.$emit('事件名')
- methods: {
- sendStudentName() {
- this.$emit("getStudentName",this.name)
- }
- }
另一种更加灵活的绑定事件的方式:可以给绑定事件的时候做一些其他事。
- # 1、将子组件通过ref属性命名
- <Student ref="student">Student>
- # 2、在父组件通过 mounted 钩子函数给绑定
- mounted() {
- setTimeout(()=> {
- this.$refs.student.$on('getStudentName',this.getStudentName)
- },3000)
- }
-
- # 3、在子组件中触发
- methods: {
- sendStudentName() {
- this.$emit("getStudentName",this.name)
- }
- }
如果是事件单次触发:v-on:getStudentName.once或者this.$refs.student.$once('getStudentName',this.getStudentName)
解绑自定义事件:
- //解绑一个自定义事件
- this.$off('getStudentName')
-
- //解绑一个多个自定义事件
- this.$off(['getStudentName','demoEvent'])
-
- //解绑所有自定义事件
- this.$off()
-
- //销毁组件实例,组件及其子组件绑定的所有自定义事件也会解绑
自定义事件注意点:
1、ref 属性绑定的时候,mounted中的 this.$refs.xxx.$on('getStudentName',回调函数)
回调需要写成箭头函数,或者直接写在methods,如果直接写 function 函数名,函数名中的this代表子组件。
3、绑定事件为原生事件的时候需要加.native