vue(9)—— 組件化開發 - webpack(3)

来源:https://www.cnblogs.com/yangva/archive/2019/03/28/10600648.html
-Advertisement-
Play Games

前面兩個終於把webpack相關配置解析完了。 現在終於進入vue的開發了 vue組件化開發預熱 前期準備 ...


前面兩個終於把webpack相關配置解析完了。現在終於進入vue的開發了

  

vue組件化開發預熱 

 

前期準備 

 

創建如下項目:

 

 

 app.js:

 footer.js:

main.js:

 

 

 

webpack.config.js:

 

同樣的生成兩個webpack配置文件,webpack.dev.config.js,webpack.prod.config.js,配置跟webpack.config.js一模一樣

 

package.json:

 

 

組件化開發終於到了重頭戲了

 

webpack引入vue

 

有幾種方法導入

 

1.第一種

這個前面文章 vue(8)—— 組件化開發 - webpack(2)   已經用過了,不多說,直接在html文件里導入

 

 

2.第二種

 

在入口函數里引入:

 

然後在webpack配置文件里添加一個resolve屬性:

 

註意,使用import導入的方法導入vue,導入的vue並不是完整的vue對象,只提供runtime-only的方式。

 

 

安裝loader 

 

其實vue真的做組件化開發的時候,文件尾碼名是.vue,並不是.js,所以webpack要識別尾碼為vue的組件的話,需要安裝loader

 

這裡要註意,需要安裝vue-loader和vue-template-compiler,前者是識別vue尾碼的文件的,後者是識別vue尾碼文件里的組件代碼的,並且兩者版本是配套,必須匹配,

我這安裝的是vue-loader14.1.1 和[email protected]版本,當然你也可以安裝更高版本的兩個匹配的

 

webpack配置文件里配置 

 

配置上webpack-dev-server,html-webpack-plugin的配置,這裡就略過了,還不太會的回過頭去看

 

 

 

package.json配置:

 

 在項目根目錄創建一個src文件,將剛纔的app.js,footer.js,main.js移到src文件夾內,並把app.js和footer.js文件重命名尾碼為.vue:

 

 

 

代碼規範整合

 

vue文件

 

上面的app.js文件修改成app.vue之後,開發規範已經變了,只有如下三個標簽作為邏輯代碼,之前我們寫的代碼已經不認識

 

<!--結構-->
<template>    

</template>

<!--邏輯-->
<script>
export default {
    
}
</script>

<!--樣式-->
<style>

</style>

 

 

 改成正確的代碼:

 

 

export default 拋出一個vue組件,組件的結構為template,數據為data拋出,因為vue組件的data必須是一個函數,所以這裡是函數

style樣式則和之前用的沒什麼區別

 

footer.vue文件:

 

入口文件 

 

入口函數不用改為js文件

 

 main.js:

 

 

 

其他配置

 

其他webpack.dev.config.js和package.json不用變

 

 

編譯運行 

npm  run dev: 

發現報錯了,這裡就解釋前面文章 vue(7)—— 組件化開發 — webpack(1)   的問題為什麼已經在全局安裝webpack,在開發環境下還要再裝一次了

 

npm i webpack -D 之後,再次編譯運行,註意安裝指定版本的webpack vue(7)—— 組件化開發 — webpack(1)

 

 運行是運行了,但是頁面打開報錯了,大概意思是說vue-loader和vue-template-compiler這兩個插件有問題

 

按照我多年解決bug的問題,我把當前的vue版本卸載了,然後裝了個低版本的,裝了個與vue-template-compiler的版本一樣的2.5.17版本的,完美解決上面這個問題

 

重新編譯:

 

 發現還是報錯,意思是這個App組件沒有正確註冊,檢查代碼,發現根本沒有問題,把App刪除之後,只留一個Footer看看:

 

 

 可以渲染,但是沒有任何數據,按理說是有的

 

這下怎麼辦呢?進入關鍵地步,仔細看

 

初學者容易入的坑

 

錯誤分析

 

其實按道理完全沒有問題,因為在之前非webpack下的vue開發中,在一個html文件就是這麼用的沒有錯,那為什麼這裡的footer可以,app不行呢?大眾思維,先把App刪除掉,看Footer呢?

 

這到底怎麼回事呢?標簽可以出,但是沒有數據渲染,卡在這了。

 

這裡如果你去發現研究的話花些時間也會發現問題的,但是為了不浪費你的時間,你不用自己去研究了。

 

其實上面的Footer和App組件都錯的,都不可以渲染成功的,其實footer的顯示,其實是被瀏覽器當html5的標簽處理了

 

 

 

如果你運氣好,定義的兩個組件的名字剛好和html5的標簽撞上,那絕對不會報錯,但是一樣不會把數據渲染出來

 

總之,按以上以前簡單的html頁面的vue配置,根本就是錯的,組件化開髮根本不認這種寫法。

為什麼,就因為多定義了一個局部,然後再從這個局部組件掛載到vue實例,所以關鍵就在於我標註出的位置

 

 

也就是說,在webpack里,或者說在vue-loader和vue-template-compiler插件里,不認這種寫法 

 

 既然都已經是組件化開發了,那麼你要定義局部組件,完全可以再新建一個vue文件,然後寫上組件代碼,最後在入口文件main.js里掛載就行了

 

不信的話,看我現在不通過Main組件掛載,直接在vue實例對象里掛載App和Footer看看:

 

 

其他配置不變

 

打開頁面,是不是顯示了,而且沒報錯

 

正確引入vue組件

 

 好,再把剛纔按個Main組件新建一個vue文件放進去

 

 

註意在vue文件里導入另一個vue文件的用法

 

main.js:

 

其他不變,打開網頁,正確返回

 

 

好了組件化開發規範終於解析完了,下麵才開始真正的開發測試

 

Vue組件化開發

 

掌握以上的規範之後,你就可以利用前面學到的vue開發,只要符合規範,隨心所欲的在裡面寫你的代碼了。如下,給一個簡單的例子:

 

package.json:

 

 webpack.dev.config.js

 

 

 

入口文件  main.js:

 

main.vue

 

 

app.vue

 

 

 footer.vue

 

index.html

 

 

 

編譯運行

 

打開網頁:

 

 

頁面數據是有了,但是這個有個問題,css樣式亂了,我明明每個vue組件都設置了css的,但是都亂了

 

問題解決

 

這個就不多說了,在每個vue組件的sytle標簽里都加上  scoped參數就行了

 

這個scoped就不多說了,它是由css屬性選擇器實現的,沒必要去深究了,反正你就記住設置scoped之後當前的css樣式只對當前的元素生效,對其他文件上的html元素不生效就行了

 

相關代碼:

{
  "name": "day3",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server --open --hot --inline --config ./webpack.dev.config.js",
    "build": "webpack --config ./webpack.prod.config.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {},
  "devDependencies": {
    "css-loader": "^2.1.1",
    "html-webpack-plugin": "^3.2.0",
    "style-loader": "^0.23.1",
    "vue": "^2.5.17",
    "vue-loader": "^14.1.1",
    "vue-template-compiler": "^2.5.17",
    "webpack": "^3.12.0",
    "webpack-dev-server": "^2.9.0"
  }
}
package.json
var path = require('path')
var htmlwebpackplugin = require('html-webpack-plugin')
module.exports = {
    entry: {
        name: './src/main.js'
    },
    output: {
        path: path.resolve('./dist'), // 項目輸出文件路徑
        filename: './bundle.js'
    },
    watch: true,
    module: {
        loaders: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            {
                test: /\.css$/,
                loader: 'style-loader!css-loader'
            }
        ]
    },
    plugins: [
        new htmlwebpackplugin({
            template: `./index.html`  //參照物
        })
    ]
}
webpack.dev.config.js
var path = require('path')
var htmlwebpackplugin = require('html-webpack-plugin')
module.exports = {
    entry: {
        name: './src/main.js'
    },
    output: {
        path: path.resolve('./dist'), // 項目輸出文件路徑
        filename: './bundle.js'
    },
    module: {
        loaders: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            {
                test: /\.css$/,
                loader: 'style-loader!css-loader'
            }
        ]
    },
    plugins: [
        new htmlwebpackplugin({
            template: `./index.html`  //參照物
        })
    ]
}
webpack.prod.config.js
import Vue from '../node_modules/vue/dist/vue.js'
import Main from './Main.vue'
new Vue({
    el: '#app',
    data() {
        return {
        }
    },
    components: {
        Main
    },
    render(createdElements) {
        return createdElements(Main)
    },
    // template: `<Main />`
});
main.js
<template>
    <div class='main'> {{msg}}
        <App @postHander='postHanders'/>
        <Footer :cont='sendmsg'/> 
    </div>
</template>
<script>
import App from './app.vue'  // 在vue組件里導入另一個vue組件,得在script標簽里導入
import Footer from './footer.vue'
export default {
    name:'Main',
    data(){
        return {
            msg:'Main入口',
            sendmsg:'',
        }
    },
    components:{
        App,
        Footer
    },
    methods:{
        postHanders(value){
            console.log(value,'父級接收到了數據,正準備傳給footer組件')
            this.sendmsg = value // app.vue組件傳來的數據,值為true
        }
    },    
}
</script>
<style scoped>
    .main{
        color: brown;
    }
</style>
Main.vue
<template>
  <div class='apps'> {{msg}}
    <div v-bind:class="isShow"></div>
    <input type="text" v-model="test"><span>{{test}}</span><br>
    <input type="text" ref='inputs' v-model='test2'><br>
    <button @click="btnHander" ref="btn">點我傳數據給父級</button>
  </div>
</template>
<script>
export default {
    name:'App',
    data(){
        return {
            msg:'app內容',
            isShow:true,
            test:'', 
            test2:''  }
    },
    methods:{
        btnHander(){
            this.$emit('postHander',this.isShow)
            this.$refs.btn.innerHTML = '數據已發送'  }
    },
    watch: {
        test2(value){
            if(value=='vue'){
                this.test2 = '我監聽到你填了vue'
                this.$refs.inputs.value = '' }
        }
    }
}
</script>
<style scoped>
    .apps{
        font-size: 12px;
        background: salmon;
        color: blue;
    }
</style>
app.vue
<template>
    <div class='footers'>{{msg}}
        <p v-text="test1"></p>  
        <p v-html="test2"></p>       
        <button @click="getHander(cont)">點我展示從父級獲取到的數據</button>
        <ul v-show="isShow">
            <li v-for = 'item in datas' :key = 'item.id'>  {{ item.name }} -- {{item.age}} </li>
        </ul>
    </div>
</template>
<script>
export default {
    name:'Footer',
    data(){
        return {
            msg:'footer內容',
            test1:'測試1',
            test2:'<h4>測試2</h4>',
            datas:[
                {'id':1,'name':'jack','age':30},
                {'id':2,'name':'lucy','age':26},
                {'id':3,'name':'lily','age':28},],
            isShow:false }},
    methods:{
        getHander(cont){
            this.isShow = cont }
    },
    props:['cont'], // 父級傳來的數據,值為true
    mounted(){      // 生命周期函數
        console.log() }
}
</script>
<style scoped>
    .footers{
        color: purple;
        font-size: 15px;
        font-weight: bold;  }
</style>
footer.vue
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    
    <div id="app">    
        <p>test</p>
    </div>    
</body>
</html>
index.html

 

 

Vuex

 

什麼是vuex

 官網:傳送門,官方解釋:

Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。Vuex 也集成到 Vue 的官方調試工具 devtools extension,提供了諸如零配置的 time-travel 調試、狀態快照導入導出等高級調試功能

 

vuex的作用

 

vuex是為了保存組件之間的共用數據而誕生的。如果組件之間有共用的數據,直接掛載在vuex上即可,而沒必要子級組件通過向父級組件傳遞之後,父級組件再將數據轉給目標子級組件,這個很麻煩,這個之前我個人試過,利用子級傳遞一個簡單的數據還好,傳遞一個數組感覺有點繞,很不方便。

所以,vuex是一個全局的共用數據存儲區域,相當於一個數據倉庫

Vuex 可以幫助我們管理共用狀態,並附帶了更多的概念和框架。這需要對短期和長期效益進行權衡。

 

如果您不打算開發大型單頁應用,使用 Vuex 可能是繁瑣冗餘的。確實是如此——如果您的應用夠簡單,您最好不要使用 Vuex。一個簡單的 store 模式就足夠您所需了。但是,如果您需要構建一個中大型單頁應用,您很可能會考慮如何更好地在組件外部管理狀態,Vuex 將會成為自然而然的選擇

 

簡單使用vuex

 

安裝  npm i vuex

 

配置vuex

 

還是上面的例子,做了稍微修改:

 

main.js:

 

1.導入vuex並掛載到Vue實例對象上,這個用法跟掛載vue-router類似,不多說

2.定義一個vuex實例對象,其有三個屬性,state,mutations,getters

  • state類似vue實例中的data屬性,裡面的值就是數據倉庫,所有的vue組件都可以共用
  • mutations類似vue實例中的methods屬性,裡面的方法類似computed計算屬性,裡面的方法主要是對數據的修改,方法名自定義,vuex官方不建議直接在數據被引用的組件里直接賦值修改
  • getters類似vueshilling中的watch或者filters屬性,方法名可以自定義,但是參數固定必須是state屬性

 

3.同樣的類似路由對象一樣,直接在vue實例上掛載定義的vuex對象

 

app.vue:

 

其他不變,直接用$store.state.XX(你定義的公用數據變數名)獲取vuex實例的數據

定義了兩個方法,與vuex的mutations屬性中的方法對應,一個加法,一個減法,傳入的第一個值就是mutations里的方法名,第二個值隨意,但最多只能傳入兩個值,當然你可以傳入一個對象,對象里放很多屬性即可

註意:組件中的方法要操作store公用倉庫的數據,必須使用this.$store.commit或者this.$store.disptch提交,不能是$store.commit,在方法中必須加this,註意區分

 

 

 

footer.vue:

只有標註區域是添加的,其他沒變,就是通過了vuex實例的getters屬性,獲取了最新的數據,有點類似vue的watch或者filters屬性,實時獲取最新的值

 

這裡可能有疑惑,為什麼用getters獲取呢?直接像上面的app.vue中的用$store.state.count獲取不行嗎?可以是可以,假如說你希望給這個數據添加一些其他的樣式,加個單位或者什麼呢?這樣就可以直接用getters,不需要你再自己定義一個方法了,大家都公用的

 

 

其他沒做任何改動,npm run dev運行,打開瀏覽器:這個不太好展示效果,效果就是我點增加或減少按鈕,兩處的數據都跟著改變

感覺還是挺簡單的對吧

 

 

相關代碼:

{
  "name": "day3",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server --open --hot --inline --config ./webpack.dev.config.js",
    "build": "webpack --config ./webpack.prod.config.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "vuex": "^3.1.0"
  },
  "devDependencies": {
    "css-loader": "^2.1.1",
    "html-webpack-plugin": "^3.2.0",
    "style-loader": "^0.23.1",
    "vue": "^2.5.17",
    "vue-loader": "^14.1.1",
    "vue-template-compiler": "^2.5.17",
    "webpack": "^3.12.0",
    "webpack-dev-server": "^2.9.0"
  }
}
package.json
import Vue from '../node_modules/vue/dist/vue.js'
import Main from './Main.vue'
import Vuex from 'vuex'
Vue.use(Vuex)

var store = new Vuex.Store({

    state: {  //類似於data屬性
        count: 0
    },
    mutations: { // 類似於methods屬性
        increment(state) { // 加法
            state.count++
        },
        subtract(state, value) { // 減法
            state.count -= value
        }
    },
    getters: { // 類似於filters過濾器屬性
        currentCount:function(state) {
            return '當前最新的count值是:' + state.count
        }
    }
})
new Vue({
    el: '#app',
    data() {
        return {}
    },
    components: {Main},
    store,
    template: `<Main />`
});
main.js
<template>
    <div class='main'> {{msg}}
        <App @postHander='postHanders'/>
        <Footer :cont='sendmsg'/> 
    </div>
</template>
<script>
import App from './app.vue'  // 在vue組件里導入另一個vue組件,得在script標簽里導入
import Footer from './footer.vue'
export default {
    name:'Main',
    data(){
        return {
            msg:'Main入口',
            sendmsg:'',
        }
    },
    components:{
        App,
        Footer
    },
    methods:{
        postHanders(value){
            console.log(value,'父級接收到了數據,正準備傳給footer組件')
            this.sendmsg = value // app.vue組件傳來的數據,值為true
        }
    },    
}
</script>
<style scoped>
    .main{
        color: brown;
    }
</style>
main.vue
<template>
  <div class='apps'> {{msg}}
    
    <input type='text' v-model="$store.state.count">

    <input type='button' value="增加" @click="add">
    <input type="button" value="減少" @click="sub">

    <div v-bind:class="isShow"></div>
    <input type="text" v-model="test"><span>{{test}}</span><br>
    <input type="text" ref='inputs' v-model='test2'><br>
    <button @click="btnHander" ref="btn">點我傳數據給父級</button>
  </div>
</template>
<script>
export default {
    name:'App',
    data(){
        return {
            msg:'app內容',
            isShow:true,
            test:'', 
            test2:''  }
    },
    methods:{
        add(){
            this.$store.commit('increment')
        },
        sub(){
            this.$store.commit('subtract',5)
        },
        btnHander(){
            this.$emit('postHander',this.isShow)
            this.$refs.btn.innerHTML = '數據已發送'  }
    },
    watch: {
        test2(value){
            if(value=='vue'){
                this.test2 = '我監聽到你填了vue'
                this.$refs.inputs.value = '' }
        }
    }
}
</script>
<style scoped>
    .apps{
        font-size: 12px;
        background: salmon;
        color: blue;
    }
</style>
app.vue
<template>
    <div class='footers'>{{msg}}
        <p v-text="test1"></p>  
        <p v-html="test2"></p>       
        <button @click="getHander(cont)">點我展示從父級獲取到的數據</button>
        <ul v-show="isShow">
            <li v-for = 'item in datas' :key = 'item.id'>  {{ item.name }} -- {{item.age}} </li>
        </ul>
        <h3>{{$store.getters.currentCount}}</h3>
    </div>
</template>
<script>
export default {
    name:'Footer',
    data(){
        return {
            msg:'footer內容',
            test1:'測試1',
            test2:'<h4>測試2</h4>',
            datas:[
                {'id':1,'name':'jack','age':30},
                {'id':2,'name':'lucy','age':26},
                {'id':3,'name':'lily','age':28},],
            isShow:false }},
    methods:{
        getHander(cont){
            this.isShow = cont }
    },
    props:['cont'], // 父級傳來的數據,值為true
    mounted(){      // 生命周期函數
        console.log() }
}
</script>
<style scoped>
    .footers{
        color: purple;
        font-size: 15px;
        font-weight: bold;  }
</style>
footer.vue
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    
    <div id="app">    
        <p>test</p>
    </div>    
</body>
</html>
index.html

 

 

actions和同步非同步問題

 

在vuex的官網中,我們可以看到,在mutations中的方法都是同步更新數據的,在actions中的操作時非同步更新數據的。如果我們的數據需要非同步操作的話,就不能實現實時更新數據了,這樣就很容易有後患,比如,組件A將store里的數據用非同步操作改了,然後另一個組件B獲取數據時因為非同步操作獲取數據並不及時,所以可能導致獲取的數據並不是最新的,所以會有這種隱患存在。

 

看個例子:

為上面的例子加一個非同步增加的方法:

main.js,用setTimeout模擬非同步操作

 

 

 

app.vue:

 

編譯運行

 

我先點同步增加:

 

 

這裡查看數據的工具,使用的是谷歌瀏覽器的vue-devtools插件,這個需要自己手動安裝,然後就可以在調試工具視窗中看到vue的相關數據了,這個方便以後的開發,具體就不掩飾怎麼安裝了,自行網上查詢解決

 

再點非同步增加:

 

發現這個問題了吧?雖然在當前頁面會顯示正常的,但是實際的倉庫中的數據其實還沒有變化的。

再點減少按鈕模擬其他的組件要操作這個數據,一步錯,步步錯,後面的操作就永遠不是正確的數據了:

 

  

問題解決

 

前面已經說了,mutations里的方法是同步的,然後模擬非同步操作時,因為mutations獲取操作的數據是同步並不會拿到最新的數據,所以在這種場景下,不用使用直接mutations里的方法來操作數據,需要借用actions來操作:

 

在main.js添加actions:

 

 app.vue中,註意非同步操作分發用的不是commit而是dispatch了

 

 

編譯運行

果然同步了,目前這個才是我們希望的效果:

 

actions函數和傳參

在actions的方法中,方法名就是mutations中的方法名,這樣以遍actions分發到mutations中的同名方法中 ,格式  XX({commit}){}

如果要傳參的話,格式   xx({commit},value){}  ,其中value就是傳入的參數,比如:

 

vuex中的actions的方法本質上還是調用的mutations里的方法,只是做了非同步處理分發,在方法本身是沒有做改動的。然後再組件部分不再使用commit提交數據,而是用dispatch方法提交,非同步操作。

個人感覺這個actions非常類似Python中的裝飾器

  

相關代碼:

{
  "name": "day3",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server --open --hot --inline --config ./webpack.dev.config.js",
    "build": "webpack --config ./webpack.prod.config.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "vuex": "^3.1.0"
  },
  "devDependencies": {
    "css-loader": "^2.1.1",
    "html-webpack-plugin": "^3.2.0",
    "style-loader": "^0.23.1",
    "vue": "^2.5.17",
    "vue-loader": "^14.1.1",
    "vue-template-compiler": "^2.5.17",
    "webpack": "^3.12.0",
    "webpack-dev-server": "^2.9.0"
  }
}
package.json
import Vue from '../node_modules/vue/dist/vue.js'
import Main from './Main.vue'
import Vuex from 'vuex'
Vue.use(Vuex)
var store = new Vuex.Store({
    state: {  //類似於data屬性
        count: 0
    },
    mutations: { // 類似於methods屬性
        increment(state) { // 加法
            state.count++
        },
        asyincrement(state) { // 非同步加法,兩秒之後再加            
                state.count++            
        },
        subtract(state, value) { // 減法
            state.count -= value
        }
    },
    getters: { // 類似於filters過濾器屬性
        currentCount:function(state) {
            return '當前最新的count值是:' + state.count
        }
    },
    actions:{  // 非同步操作
        increment({commit}){  //同步加法
            commit('increment')
        },
        asyincrement({commit}){ // 非同步加法,兩秒之後再加
            setTimeout(()=>{
                commit('asyincrement')
            },2000)            
        },
    }
})
new Vue({
    el: '#app',
    data() {
        return {}
    },
    components: {Main},
    store,
    template: `<Main />`
});
main.js
<template>
    <div class='main'> {{msg}}
        <App @postHander='postHanders'/>
        <Footer :cont='sendmsg'/> 
    </div>
</template>
<script>
import App from './app.vue'  // 在vue組件里導入另一個vue組件,得在script標簽里導入
import Footer from './footer.vue'
export default {
    name:'Main',
    data(){
        return {
            msg:'Main入口',
            sendmsg:'',
        }
    },
    components:{
        App,
        Footer
    },
    methods:{
        postHanders(value){
            console.log(value,'父級接收到了數據,正準備傳給footer組件')
            this.sendmsg = value // app.vue組件傳來的數據,值為true
        }
    },    
}
</script>
<style scoped>
    .main{
        color: brown;
    }
</style>
main.vue
<template>
  <div class='apps'> {{msg}}    
    <input type='text' v-model="$store.state.count">
    <input type='button' value="同步增加" @click="add">
    <input type='button' value="非同步增加" @click="asyadd">
    <input type="button" value="減少" @click="sub">
    <div v-bind:class="isShow"></div>
    <input type="text" v-model="test"><span>{{test}}</span><br>
    <input type="text" ref='inputs' v-model='test2'><br>
    <button @click="btnHander" ref="btn">點我傳數據給父級</button>
  </div>
</template>
<script>
export default {
    name:'App',
    data(){
        return {
            msg:'app內容',
            isShow:true,
            test:'', 
            test2:''  }
    },
    methods:{
        add(){     //同步增加
            //this.$store.commit('increment')
            this.$store.dispatch('increment')
        },
        asyadd(){  // 非同步增加
            //this.$store.commit('asyincrement')
            this.$store.dispatch('asyincrement')
        },
        sub(){
            //this.$store.commit('subtract',5)
            this.$store.dispatch('subtract',5)
        },
        btnHander(){
            this.$emit('postHander',this.isShow)
            this.$refs.btn.innerHTML = '數據已發送'  }
    },
    watch: {
        test2(value){
            if(value=='vue'){
                this.test2 = '我監聽到你填了vue'
                this.$refs.inputs.value = '' }
        }
    }
}
</script>
<style scoped>
    .apps{
        font-size: 12px;
        background: salmon;
        color: blue;
    }
</style>
app.vue
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • SQL、LINQ、Lambda 三種用法顏色註釋: SQL LinqToSql Lambda QA1、 查詢Student表中的所有記錄的Sname、Ssex和Class列。select sname,ssex,class from studentLinq: from s in Students se ...
  • 錯誤如圖: 解決方案分享如下: 第一步:卸載下圖紅框圈住的玩藝。 第二步:把SP4補丁文件解壓,找到下圖紅框圈住的玩藝: 第三步:重新運行SP4補丁安裝文件,安裝正常。 ...
  • Mysql (針對Mysql5.7版本,其他版本可能略有不同) 錯誤:1045 解決方法: 以管理員身份運行cmd(win8系統:win+x 鍵 ,再按 A鍵 ),進入Mysql安裝目錄下的bin目錄下(如下圖所示,根據自己的情況修改目錄)@:下麵還要再打開cmd視窗,為方便區別,此視窗記為‘’ c ...
  • HBase為篩選數據提供了一組過濾器,通過這個過濾器可以在HBase中的數據的多個維度(行,列,數據版本)上進行對數據的篩選操作,也就是說過濾器最終能夠篩選的數據能夠細化到具體的一個存儲單元格上(由行鍵,列明,時間戳定位)。通常來說,通過行鍵,值來篩選數據的應用場景較多。 1.創建測試表studne ...
  • 正文 pt online schema change ALTER tables without locking them. pt online schema change alters a table’s structure without blocking reads or writes. Spe ...
  • MySQL的“utf8”實際上不是真正的UTF-8。 MySQL中的“utf8”只支持每個字元最多三個位元組,而真正的UTF-8是每個字元最多四個位元組。 MySQL一直沒有修複這個bug,但是他們在2010年發佈了一個叫作“utf8mb4”的字元集,繞過了這個問題。 當然,他們並沒有對新的字元集廣而告 ...
  • 購物車是電商APP的一個關鍵功能點,一般購物車包含 3~4 個頁面,分別是: 1.購物車的商品列表頁 2.商品下單頁 3.訂單付款頁面 4.訂單付款成功頁面 由於現有購物車邏輯相對混亂,這裡重新整理一下商品下單頁的業務流程設計 1.生成訂單 這裡在業務層面把訂單的生命周期劃分為4個階段,分別是: 訂 ...
  • 程式26:給一個不多於5位的正整數。要求:一、求它是幾位數,二、逆序列印出各位數字。 var test=456; var arr=[]; arr[0]=test%10; arr[1]=parseInt(test%100/10); arr[2]=parseInt(test%1000/100); arr ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...